如何在 C 中的任何 linux 发行版上解析 /proc/cpuinfo
How to parse /proc/cpuinfo on any linux distro in C
我是 运行 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] = '[=12=]';
printf("%s", buffer);
}
这会输出 572 bytes read out of 1152
,但每当我再次使用 fread
时它都会覆盖缓冲区。而且我也不能使用 sysconf(_SC_NPROCESSORS_ONLN);
,因为它似乎不适用于 Ubuntu。
使用 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] = '[=10=]';
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()
中的错误处理,使其对用户友好一些(现在,您真的不知道如果 returns -1 会发生什么)。
更新
正如下面评论中提到的,nproc(1)
在这里可能是更好的选择,至少命令更小。它会以任何方式工作,我们可以将 grep
+ wc
替换为 nproc
.
这是个老问题,但如果有人有同样的问题。此代码也适用于 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 Model : Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz | Cores : 12 | Average Frequency : 808.687
这是一个如何获取物理内核和虚拟线程的最小示例:
#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
将 return EOF
。这将导致循环安全停止。
此外,此示例不包含检查 fopen
是否失败的错误。这应该按照您认为合适的方式进行。
此 fscanf
技术源自此处:
我是 运行 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] = '[=12=]';
printf("%s", buffer);
}
这会输出 572 bytes read out of 1152
,但每当我再次使用 fread
时它都会覆盖缓冲区。而且我也不能使用 sysconf(_SC_NPROCESSORS_ONLN);
,因为它似乎不适用于 Ubuntu。
使用 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] = '[=10=]';
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()
中的错误处理,使其对用户友好一些(现在,您真的不知道如果 returns -1 会发生什么)。
更新
正如下面评论中提到的,nproc(1)
在这里可能是更好的选择,至少命令更小。它会以任何方式工作,我们可以将 grep
+ wc
替换为 nproc
.
这是个老问题,但如果有人有同样的问题。此代码也适用于 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 Model : Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz | Cores : 12 | Average Frequency : 808.687
这是一个如何获取物理内核和虚拟线程的最小示例:
#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
将 return EOF
。这将导致循环安全停止。
此外,此示例不包含检查 fopen
是否失败的错误。这应该按照您认为合适的方式进行。
此 fscanf
技术源自此处: