繁体   English   中英

比较rdtsc clock和c ++ 11 std :: chrono :: high_resolution_clock产生的时间测量结果

[英]Comparing the time measured results produced by rdtsc clock and c++11 std::chrono::high_resolution_clock

我试图比较c ++ 11 std::chrono::high_resolution_clock rdtsc_clock std::chrono::high_resolution_clock rdtsc_clock时间和下面的rdtsc_clock时钟。 high_resolution_clock ,我得到的结果如rdtsc_clock 。从rdtsc_clock ,我得到rdtsc_clock等。为什么他们的结果看起来如此不同? 从我的直觉来看,我相信rdtsc_clock正在呈现〜准确的结果,对吗?

    template<std::intmax_t clock_freq>
    struct rdtsc_clock {
        typedef unsigned long long rep;
        typedef std::ratio<1, clock_freq> period;
        typedef std::chrono::duration<rep, period> duration;
        typedef std::chrono::time_point<rdtsc_clock> time_point;
        static const bool is_steady = true;

        static time_point now() noexcept
        {

            unsigned lo, hi;
            asm volatile("rdtsc" : "=a" (lo), "=d" (hi));

            return time_point(duration(static_cast<rep>(hi) << 32 | lo));
        }
    };

时间码:

typedef std::chrono::high_resolution_clock Clock;
//typedef rdtsc_clock<3300000000> Clock;
typedef std::chrono::nanoseconds nanoseconds;
typedef std::chrono::duration<double, typename Clock::period> Cycle;
for(int n=0; n < 10; n++){
   auto t1 = Clock::now();
   //codes
   auto t2 = Clock::now();
   printf(%.0f ns \n", duration_cast<nanoseconds>(Cycle(t2 - t1)).count());
}

RDTSC使用问题

如果您在RDTSC上阅读了一些在线文档,您将看到它不能确保在RDTSC指令本身运行之前RDTSC指令之后的指令没有在管道中执行(前面的指令也不会在之后运行)。 通常的建议是在RDTSC之前和/或之后立即使用CPUID指令来触发这样的“序列点”。 显然,这会影响程序性能,并且对于某些类型的测量比其他测量更为理想(其中平均吞吐量数字比单个样本更有意义)。 您可以预期标准库实现会对此更加谨慎,这可能是其测量值远高于此的一个原因。

跨核心问题(根据您的评论不相关)

每个CPU内核都维护着自己的TSC寄存器......如果你只是开始在一个没有绑定到核心的线程上采样,或者在没有绑定到同一个核心的多个线程上采样,你可能会看到值“奇怪”的跳转。 一些公司(例如微软)坚持认为硬件抽象层(HAL)负责尽可能使寄存器尽可能接近同步,但许多(甚至是全新的高端)PC都无法做到这一点。

您可以通过绑定到核心来解决这个问题,或者通过执行一些测量跨核心增量的校准步骤(带有一些校准误差余量),然后根据它们被采样的核心调整后续样本(这本身就是在大多数CPU上确定是很痛苦的 - 你需要在CPUID指令或类似的东西之间旋转采样。

我认为你不是在比较同样的事情,在我的mac上这个例子工作,rdtsc和std :: chrono给出相同数量的循环,如果它可以帮助:

#include <iostream>
#include <vector>
#include <numeric>
#include <chrono>

static __inline__ unsigned long long rdtsc(void){
    unsigned hi, lo;  
    __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
    return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32   );
}

static int sink = 0;

int main(){
    typedef std::ratio<1, 2400000000> period; // My mac @ 2.4 GHz
    unsigned long long int a,b;
    for (auto size = 1ull; size < 1000000000ull; size *= 100) {
        // record start time
        auto start = std::chrono::high_resolution_clock::now();
        a = rdtsc();
        // do some work
        std::vector<int> v(size, 42);
        sink = std::accumulate(v.begin(), v.end(), 0u); // make sure it's a side effect
        // record end time
        b = rdtsc();
        auto end = std::chrono::high_resolution_clock::now();
        std::chrono::duration<double, period> diff = end-start;
        std::cout << "Time to fill and iterate a vector of "
                  << size << " ints : " << diff.count() << " [cycle]"
                  << ", old style: "<< b-a << " [cycle] \n";
   }
}


Time to fill and iterate a vector of 1 ints : 13965.6 [cycle], old style: 13731 [cycle] 
Time to fill and iterate a vector of 100 ints : 1065.6 [cycle], old style: 969 [cycle] 
Time to fill and iterate a vector of 10000 ints : 68076 [cycle], old style: 67899 [cycle] 
Time to fill and iterate a vector of 1000000 ints : 5.4853e+06 [cycle], old style: 5483487 [cycle] 
Time to fill and iterate a vector of 100000000 ints : 6.57399e+08 [cycle], old style: 657395277 [cycle] 

我发现Timocafe在我自己的Mac笔记本电脑上的示例代码存在很大差异

clang++ 9.1.0 -O3 Time to fill and iterate a vector of 1 ints : 27650.4 [cycle], old style: 35464 [cycle] Time to fill and iterate a vector of 100 ints : 763.2 [cycle], old style: 939 [cycle] Time to fill and iterate a vector of 10000 ints : 90712.8 [cycle], old style: 117181 [cycle] Time to fill and iterate a vector of 1000000 ints : 4.79993e+06 [cycle], old style: 6199891 [cycle] Time to fill and iterate a vector of 100000000 ints : 4.80331e+08 [cycle], old style: 620426953 [cycle]

g++ 5.5 -O3 Time to fill and iterate a vector of 1 ints : 2400 [cycle], old style: 1324 [cycle] Time to fill and iterate a vector of 100 ints : 0 [cycle], old style: 944 [cycle] Time to fill and iterate a vector of 10000 ints : 96000 [cycle], old style: 125444 [cycle] Time to fill and iterate a vector of 1000000 ints : 5.4648e+06 [cycle], old style: 7059362 [cycle] Time to fill and iterate a vector of 100000000 ints : 5.05517e+08 [cycle], old style: 652940006 [cycle]

像0时间这样的事情很麻烦。 这表明编译器重新排序了high_precision_clock周围的东西。 至少使用我们的汇编代码rdtsc定时器,我们可以使用volatile来获得我们想要的一些行为。 如果我把rdtsc调用放在high_precision_clock调用中,那么我就可以获得一个单调时钟,这会告诉我,我们的程序集中的volatile是保持排序的。 此外, time_point似乎在两个编译器中具有不同的单位和精度。 啊。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM