2016-03-19 4 views
2

__rdtscp intrinsinc関数を使用して時間間隔を測定しようとしています。ターゲットプラットフォームはLinux x64、CPU Intel Xeon X5550です。Intel Xeon X5550のLinuxでは__rdtscp較正が不安定です

$ taskset -c 1 ./ticks 
Ticks per usec: 256 
$ taskset -c 1 ./ticks 
Ticks per usec: 330.667 
$ taskset -c 1 ./ticks 
Ticks per usec: 345.043 
$ taskset -c 1 ./ticks 
Ticks per usec: 166.054 
$ taskset -c 1 ./ticks 
Ticks per usec: 256 
$ taskset -c 1 ./ticks 
Ticks per usec: 345.043 
$ taskset -c 1 ./ticks 
Ticks per usec: 256 
$ taskset -c 1 ./ticks 
Ticks per usec: 330.667 
$ taskset -c 1 ./ticks 
Ticks per usec: 256 
$ taskset -c 1 ./ticks 
Ticks per usec: 330.667 
$ taskset -c 1 ./ticks 
Ticks per usec: 330.667 
$ taskset -c 1 ./ticks 
Ticks per usec: 345.043 
$ taskset -c 1 ./ticks 
Ticks per usec: 256 
$ taskset -c 1 ./ticks 
Ticks per usec: 125.388 
$ taskset -c 1 ./ticks 
Ticks per usec: 360.727 
$ taskset -c 1 ./ticks 
Ticks per usec: 345.043 

我々はプログラムの実行の間の差が3倍(125から360)までとすることができる見ることができるように:constant_tscフラグは、このプロセッサのために設定されているが、__rdtscp較正は非常に異なった結果を与えます。このような不安定性は、いかなる測定にも不適切である。ここで

は(、GCC 4.9.3オラクルのLinux 6.6カーネル3.8.13-55.1.2.el6uek.x86_64上で実行されている)のコードです:私は、Windows 7の下に非常によく似たプログラムを実行

// g++ -O3 -std=c++11 -Wall ticks.cpp -o ticks 
#include <x86intrin.h> 
#include <ctime> 
#include <cstdint> 
#include <iostream> 

int main() 
{  
    timespec start, end; 
    uint64_t s = 0; 

    const double rdtsc_ticks_per_usec = [&]() 
    { 
     unsigned int dummy; 

     clock_gettime(CLOCK_MONOTONIC, &start); 

     uint64_t rd_start = __rdtscp(&dummy); 
     for (size_t i = 0; i < 1000000; ++i) ++s; 
     uint64_t rd_end = __rdtscp(&dummy); 

     clock_gettime(CLOCK_MONOTONIC, &end); 

     double usec_dur = double(end.tv_sec) * 1E6 + end.tv_nsec/1E3; 
     usec_dur -= double(start.tv_sec) * 1E6 + start.tv_nsec/1E3; 

     return (double)(rd_end - rd_start)/usec_dur; 
    }(); 

    std::cout << s << std::endl; 
    std::cout << "Ticks per usec: " << rdtsc_ticks_per_usec << std::endl; 
    return 0; 
} 

、i7-4470、VS2015較正の結果はかなり安定していて、最後の桁の小さな差のみです。

だから、その問題は何ですか?それはCPUの問題、Linuxの問題または私のコードの問題ですか?

+2

'constant_tsc'は、TSCがCPUの実際の周波数に固定されていないことを意味します。最適化されたタイミングループの問題のほかに、ウォームアップループを実行して、タイミングループが始まる前に最大ターボクロック速度までCPUを取得する必要があります。 –

答えて

2

間違いなく私のコード(またはgcc)の問題でした。コンパイラはループを最適化してs = 1000000に置き換えました。この較正ループを最適化するために、GCCを防ぐため

は、この方法を変更しなければならない:

for (size_t i = 0; i < 1000000; ++i) s += i; 

以上簡単かつ正確な方法(HALのおかげで):

for (volatile size_t i = 0; i < 1000000; ++i); 
+0

誰かがあなたの質問に正しく答えるなら、受け入れられた答えが正しいかどうかを自分で説明するのではなく、受け入れられたものとして回答をマークするのが丁寧です... – Hal

3

ジッタの他の供給源がされますあなたはまた、CPUが隔離されていることを確認していない場合はそこに。あなたは本当にそのコアでスケジュールされた別のプロセスを避けたいと思っています。 また、理想的には、そのコア上でカーネルコードを全く実行しないように、ティックレスカーネルを実行します。上記のコードでは、clock_gettime()と__rdtscpの呼び出しの間に目盛りやコンテキストの切り替えを行うのに不運な場合にのみ問題になると思います。

コンパイラ最適化を無効にするもう1つの方法は、 。

+0

この場合、 'volatile ' 'は還元剤です。 – Rost

関連する問題