首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >RDTSC开销的差异

RDTSC开销的差异
EN

Stack Overflow用户
提问于 2011-06-21 22:15:15
回答 3查看 5K关注 0票数 15

当我在一些原始图像处理操作中使用SIMD指令本质的实验时,我正在构建一个微基准来测量性能变化。然而,编写有用的微基准是困难的,所以我想首先理解(如果可能的话)尽可能多的变化和错误的来源。

我必须考虑的一个因素是度量代码本身的开销。我正在使用RDTSC进行度量,并使用以下代码查找度量开销:

代码语言:javascript
复制
extern inline unsigned long long __attribute__((always_inline)) rdtsc64() {
    unsigned int hi, lo;
        __asm__ __volatile__(
            "xorl %%eax, %%eax\n\t"
            "cpuid\n\t"
            "rdtsc"
        : "=a"(lo), "=d"(hi)
        : /* no inputs */
        : "rbx", "rcx");
    return ((unsigned long long)hi << 32ull) | (unsigned long long)lo;
}

unsigned int find_rdtsc_overhead() {
    const int trials = 1000000;

    std::vector<unsigned long long> times;
    times.resize(trials, 0.0);

    for (int i = 0; i < trials; ++i) {
        unsigned long long t_begin = rdtsc64();
        unsigned long long t_end = rdtsc64();
        times[i] = (t_end - t_begin);
    }

    // print frequencies of cycle counts
}

在运行此代码时,输出如下所示:

代码语言:javascript
复制
Frequency of occurrence (for 1000000 trials):
234 cycles (counted 28 times)
243 cycles (counted 875703 times)
252 cycles (counted 124194 times)
261 cycles (counted 37 times)
270 cycles (counted 2 times)
693 cycles (counted 1 times)
1611 cycles (counted 1 times)
1665 cycles (counted 1 times)
... (a bunch of larger times each only seen once)

我的问题是:

  1. What是由代码above?
  2. Why生成的循环计数的双模态分布的可能原因--最快的时间(234个周期)只会发生几次--可以减少count?

,这是什么非常不寻常的情况?

进一步信息

平台:

  • Linux2.6.32(Ubuntu10.04)
  • g++ 4.4.3
  • Core 2 Duo (E6600);这具有恒定速率的TSC.

SpeedStep已关闭(处理器设置为性能模式,运行在2.4GHz);如果以“按需”模式运行,则在243和252个周期出现两个峰值,在360和369个周期出现两个(可能对应的)峰值。

我使用sched_setaffinity将进程锁定在一个核心上。如果我依次在每个核心上运行测试(即锁定到核心0并运行,然后锁定到核心1并运行),则两个核心的结果相似,只不过234个周期中最快的时间在核心1上发生的次数比在核心0上的次数要少一些。

编译命令是:

代码语言:javascript
复制
g++ -Wall -mssse3 -mtune=core2 -O3 -o test.bin test.cpp

GCC为核心循环生成的代码是:

代码语言:javascript
复制
.L105:
#APP
# 27 "test.cpp" 1
    xorl %eax, %eax
    cpuid
    rdtsc
# 0 "" 2
#NO_APP
    movl    %edx, %ebp
    movl    %eax, %edi
#APP
# 27 "test.cpp" 1
    xorl %eax, %eax
    cpuid
    rdtsc
# 0 "" 2
#NO_APP
    salq    $32, %rdx
    salq    $32, %rbp
    mov %eax, %eax
    mov %edi, %edi
    orq %rax, %rdx
    orq %rdi, %rbp
    subq    %rbp, %rdx
    movq    %rdx, (%r8,%rsi)
    addq    $8, %rsi
    cmpq    $8000000, %rsi
    jne .L105
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-06-21 22:39:56

RDTSC可以返回不一致的结果,原因如下:

