Windows XP Windows 7 Windows 2003 Windows Vista Windows 綜合教學 Linux 系統教學
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟體教學
您现在的位置: Windows教程網 >> Windows教程 >  >> Linux 系統教學 >> Linux 教學

Linux C 語言獲取 CPU 使用率:解析 /proc/stat 實作

編輯:Linux 教學

原理

Linux 核心在 /proc/stat 暴露 CPU 時間統計 (單位:jiffies,通常 1/100 秒或 1/1000 秒)。讀取兩次樣本相減,即可計算區間內 CPU 忙碌比例。

/proc/stat 格式

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 為各核心。欄位含義:

  1. user:用戶態時間 (nice=0)
  2. nice:低優先級用戶態時間
  3. system:核心態時間
  4. idle:閒置時間
  5. iowait:等待 I/O (2.5.41+)
  6. irq:硬體中斷
  7. softirq:軟中斷
  8. steal:虛擬機被 Hypervisor 偷走
  9. guest:客體虛擬機
  10. 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

完整 C 實作 (支援多核)

#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

進階:使用 libstatgrab / sysinfo

若需跨平台 (BSD、Solaris) 或更豐富指標 (記憶體、磁碟、網路),建議使用成熟庫:

  • libstatgrab:sg_get_cpu_stats()、sg_get_mem_stats() 等。
  • sysstat (sar, iostat, mpstat):系統級監控工具,可作為守護程式收集歷史資料。
  • Prometheus Node Exporter:現代雲原生監控標準,暴露 /metrics 供抓取。

常見坑點

  • /proc/stat 累計值會溢位 (32 位系統約 497 天),64 位系統極難溢位,但長期運行仍建議用 64 位無符號整數。
  • 容器環境下 /proc/stat 反映宿主機全域 CPU,若需容器限制 (cgroup cpuacct),需讀取 /sys/fs/cgroup/cpuacct/cpuacct.stat。
  • 採樣間隔太短 (如 < 100ms) 受 jiffies 粒度影響誤差大;建議 1~5 秒。
Copyright © Windows教程網 All Rights Reserved