在C中单独获取所有可用CPU的CPU利用率

问题描述 投票:0回答:2

当我在终端上使用cat /proc/stat命令时,我得到以下输出:

cpu  9268738 47123 3940054 3851366876 911347 0 164981 0 0 0 
cpu0 558436 2170 208965 240825151 54221 0 30439 0 0 0 
cpu1 699380 1976 382320 240476662 50707 0 7260 0 0 0 
cpu2 547485 2685 204733 240867376 56441 0 4410 0 0 0 
cpu3 541016 3581 202538 240872692 57657 0 3051 0 0 0 
cpu4 552305 2716 286470 240322626 70098 0 60308 0 0 0 
cpu5 490248 3598 211000 240891224 59970 0 2596 0 0 0 
cpu6 510708 1987 215605 240879645 57692 0 2546 0 0 0 
cpu7 528486 3053 220346 240866189 54916 0 2273 0 0 0 
cpu8 540615 2563 216076 240857715 53633 0 2161 0 0 0 
cpu9 862775 1794 413426 240049704 49504 0 1755 0 0 0 
cpu10 576740 5166 230907 240805093 51594 0 2084 0 0 0 
cpu11 611709 2192 268375 240408228 62183 0 37502 0 0 0 
cpu12 589948 3351 227945 240734505 59752 0 1992 0 0 0 
cpu13 552315 3205 217448 240834143 58786 0 2137 0 0 0 
cpu14 554752 3387 218348 240835453 56078 0 2222 0 0 0 
cpu15 551815 3693 215547 240840464 58106 0 2240 0 0 0 
...

从上面提到的输出我可以注意到我的计算机有16个不同的CPU。我正在尝试编写一个C程序来获取所有可用CPU核心的CPU利用率。但问题是我有以下代码,它只能让我获取整体CPU利用率,但只读取/proc/stat文件的第一行:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(void)
{
    long double cpu0_a[4], cpu0_b[4], loadavg;
    FILE *fp;
    char dump[50];

    while(1)
    {
        fp = fopen("/proc/stat","r");
        fscanf(fp,"%*s %Lf %Lf %Lf %Lf",&cpu0_a[0],&cpu0_a[1],&cpu0_a[2],&cpu0_a[3]);
        fclose(fp);
        sleep(1);

        fp = fopen("/proc/stat","r");
        fscanf(fp,"%*s %Lf %Lf %Lf %Lf",&cpu0_b[0],&cpu0_b[1],&cpu0_b[2],&cpu0_b[3]);
        fclose(fp);

        loadavg = ((cpu0_b[0]+cpu0_b[1]+cpu0_b[2]) - (cpu0_a[0]+cpu0_a[1]+cpu0_a[2])) / ((cpu0_b[0]+cpu0_b[1]+cpu0_b[2]+cpu0_b[3]) - (cpu0_a[0]+cpu0_a[1]+cpu0_a[2]+cpu0_a[3]));
        printf("The current CPU utilization is : %Lf\n",loadavg);
    }

    return(0);
}

如何读取/proc/stat文件以单独打印所有可用CPU的当前CPU利用率而不是整体CPU利用率?

附:我是C编程的新手,来自C#背景,所以我可能会遗漏一些非常基本的东西。谢谢你的帮助。

c resources cpu cpu-usage procstat
2个回答
1
投票

以下代码完成了工作。虽然在适当的考虑下,代码具有系统上可用的硬编码CPU数量,因此必须根据您运行的系统手动更改。尽管EOF可以与regex结合使用来检查来自/ proc / stat文件的cpu利用率,但正则表达式有一个计算开销(我使用的系统差不多30ms)。该代码更倾向于在实时设备中使用,因此,由于上述原因,避免使用正则表达式。

代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define NUM_CPU     16