在一些CPU(特别是某些较旧的Opterons)上,

  • 没有在内核之间同步。听起来你已经在用sched_setaffinity来处理这个问题了--很好!
  • --如果操作系统计时器在运行代码时触发中断,那么在运行时会出现延迟。没有实用的方法来避免这种情况;只要在CPU中抛出异常高的values.
  • Pipelining工件,有时就会在紧循环中向任何一个方向抛出几个周期。完全有可能有一些循环运行在一个非整数的时钟周期。
  • 缓存!根据CPU缓存的变化无常,内存操作(如对times[]的写操作)在速度上可能有所不同。在这种情况下,您很幸运,所使用的std::vector实现只是一个平面数组;即使如此,写入也会抛出一些东西。这可能是这段代码最重要的因素。

对于Core2微体系结构,我还不足以确切地说明为什么要获得这个双峰分发版,也不足以说明您的代码如何以28次的速度运行,但这可能与上述原因之一有关。

票数 10
EN

Stack Overflow用户

发布于 2011-12-14 08:46:30

英特尔程序员手册建议您使用lfence;rdtscrdtscp,如果您希望确保rdtsc之前的指令已经实际执行。这是因为rdtsc本身并不是一个序列化指令。

票数 3
EN

Stack Overflow用户

发布于 2011-08-17 12:49:45

您应该确保在OS级别禁用频率节流/绿色功能。重新启动机器。否则,可能会出现核心具有不同步时间戳计数器值的情况。

到目前为止,243阅读是最常见的,这也是使用它的原因之一。另一方面,假设您经过的时间<243:您减去开销,得到一个下流。由于算法没有签名,所以最终得到了一个巨大的结果。这个事实说明使用最低读数(234)代替。要精确测量只有几个周期长的序列是非常困难的。在一个典型的x86 @几个GHz上,我建议不要使用小于10 be的定时序列,即使在这个长度上,它们通常也远离岩石。

我其余的回答是我做什么,我如何处理结果和我对主题的推理。

至于开销,最简单的方法是使用这样的代码

代码语言:javascript
复制
unsigned __int64 rdtsc_inline (void);
unsigned __int64 rdtsc_function (void);

第一个表单将rdtsc指令发送到生成的代码中(如您的代码)。第二个将导致调用函数、执行rdtsc和返回指令。也许它会生成堆栈帧。显然,第二种形式要比第一种慢得多。

然后编写用于计算开销的(C)代码。

代码语言:javascript
复制
unsigned __int64 start_cycle,end_cycle;    /* place these @ the module level*/

unsigned __int64 overhead;
    
/* place this code inside a function */
    
start_cycle=rdtsc_inline();
  end_cycle=rdtsc_inline();
overhead=end_cycle-start_cycle;

如果您使用内联变体,您将获得较低的开销(呃)。您还将面临计算比“应该”更大的开销的风险(特别是对于函数形式),这反过来意味着,如果您测量非常短/快速的序列,您可能会遇到以前计算的开销大于度量本身的开销。当你试图调整你的开销,你会得到一个下流,这将导致混乱的情况。处理这件事的最好方法是

  1. 时间开销多次,并且总是使用实现的最小值,
  2. 不会度量真正短的代码序列,因为您可能会遇到流水线效果,如果您必须测量非常短的序列,而不是事实,那么在rdtsc指令和
  3. 之前,可能会遇到混乱的同步指令。

我之前已经讨论过如何处理this thread中的结果。

我要做的另一件事是将度量代码集成到应用程序中。开销是微不足道的。在计算结果之后,我将其发送到一个特殊的结构中,在该结构中,我计算测量的数量、和x和x^2值,并确定最小和最大测量值。稍后,我可以使用数据来计算平均值和标准差。该结构本身是索引的,我可以测量不同的性能方面,例如单独的应用程序功能(“功能性能”),在cpu中花费的时间,磁盘读写,网络读写(“非功能性能”)等等。

如果应用程序从一开始就以这种方式进行检测和监视,我预计它在其生命周期内出现性能问题的风险将大大降低。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6432669

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档