【问题标题】:How to parse /proc/cpuinfo on any linux distro in C如何在 C 中的任何 linux 发行版上解析 /proc/cpuinfo
【发布时间】:2015-07-30 10:51:30
【问题描述】:

我正在运行 Ubuntu,但我不明白为什么我很难在 C 中获得系统上的内核数量!我已经尝试在运行 Ubuntu 的系统上成功解析 /proc/cpuinfo,但后来我尝试在另一个运行 arch linux 的系统上失败,因为缓冲区太小,我似乎无法弄清楚如何让它工作我的两个系统。

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

int main() {
  FILE* fp; 
  char *buffer, *tmp; 
  size_t bytes_read, size; 

  if((fp = fopen("/proc/cpuinfo", "r")) == NULL) {
    perror("open failed");
    exit(EXIT_FAILURE); 
  }
  size = 1024;
  if((buffer = malloc(size)) == NULL) {
    perror("malloc failed");
    free(buffer);
    exit(EXIT_FAILURE);
  }
  while(!feof(fp)) {
    bytes_read = fread(buffer, 1, size, fp);
    if(bytes_read == size) {
      size += 128;
      if((tmp = realloc(buffer, size)) == NULL) {
        perror("realloc failed");
        free(buffer);
        exit(EXIT_FAILURE);
      }else {
        buffer = tmp;
      }
    } 
  }
  fclose(fp); 
  if(bytes_read == 0 || bytes_read == size) {
    perror("read failed or buffer isn't big enough.");
    exit(EXIT_FAILURE); 
  }
  printf("%d bytes read out of %d\n", (int)bytes_read,(int) size);
  buffer[bytes_read] = '\0';

  printf("%s", buffer); 
}

这会输出572 bytes read out of 1152,但每当我再次使用fread 时,它都会覆盖缓冲区。我也不能使用sysconf(_SC_NPROCESSORS_ONLN);,因为它似乎在 Ubuntu 上不起作用。

【问题讨论】:

  • 不要这样做while (!feof(...)),它很少会像你期望的那样工作。原因是文件结束标志直到您第一次尝试从文件末尾之外读取之后才设置。这会导致您的循环一次对多次迭代,而您并没有真正注意到。
  • 其次,在指针上使用sizeof 会返回指针的大小,而不是指针所指向的大小。
  • 你的free()realloc() == 0之后什么都不做,原来的内存泄露了。
  • 第三,不要将realloc返回的指针重新分配给你重新分配的指针。如果realloc 失败,您将失去原来的指针。
  • 为什么要读入全部内容才能得到核数?只需解析感兴趣的行。见this answer for an example to parse /proc/cpuinfo or /proc/stat to get the number of cores

标签: c linux ubuntu fread cpu-cores


【解决方案1】:

如何使用popen(3) 执行cat ^processor /proc/cpuinfo | wc -l 来获取CPU 的数量,然后从管道中读取结果?这很简单,您不必维护复杂的代码来读取和解析整个文件。

这是一个例子:

#include <stdio.h>

int ncpus(void) {
    FILE *cmd = popen("grep '^processor' /proc/cpuinfo | wc -l", "r");

    if (cmd == NULL)
        return -1;

    unsigned nprocs;
    size_t n;
    char buff[8];

    if ((n = fread(buff, 1, sizeof(buff)-1, cmd)) <= 0)
        return -1;

    buff[n] = '\0';
    if (sscanf(buff, "%u", &nprocs) != 1)
        return -1;

    pclose(cmd);

    return nprocs;
}

int main(void) {
    int cpus = ncpus();
    if (cpus == -1)
        fprintf(stderr, "Error retrieving number of CPUs\n");
    else
        printf("Number of CPUs: %d\n", cpus);
    return 0;
}

您可能希望改进ncpus() 中的错误处理,使其对用户友好一点(现在,您并不真正知道如果返回 -1 会发生什么)。

更新

正如下面在 cmets 中提到的,nproc(1) 在这里可能是更好的选择,至少命令更小。无论哪种方式都可以,我们可以将grep + wc 替换为nproc

【讨论】:

  • 这是一种很酷的方法,但是使用 nproc 更好吗?我的意思是它肯定不那么复杂。
  • @Linus 啊,是的,绝对!您绝对可以使用nproc(1) 代替grep + wc。我没有考虑。如果您只是更改传递给popen(3) 的命令,它应该可以工作,因为这两个命令具有相同的输出。更新了我的答案(并确认它可以双向工作)。
【解决方案2】:

这是一个如何获取物理内核和虚拟线程的最小示例:

#include <stdio.h>

...

FILE *cpu_info = fopen("/proc/cpuinfo", "r");
unsigned int thread_count, core_count;
while (!fscanf(cpu_info, "siblings\t: %u", &thread_count))
  fscanf(cpu_info, "%*[^s]");
while (!fscanf(cpu_info, "cpu cores\t: %u", &core_count))                   
  fscanf(cpu_info, "%*[^c]");                                                                                          
fclose(cpu_info);

请注意,在此示例中您不需要检查 EOF,因为如果达到 fscanf 将返回 EOF。这将导致循环安全停止。

此外,此示例不包含检查 fopen 是否失败的错误检查。这应该按照您认为合适的方式进行。

fscanf 技术源自这里:https://stackoverflow.com/a/43483850

【讨论】:

    【解决方案3】:

    这是老问题,但如果有人有同样的问题。此代码也适用于 bigLITTLE 处理器。

    #include <string>
    #include <iostream>
    #include <fstream>
    #include <sstream>
    #include<map>
    #include<cstring>
    using namespace std;
    
    int main() {
        map <string,int > cpu_count;
        map <string,float > freq_count;
        string line;
        string temp="";
        ifstream finfo("/proc/cpuinfo");
        while(getline(finfo,line)) {
            stringstream str(line);
            string itype;
            string info;
            stringstream str1(line);
            string itype1;
            string info1;
            
            if ( getline( str, itype, ':' ) && getline(str,info) && itype.substr(0,10) == "model name" ) {
                cpu_count[info]++;
                temp=info;  
            }
    
            if ( getline( str1, itype1, ':' ) && getline(str1,info1) && (itype1.substr(0,7) == "cpu MHz" || itype1.substr(0,8) == "BogoMIPS") ) {
                float freq = stof(info1);
                freq_count[temp]+=freq;
            }
        }
    
        map<string, int>::iterator it1;
        map<string, float>::iterator it2;
        it2=freq_count.begin();
        for (it1 = cpu_count.begin(); it1 != cpu_count.end(); it1++)
        {
            cout << "CPU Model : "<<it1->first << " | Cores : " << it1->second << " | Average Frequency :  " <<it2->second/it1->second<<endl;
            it2++;
        }
        return 0;
    }
    

    输出

    CPU 型号:Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz |芯数:12 |平均频率:808.687

    【讨论】:

    • 这是一个 C++ 答案,这是一个 C 问题。
    猜你喜欢
    • 2014-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多