int main(void)
{
    //This code only caters for first 8 CPUs available
    long double cpu_a[NUM_CPU+1][4], cpu_b[NUM_CPU+1][4], loadavg[NUM_CPU];
    FILE *fp;
    char dump[50];

    while(1)
    {
        int count = 0;
        fp = fopen("/proc/stat","r");
        while(count < NUM_CPU+2)
        {
          fscanf(fp,"%*s %Lf %Lf %Lf %Lf",&cpu_a[count][0],&cpu_a[count][1],&cpu_a[count][2],&cpu_a[count][3]);
          count++;
        }
        fclose(fp);
        usleep(200*1000); // 200 msec sleep and read the /proc/stat file again

        count = 0;
        fp = fopen("/proc/stat","r");
        while(count < NUM_CPU+2)
        {
          fscanf(fp,"%*s %Lf %Lf %Lf %Lf",&cpu_b[count][0],&cpu_b[count][1],&cpu_b[count][2],&cpu_b[count][3]);
          count++;
        }
        fclose(fp);

        for(int i = 1; i < NUM_CPU+2; i++)
        {
          loadavg[i-1] = ((cpu_b[i][0]+cpu_b[i][1]+cpu_b[i][2]) - (cpu_a[i][0]+cpu_a[i][1]+cpu_a[i][2])) / ((cpu_b[i][0]+cpu_b[i][1]+cpu_b[i][2]+cpu_b[i][3]) - (cpu_a[i][0]+cpu_a[i][1]+cpu_a[i][2]+cpu_a[i][3]));
          printf("The current CPU %d utilization is : %Lf\n", (i-1), loadavg[i-1]);
        }
        printf("\n\n");
    }

    return(0);
}

注:这里,在程序中,CPU利用率1.0 = 100%CPU利用率。


0
投票

正如您在后续答案中已经演示的那样,您需要迭代输出行。

但是,要迭代所有存在的CPU而不知道总数,您可以简单地定义一个C结构,并使用任意(高)计数对其进行实例化。

我已经修改了类似于我的例子,所以输出是不同的,但应该足够作为一个例子。

(没有经过很好的测试,可能会有一些明显的逻辑漏洞,但再一次,一个例子)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

/*
outputs CPU utilization for up to MAX_CPU CPUs.

* To output only the individual CPUs and not the combined total, set SKIP_TOTAL to 1
* To output only the combined total, set SKIP_TOTAL to 0, and MAX_CPU to 0
*/

#define MAX_CPU     64  // arbitrary max; can be set to 0 to only output overall
#define SKIP_TOTAL  1   // skips first "cpu", set to 0 to include in output

struct CPUS {
  char id[4];
  long double user;
  long double nice;
  long double system;
  long double idle;
  long double idle_last;  // store previous idle value
  long double sum_last;   // store previous sum value
};

struct CPUS cpus[MAX_CPU + 1];

void calculate(int output) {
  long cpu_delta, cpu_idle, cpu_used, utilization;
  FILE *fp;

  int last_cpu = 0;
  int cpu_num = 0;
  int sum;

  fp = fopen("/proc/stat", "r");

  while (last_cpu == 0 && cpu_num <= MAX_CPU) {
    fscanf(
      fp, "%s %Lf %Lf %Lf %Lf%*[^\n]\n",
      (char *)&cpus[cpu_num].id, &cpus[cpu_num].user, &cpus[cpu_num].nice,
      &cpus[cpu_num].system, &cpus[cpu_num].idle
    );

    // check if the first colum (placed in the id field) contains "cpu", if
    // not, we are no longer processing CPU related lines
    if(strstr(cpus[cpu_num].id, "cpu") != NULL) {

      if (cpu_num == 0) {
        if (SKIP_TOTAL == 1) {
          cpu_num += 1;
          continue;
        } else {
          // overwrite "cpu" to "all"
          strcpy(cpus[cpu_num].id, "all");
        }
      }

      // sum all of the values
      sum = cpus[cpu_num].user + cpus[cpu_num].nice + \
        cpus[cpu_num].system + cpus[cpu_num].idle;

      // collect the difference between sum and the last sum
      cpu_delta = sum - cpus[cpu_num].sum_last;
      // collect idle time
      cpu_idle = cpus[cpu_num].idle - cpus[cpu_num].idle_last;
      // delta minus ide time
      cpu_used = cpu_delta - cpu_idle;
      // percentage of utilization
      utilization = (100 * cpu_used) / cpu_delta;

      if (output == 1) {
        printf("%s:\t%li%%\n", cpus[cpu_num].id, utilization);
      }

      // store the current sum and idle time for calculation on next iteration
      cpus[cpu_num].sum_last = sum;
      cpus[cpu_num].idle_last = cpus[cpu_num].idle;
    } else {
      // no more CPUs to enumarte; exit while loop
      last_cpu = 1;
    }
    cpu_num += 1;
  }
  fclose(fp);
}

int main(void) {
  calculate(0);     // first pass to collect baseline (no output)
  usleep(200*1000); // wait
  calculate(1);     // collect again and output

  return 0;
}

© www.soinside.com 2019 - 2024. All rights reserved.