2

__rdtscpintrinsinc 関数を使用して時間間隔を測定しようとしています。ターゲット プラットフォームは Linux x64、CPU Intel Xeon X5550 です。このconstant_tscプロセッサにはフラグが設定されていますが、キャリブレーション__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) になる可能性があります。このような不安定性は、どの測定にも適していません。

コードは次のとおりです (gcc 4.9.3、Oracle Linux 6.6、カーネル 3.8.13-55.1.2.el6uek.x86_64 で実行):

// 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;
}

Windows 7、i7-4470、VS2015 で非常によく似たプログラムを実行すると、キャリブレーションの結果は非常に安定しており、最後の桁にわずかな違いしかありません。

それで質問です - その問題は何ですか?CPUの問題ですか、Linuxの問題ですか、それとも私のコードの問題ですか?

4

2 に答える 2

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);
于 2016-03-19T12:19:01.190 に答える