对于一项作业,我一直在尝试开展一个项目,以纯 C 或内联 ASM 形式检查和检索 Linux 上的系统信息。我现在遇到的一个问题实际上是检索时钟速度。
我最初尝试只阅读
__cpuid
:
__cpuid(0x80000002 + i, eax, ebx, ecx, edx);
我不相信在 AMD CPU 上,时钟速度会包含在该字符串中。现在,我使用
rdtsc
来检索相当准确的数字,但是我越减少忙等待循环的时间,我失去的准确性就越高。到目前为止,这就是我想出的:
static inline uint64_t rdtsc() {
unsigned int lo, hi;
asm volatile ("rdtsc" : "=a" (lo), "=d" (hi));
return ((uint64_t)hi << 32) | lo;
}
void calculate_cpu_clock_speed() {
uint64_t start, end;
struct timespec ts_start, ts_end;
double elapsed_time;
// Get TSC and time at start
start = rdtsc();
clock_gettime(CLOCK_MONOTONIC, &ts_start);
// (~1 ms)
do {
clock_gettime(CLOCK_MONOTONIC, &ts_end);
elapsed_time = (ts_end.tv_sec - ts_start.tv_sec) +
(ts_end.tv_nsec - ts_start.tv_nsec) / 1e9;
} while (elapsed_time < 0.001);
end = rdtsc();
(cycles per second -> Hz -> GHz)
double clock_speed_hz = (end - start) / elapsed_time;
double clock_speed_ghz = clock_speed_hz / 1e9;
printf("%.1f0 GHz\n", clock_speed_ghz);
}
有机会更快地实现这个目标吗?
以下 C 程序从 sys 文件系统中检索各个 CPU 内核的当前频率。也许这是解决您问题的有效方法。
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#define PATH_LEN 80
#define CORES 8
#define INDEX_CPU_ID 27
#define PATH "/sys/devices/system/cpu/cpuX/cpufreq/scaling_cur_freq"
void error(const char *msg) {
perror(msg);
exit(errno);
}
int main() {
char path[strlen(PATH)+1];
strcpy(path,PATH);
for(int i=0;i<CORES;i++) {
path[INDEX_CPU_ID] = i+'0';
FILE *fp = fopen(path, "r");
if (fp == NULL) continue;
unsigned int freq;
if (fscanf(fp, "%u", &freq) != 1) perror(path);
printf("CPU %d frequency: %u kHz\n", i, freq);
fclose(fp);
}
}