Linux 核心在 /proc/stat 暴露 CPU 時間統計 (單位:jiffies,通常 1/100 秒或 1/1000 秒)。讀取兩次樣本相減,即可計算區間內 CPU 忙碌比例。
cpu 12345 678 9012 345678 90 0 12 0 0 0
cpu0 1234 56 789 34567 9 0 1 0 0 0
cpu1 1234 56 789 34567 9 0 1 0 0 0
...
intr 123456789 ...
ctxt 987654
btime 1600000000
processes 12345
procs_running 2
procs_blocked 1
第一行 cpu 為所有核心總和,後續 cpuN 為各核心。欄位含義:
user:用戶態時間 (nice=0)nice:低優先級用戶態時間system:核心態時間idle:閒置時間iowait:等待 I/O (2.5.41+)irq:硬體中斷softirq:軟中斷steal:虛擬機被 Hypervisor 偷走guest:客體虛擬機guest_nice:低優先級客體Total_diff = (user2+nice2+sys2+idle2+iowait2+irq2+softirq2+steal2) - (user1+nice1+sys1+idle1+iowait1+irq1+softirq1+steal1)
Idle_diff = idle2 - idle1
Busy_diff = Total_diff - Idle_diff
CPU% = Busy_diff * 100.0 / Total_diff
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h>
typedef struct {
unsigned long long user, nice, sys, idle, iowait, irq, softirq, steal;
} cpu_stat_t;
int read_cpu_stat(cpu_stat_t *stats, int max_cpus) {
FILE *fp = fopen("/proc/stat", "r");
if (!fp) return -1;
char line[1024];
int cpu_idx = -1;
while (fgets(line, sizeof(line), fp) && cpu_idx < max_cpus) {
if (strncmp(line, "cpu", 3) != 0) break;
cpu_stat_t *s = &stats[cpu_idx + 1];
int n = sscanf(line + 3, "%llu %llu %llu %llu %llu %llu %llu %llu",
&s->user, &s->nice, &s->sys, &s->idle,
&s->iowait, &s->irq, &s->softirq, &s->steal);
if (n < 4) break; // 至少前4欄
if (n < 8) { s->iowait = s->irq = s->softirq = s->steal = 0; }
cpu_idx++;
}
fclose(fp);
return cpu_idx + 1; // 實際讀取核心數 (含總計行)
}
double calc_cpu_usage(const cpu_stat_t *prev, const cpu_stat_t *cur) {
unsigned long long prev_total = prev->user + prev->nice + prev->sys + prev->idle + prev->iowait + prev->irq + prev->softirq + prev->steal;
unsigned long long cur_total = cur->user + cur->nice + cur->sys + cur->idle + cur->iowait + cur->irq + cur->softirq + cur->steal;
unsigned long long total_diff = cur_total - prev_total;
unsigned long long idle_diff = cur->idle - prev->idle;
if (total_diff == 0) return 0.0;
return (double)(total_diff - idle_diff) * 100.0 / total_diff;
}
int main() {
int ncpus = sysconf(_SC_NPROCESSORS_ONLN);
cpu_stat_t *prev = calloc(ncpus + 1, sizeof(cpu_stat_t));
cpu_stat_t *cur = calloc(ncpus + 1, sizeof(cpu_stat_t));
read_cpu_stat(prev, ncpus);
while (1) {
sleep(1);
read_cpu_stat(cur, ncpus);
printf("=== CPU Usage ===\n");
for (int i = 0; i <= ncpus; i++) {
double usage = calc_cpu_usage(&prev[i], &cur[i]);
printf("cpu%-2d: %5.2f%%\n", i, usage);
}
// 交換指標
cpu_stat_t *tmp = prev; prev = cur; cur = tmp;
}
return 0;
}
gcc cpu_usage.c -o cpu_usage
./cpu_usage
若需跨平台 (BSD、Solaris) 或更豐富指標 (記憶體、磁碟、網路),建議使用成熟庫:
sg_get_cpu_stats()、sg_get_mem_stats() 等。/metrics 供抓取。/proc/stat 累計值會溢位 (32 位系統約 497 天),64 位系統極難溢位,但長期運行仍建議用 64 位無符號整數。/proc/stat 反映宿主機全域 CPU,若需容器限制 (cgroup cpuacct),需讀取 /sys/fs/cgroup/cpuacct/cpuacct.stat。