Linux内核获取CPU占用率方法
Linux内核获取CPU占用率的接口
在 Linux 内核中,获取 CPU 占用率通常涉及读取系统统计信息。以下是主要的内核接口和方法:
1. /proc/stat
接口(用户空间)
路径:/proc/stat
内容:提供系统启动以来的 CPU 时间累积值(单位:USER_HZ,通常 1/100 秒)。
格式:
1
2cpu user nice system idle iowait irq softirq steal guest guest_nice
cpu0 ... # 每个 CPU 核心的单独统计
计算占用率:
1
2
3total_time = user + nice + system + idle + iowait + irq + softirq + steal;
idle_time = idle + iowait; // 通常将 iowait 视为空闲
usage = (total_time - idle_time) * 100 / total_time;
2. 内核数据结构(驱动/模块开发)
在内核模块中,可直接访问以下数据结构:
- 全局统计:
kernel_cpustat
(每 CPU 变量)1
2
3
4
5
6
7
struct kernel_cpustat *stat = kcpustat_cpu(cpu); // 获取指定 CPU 的统计
u64 user = stat->cpustat[CPUTIME_USER];
u64 system = stat->cpustat[CPUTIME_SYSTEM];
u64 idle = stat->cpustat[CPUTIME_IDLE];
// 其他状态:CPUTIME_NICE, CPUTIME_IOWAIT 等 - 运行队列统计:
struct rq
(调度器相关)1
2
3
struct rq *rq = cpu_rq(cpu);
u64 nr_running = rq->nr_running; // 当前运行队列中的任务数
3. 计算瞬时占用率
需两次采样并计算差值:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// 第一次采样
get_cpu_stats(&prev_total, &prev_idle);
// 等待一段时间(如 1 秒)
msleep(1000);
// 第二次采样
get_cpu_stats(&curr_total, &curr_idle);
// 计算差值
total_delta = curr_total - prev_total;
idle_delta = curr_idle - prev_idle;
// 计算占用率
usage = (total_delta - idle_delta) * 100 / total_delta;
4. Perf 事件(性能监控)
使用 perf_event_open
系统调用监控 CPU 周期:
1
2
3
4
5
6
7
8
struct perf_event_attr attr = {
.type = PERF_TYPE_HARDWARE,
.config = PERF_COUNT_HW_CPU_CYCLES,
};
int fd = perf_event_open(&attr, -1, cpu, -1, 0);
read(fd, &count, sizeof(count)); // 读取 CPU 周期计数
5. 调度器统计
- 调度器钩子:注册
scheduler_tick
钩子统计任务执行时间。 - **
/proc/<pid>/stat
**:进程级 CPU 时间(utime
、stime
)。
注意事项
- 时间单位:
/proc/stat
使用 USER_HZ(通常 100 Hz)。- 内核数据结构使用 NSEC_PER_SEC(纳秒)。
- 多核处理:
需为每个 CPU 核心单独统计。 - 抢占安全:
内核模块中访问每 CPU 数据时需禁用抢占:1
2
3get_cpu(); // 禁用抢占
// 访问每 CPU 数据
put_cpu(); // 启用抢占
示例代码(内核模块)
1 |
|
用户空间工具
- **
top
/htop
**:实时显示 CPU 占用。 - **
mpstat
**:多核详细统计(sysstat
包)。 - **
vmstat
**:系统整体性能统计。
通过以上接口,可以在内核或用户空间灵活获取 CPU 占用率数据。
Linux内核获取CPU占用率示例
以下是一个完整的 Linux 内核模块示例,演示如何在内核空间获取并计算 CPU 占用率。该模块每秒计算一次系统整体 CPU 占用率,并将结果输出到内核日志中:
1 |
|
关键说明:
工作原理:
- 使用内核定时器每秒触发一次计算
- 遍历所有在线 CPU 核心
- 读取
kernel_cpustat
数据结构中的时间计数器 - 计算与上一次采样的差值
- 公式:
(总时间 - 空闲时间) / 总时间 * 100
时间统计项:
CPUTIME_USER
:用户空间程序时间CPUTIME_NICE
:低优先级任务时间CPUTIME_SYSTEM
:内核空间时间CPUTIME_IDLE
:空闲时间CPUTIME_IOWAIT
:I/O 等待时间CPUTIME_IRQ
:硬件中断时间CPUTIME_SOFTIRQ
:软件中断时间CPUTIME_STEAL
:虚拟化环境中的被偷取时间
编译与使用:
1
2
3
4
5
6
7
8
9
10
11# 编译
make -C /lib/modules/$(uname -r)/build M=$(pwd) modules
# 加载模块
sudo insmod cpu_usage.ko
# 查看输出
dmesg | tail -f
# 卸载模块
sudo rmmod cpu_usage输出示例:
1
2
3[ 1234.567890] CPU Usage: 15%
[ 1235.567901] CPU Usage: 22%
[ 1236.567912] CPU Usage: 8%
注意事项:
时间单位:
- 所有时间值单位为纳秒 (ns)
- 使用
do_div()
处理 64 位除法
多核处理:
for_each_online_cpu()
遍历所有活跃 CPU 核心- 最终结果是所有核心的平均占用率
首次运行:
- 第一次运行时不输出,因为没有前一次数据可比较
- 从第二次定时器触发开始输出结果
性能影响:
- 计算本身非常轻量级
- 每秒触发一次,对系统影响极小
- 在生产环境中使用时,可考虑增加采样间隔
此示例展示了内核空间获取 CPU 占用率的基本方法。在实际应用中,可能需要添加:
- 每个核心的独立统计
- 用户空间接口(如通过
/proc
或sysfs
) - 历史数据记录功能
- 可配置的采样间隔
对于用户空间程序,更简单的方法是直接解析 /proc/stat
文件,实现类似 top
命令的功能。