热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

使用rdtsc对intel进行汇编器基准测试给出了奇怪的答案,为什么?

如何解决《使用rdtsc对intel进行汇编器基准测试给出了奇怪的答案,为什么?》经验,为你挑选了1个好方法。

前一段时间,我问了一个关于堆栈溢出的问题,并展示了如何在C++中执行rdtsc操作码.我最近使用rdtsc创建了一个基准函数,如下所示:

inline unsigned long long rdtsc() {
  unsigned int lo, hi;
  asm volatile (
     "cpuid \n"
     "rdtsc" 
   : "=a"(lo), "=d"(hi) /* outputs */
   : "a"(0)             /* inputs */
   : "%ebx", "%ecx");     /* clobbers*/
  return ((unsigned long long)lo) | (((unsigned long long)hi) <<32);
}

typedef uint64_t (*FuncOneInt)(uint32_t n);
/**
     time a function that takes an integer parameter and returns a 64 bit number
     Since this is capable of timing in clock cycles, we won't have to do it a
     huge number of times and divide, we can literally count clocks.
     Don't forget that everything takes time including getting into and out of the
     function.  You may want to time an empty function.  The time to do the computation
     can be compute by taking the time of the function you want minus the empty one.
 */
void clockBench(const char* msg, uint32_t n, FuncOneInt f) {
    uint64_t t0 = rdtsc();
    uint64_t r = f(n);
    uint64_t t1 = rdtsc();
    std::cout <uint64_t empty(uint32_t n) {
    return 0;
}

uint64_t sum1Ton(uint32_t n) {
    uint64_t s = 0;
    for (int i = 1; i <= n; i++)
        s += i;
    return s;
}

代码是使用编译的

g++ -g -O2

我可以理解是否由于中断或其他条件导致了一些错误,但考虑到这些例程很短,并且选择n很小,我认为我可以看到实数.但令我惊讶的是,这是两次连续运行的输出

empty n=100 elapsed=438
Sum 1 to n=100  elapsed=887

empty n=100 elapsed=357
Sum 1 to n=100  elapsed=347

一直以来,空函数显示它比预期更多.

毕竟,进入和退出该功能只涉及一些指令.真正的工作是在循环中完成的.别担心方差很大.在第二次运行中,空函数声称需要357个时钟周期,总和需要更少,这是荒谬的.

怎么了?



1> Peter Cordes..:

一直以来,空函数显示它比预期更多.

你有cpuid定时间隔. cpuid根据Agner Fog的测试,英特尔Sandybridge系列CPU需要100至250个核心时钟周期(取决于您忽略设置的输入).(https://agner.org/optimize/).

但是你没有测量核心时钟周期,你正在测量RDTSC参考周期,这可能会明显缩短.(例如我的Skylake i7-6700k在800MHz时空闲,但参考时钟频率为4008 MHz.)请参阅获取CPU周期数?因为我尝试了一个规范的答案rdtsc.

首先预热CPU,或者pause在另一个核心上运行忙碌循环以使其保持最大值(假设它是台式机/笔记本电脑的双核或四核,其中所有核心频率都锁定在一起.)


别担心方差很大.在第二次运行中,空函数声称需要357个时钟周期,总和需要更少,这是荒谬的.

这种效果是否也一致?

也许你的CPU在打印第3行消息期间/之后达到全速,使最后一个定时区域运行得更快?(为什么这个延迟循环在没有睡眠的几次迭代后开始运行得更快?).

IDK在eax和ecx之前cpuid可以有多大的不同垃圾效果.替换它lfence以消除它并使用更低的开销方式来序列化rdtsc.


推荐阅读
author-avatar
残破的前进
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有