c/c++开发分享使用RDTSC指令测量C中的代码执行时间

我写了一个简单的程序来测量使用RDTSC指令的代码执行时间。 但我不知道我的结果是否正确以及我的代码有什么问题…我不知道如何validation它。

#include  #include  #include  #include  #define N (1024*4) unsigned cycles_low, cycles_high, cycles_low1, cycles_high1; static __inline__ unsigned long long rdtsc(void) { __asm__ __volatile__ ("RDTSCnt" "mov %%edx, %0nt" "mov %%eax, %1nt": "=r" (cycles_high), "=r" (cycles_low):: "%rax", "rbx", "rcx", "rdx"); } static __inline__ unsigned long long rdtsc1(void) { __asm__ __volatile__ ("RDTSCnt" "mov %%edx, %0nt" "mov %%eax, %1nt": "=r" (cycles_high1), "=r" (cycles_low1):: "%rax", "rbx", "rcx", "rdx"); } int main(int argc, char* argv[]) { uint64_t start, end; rdtsc(); malloc(N); rdtsc1(); start = ( ((uint64_t)cycles_high << 32) | cycles_low ); end = ( ((uint64_t)cycles_high1 << 32) | cycles_low1 ); printf("cycles spent in allocating %d bytes of memory: %llun",N, end - start); return 0; } 

    在使用RDTSC计时时,您应该记住一些(非显而易见的)问题:

    我的建议:只需使用您的操作系统具有的任何高频计时器API。 在Windows上,这是QueryPerformanceCounter,在Unix上,你有gettimeofday或clock_gettime。

    除此之外,您的RDTSC代码存在一些结构性问题。 返回类型是“unsigned long long”,但实际上没有返回任何内容。 如果你修复了这个问题,你可以避免将结果存储在全局变量中,并且可以避免编写多个版本。

    可能影响您获得的结果的问题是:


    注意:我不是GCC内联汇编的专家; 但我强烈怀疑你的宏是错误的,编译器可以选择生成这样的东西:

      rdtsc mov %edx, %eax ;Oops, trashed the low 32 bits mov %eax, %ebx 

    应该可以告诉GCC在EDX:EAX中返回值/ s并完全删除两个mov指令。

    注意:在我写这篇文章时,我想出了一种更简单/更清晰的方法来校准TSC转换因子。 所以,继续阅读……

    如果您愿意,在linux下[其他一些操作系统有类似的东西 – 例如BSD实现了linux / proc的一部分],在/proc/cpuinfo ,您将看到如下字段:

     bogomips : 5306.71 flags : blah blah2 constant_tsc processor : blah 

    如果您读取此文件,则bogomips是系统引导期间计算的Mhz [sort of]的总CPU频率。 如果您的机器具有速度步长,则cpu Mhzcpu Mhz

    要使用bogomips ,请计算processor行数并将bogomips除以它。 注意剥去“。” 并将其视为Khz并使用整数数学。

    如果你有constant_tscTSC将始终以这个[最大]频率运行,并且永远不会变化,无论特定核心是否由于速度步长而减慢。

    如果读/proc/cpuinfo使您感到娇气,则可以采用另一种方法来校准/确定TSC频率。

    请执行下列操作:

     tsc1 = rdtsc clk1 = clock_gettime // delay for a while for (i = 1; i < 1000000; ++i) asm volatile ("" ::: "memory"); clk2 = clock_gettime tsc2 = rdtsc 

    使用这些值,您可以计算TSC频率。 做上面几千次。 采用最小增量 - 这可以防止操作系统时间切掉你的测量值。

    对于不会导致时间片的循环计数,请使用最大值。 实际上,您可以使用tv_sec = 0, tv_nsec = 500000 (500 us)的nanosleep替换循环。 nanosleepnanosleep好得多。 实际上,如果你nanosleep ,你可以在2-3秒内进行nanosleep

    clk2 - clk2值[转换]为小数秒,为您提供tsc2 - tsc1的校准和TSC滴答和秒的转换。

    32位平台有“= A”。 这将创建来自eax和edx的64位结果。 遗憾的是,在64位平台上,它只是意味着rax寄存器,这没有任何帮助。

    相反,更好的是,您可以使用“__builtin_ia32_rdtsc()”内在函数直接返回64位无符号整数。 同样适用于rdtscp(也返回当前核心)。 请参阅gcc手册。 与使用内联asm手动执行相比,它们发出的代码稍微好一些,并且可以在32位和64位之间移植。

    如果在/ proc / cpuinfo标志中设置了“constant_tsc”,则无论CPU频率如何缩放,TSC都以恒定速率运行。 如果设置了“nonstop_tsc”,则TSC继续以C(hibernate)状态运行。 如果两者都设置,计数器“应该”也在核心之间同步(至少在最近的CPU,Core i7或更高版本上)。 我对最后一点不太确定,也许有人可以纠正我?

      以上就是c/c++开发分享使用RDTSC指令测量C中的代码执行时间相关内容,想了解更多C/C++开发(异常处理)及C/C++游戏开发关注(猴子技术宅)。

      本文来自网络收集,不代表猴子技术宅立场,如涉及侵权请点击右边联系管理员删除。

      如若转载,请注明出处:https://www.ssfiction.com/c-cyuyankaifa/545979.html

      发表评论

      电子邮件地址不会被公开。 必填项已用*标注