使用 RDTSC 在 C 中计算 CPU 频率总是返回 0

标签 c cpu clock frequency performance

下面的代码是我们的导师给我们的,所以我们可以衡量一些算法的性能:

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

static unsigned cyc_hi = 0, cyc_lo = 0;

static void access_counter(unsigned *hi, unsigned *lo) {
    asm("rdtsc; movl %%edx,%0; movl %%eax,%1"
    : "=r" (*hi), "=r" (*lo)
    : /* No input */
    : "%edx", "%eax");
}

void start_counter() {
    access_counter(&cyc_hi, &cyc_lo);
}

double get_counter() {
    unsigned ncyc_hi, ncyc_lo, hi, lo, borrow;
    double result;

    access_counter(&ncyc_hi, &ncyc_lo);

    lo = ncyc_lo - cyc_lo;
    borrow = lo > ncyc_lo;
    hi = ncyc_hi - cyc_hi - borrow;

    result = (double) hi * (1 << 30) * 4 + lo;

    return result;
}

但是,我需要此代码能够移植到具有不同 CPU 频率的机器上。为此,我正在尝试计算运行代码的机器的 CPU 频率,如下所示:

int main(void)
{
    double c1, c2;

    start_counter();

    c1 = get_counter();
    sleep(1);
    c2 = get_counter();

    printf("CPU Frequency: %.1f MHz\n", (c2-c1)/1E6);
    printf("CPU Frequency: %.1f GHz\n", (c2-c1)/1E9);

    return 0;
}

问题是结果总是0,我不明白为什么。我在 VMware 上以访客身份运行 Linux (Arch)。

在 friend 的机器(MacBook)上,它在某种程度上可以工作;我的意思是,结果大于 0 但它是可变的,因为 CPU 频率不固定(我们试图修复它但由于某种原因我们无法做到)。他有一台运行 Linux (Ubuntu) 作为主机的不同机器,它也报告 0。这排除了虚拟机上的问题,我一开始以为是问题所在。

知道为什么会发生这种情况吗?我该如何解决?

最佳答案

好的,既然其他答案没有帮助,我会尝试更详细地解释。问题是现代 CPU 可以乱序执行指令。你的代码开始是这样的:

rdtsc
push 1
call sleep
rdtsc

不过,现代 CPU 不一定必须按指令的原始顺序执行指令。尽管有您的原始命令,但 CPU(大部分)可以自由执行,就像:

rdtsc
rdtsc
push 1
call sleep

在这种情况下,很明显为什么两个 rdtsc 之间的差异会(至少非常接近)0。为防止这种情况发生,您需要执行一条指令,CPU 将 < em>从不重新排列以乱序执行。最常用的指令是 CPUID。我链接的另一个答案应该(如果没记错的话)大致从那里开始,关于正确/有效地使用 CPUID 完成此任务的必要步骤。

当然,Tim Post 可能是对的,您看到了虚拟机的问题。尽管如此,就目前情况而言,无法保证您的代码即使在真实硬件上也能正常工作。

编辑:关于为什么代码工作:好吧,首先,指令可以乱序执行的事实并不能保证它们< em>将会。其次,sleep 的(至少某些实现)可能包含序列化指令以防止 rdtsc 围绕它重新排列,而其他的则没有(或可能包含它们,但仅在特定(但未指定)的情况下执行它们)。

剩下的是几乎任何重新编译都可能改变的行为,甚至只是在一次运行和下一次运行之间。它可以连续数十次产生极其准确的结果,然后由于某些(几乎)完全无法解释的原因(例如,完全在其他过程中发生的事情)而失败。

关于使用 RDTSC 在 C 中计算 CPU 频率总是返回 0,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2814569/

相关文章:

c - 格式错误?

linux - 如何在 Linux 上获得整体 CPU 使用率(例如 57%)

windows - 持续监控 Top X 进程的 CPU 使用率百分比

java - 如何在java中更新小时?

c - 格式字符串未使用数据参数 - 输出长整型

c++ - 我需要帮助来理解 CLOCKS_PER_SEC

创建 makefile 来编译位于不同目录中的多个源文件

c - 为什么用 short* 而不是 char* 作为字符串? char* 和 unsigned char* 的区别?

java - 为什么从无限循环切换到 TimerTask 会导致 CPU 使用率下降?

objective-c - int 不增加