【问题标题】:Negative cycles per byte? rdtsc C每个字节的负周期? rdtsc C
【发布时间】:2013-07-31 12:19:52
【问题描述】:

我编写了一些代码来测量每个字节的 cpu 周期。我越来越消极cpb 但不知道为什么...它告诉我cpb = -0.855553 cycles/byte

我的伪代码

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

uint64_t rdtsc(){
    unsigned int lo,hi;
    __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
    return ((uint64_t)hi << 32) | lo;
}

int main()
{
    long double inputsSize = 1024;
    long double counter = 1;

    long double cpuCycleStart = rdtsc();

        while(counter < 3s)
            function(args);

    long double cpuCycleEnd = rdtsc();

        long double cpb = ((cpuCycleEnd - cpuCycleStart) / (counter *  inputsSize));

    printf("%Lf cycles/byte\n", cpb);

    return 0;
}

编辑,改进代码,结果相同(否定):

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

unsigned long rdtsc( void )
    {
        unsigned long lo, hi;
        asm( "rdtsc" : "=a" (lo), "=d" (hi) );
        return( lo );
    }

int main()
{
    long double counter;
    long double inputsSize = 1024;
    char *buff = createInput(inputsSize);

    long double cpuCycleStart = rdtsc();
        countDownTime(3.0);
    for(counter=1; !secondsElapsed; counter++)
            function(args);
    long cpuCycleEnd = rdtsc();

        long double cpb = ((cpuCycleEnd - cpuCycleStart) / (counter *  inputsSize));

    printf("%Lf cycles/byte\n", cpb);

    return 0;
}

真的很奇怪。编写测试代码:

printf("\n%lu cpuCycleEnd \n%lu cpuCycleStart \n", cpuCycleEnd, cpuCycleStart);
    printf("\n%lu counter\n%lu inputsSize \n\n", counter, inputsSize);

        long double cpb = (((long double)cpuCycleEnd - (long double)cpuCycleStart) / ((long double)counter *  (long double)inputsSize));

    printf("%Lf cycles/byte\n", cpb);

其中显示:

30534991 cpuCycleEnd 
1139165971 cpuCycleStart 

1273029 counter
1024 inputsSize 

-0.850450 cycles/byte

有什么想法吗?

【问题讨论】:

  • 为什么要将uint64_t 存储到long double 中?
  • 顺便说一下,在现代处理器上,rdtsc 被定义为测量实时(挂钟时间),而不是处理器时间。英特尔几年前更改了规范。在处理器速度发生变化或各种电源状态时,它不会测量处理器周期。
  • 在现有的printf之前,分别打印cpuCycleEndcpuCycleStartcounterinputsSize的值。如果counterinputsSize 是否定的,找出原因并修复它们。如果cpuCycleEnd 小于cpuCycleStart,找出原因。柜台包装了吗?它们是否接近rdtsc 调用返回的其他值(如果您插入更多调用来查看)? unsigned long 是您的 C 实现中的 64 位吗?如果将rdtsc 的值打印为unsigned long,是否与将其转换为double 后打印的值相同?
  • 请注意,64 位 double 无法存储 64 位 unsigned long 的所有位。如果rdtsc 值设置了一些高九位,您可能会遇到舍入错误。这应该会导致减法中的精度丢失,但不会丢失负值(舍入的效果应该是单调的),直到计数器换行。在任何情况下,最好将rdtsc 值存储为uint64_t,直到它们被减去,然后如果需要,将减去的结果转换为double
  • 当我为 i386 编译和执行(unsigned long 是 32 位)时,我得到一个否定的结果(通常),但当我为 x86_64 编译和执行(unsigned long 是 64 位)时却没有。检查您的构建目标是否为 64 位目标。添加一个语句printf("sizeof(unsigned long) is %zu bytes.\n", sizeof(unsigned long));,看看它是否打印了8。最好使用#include &lt;stdint.h&gt; 并使用uint64_t 而不是unsigned long。此外,我必须进行一些修改才能编译。如果问题仍然存在,请发帖self-contained compilable example

标签: c performance benchmarking cpu-usage


【解决方案1】:

您正在为 unsigned long 为 32 位的目标进行编译。

您应该#include &lt;stdint.h&gt; 并使用uint64_t 而不是unsigned long。此外,您可能希望针对 unsigned long 为 64 位的目标进行编译。

(注意:要打印uint64_t#include &lt;inttypes.h&gt; 并使用printf("%" PRIu64 "\n", value);。)

【讨论】:

  • 当我将其更改为 uint64_t 时,我得到:error: impossible register constraint in ‘asm’
  • @nullpointer:这对我有用:uint64_t lo, hi; __asm__("rdtsc" : "=a" (lo), "=d" (hi)); return hi &lt;&lt; 32 | lo; 编译 -arch x86_64 时。如果您正在为-arch i386 进行编译,那么您可能需要将lohi 设为32 位整数(uint32_t)并使用return (uint64_t) hi &lt;&lt; 32 | lo;
  • 谢谢,这有效:pastie.org/private/7n1q6ccagthqo70bvhmcq(希望现在终于可以了吗?)。另外,另一个问题。最后我有非负面结果,看看:pastie.org/private/4c9taxfaljgft5spbyv3nq。变量类型现在一切正常吗?
  • 我可以将uint64_tuint32_t 也用于Windows,比如说mingw 和visual?
  • @nullpointer:如果您在此rdtsc 中询问使用uint64_tuint32_t 以及为不同平台构建时的时序代码,那么,是的,您应该寻求使用这些类型,只要它们没有遇到编译器问题(例如,使用 asm 及其操作数约束可能很挑剔)。
猜你喜欢
  • 2013-11-25
  • 1970-01-01
  • 1970-01-01
  • 2012-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-11
  • 2012-10-27
相关资源
最近更新 更多