7

std::chrono::high_resolution_clock以下のc++ 11とrdtsc_clock時計で測定された時間を比較しようとしています。から、high_resolution_clock11000、3000、1000、0 のような結果が得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());
}
4

3 に答える 3

8

RDTSC の使用に関する問題

RDTSC に関するいくつかのオンライン ドキュメントを読むと、RDTSC 命令自体が実行される前に、RDTSC 命令の後の命令がパイプラインで実行されないことが保証されていないことがわかります (また、以前の命令が後で実行されないこともありません)。通常のアドバイスは、RDTSC の直前または直後に CPUID 命令を使用して、そのような「シーケンス ポイント」をトリガーすることです。明らかに、これはプログラムのパフォーマンスに影響を与え、ある種の測定では他の測定よりも望ましいものです (個々のサンプルよりも平均スループットの数値が重要な場合)。標準ライブラリの実装がこれについてより慎重になっていることが予想できます。これが、測定値がはるかに高い理由の 1 つかもしれません。

クロスコアの問題 (コメントでは関係ありません)

各 CPU コアは独自の TSC レジスタを保持しています。コアにバインドされていないスレッド、または同じコアにバインドされていない複数のスレッドでサンプルの取得を開始すると、値が「奇妙な」ジャンプを示すことがあります。一部の企業 (Microsoft など) は、ハードウェア アブストラクション レイヤー (HAL) がレジスタを可能な限り同期に近づけようとする責任があると主張していますが、多くの (真新しいハイエンドの PC でさえ) これを行うことができません。

これを回避するには、コアにバインドするか、クロスコア デルタを測定するキャリブレーション ステップを実行し (キャリブレーション エラー マージンを使用)、サンプリング元のコアに基づいて後のサンプルを調整します (それ自体はほとんどの CPU で判断するのは困難です。CPUID 命令の間でサンプルを取得する必要があります)。

于 2013-11-01T02:07:05.197 に答える
1

あなたは同じことを比較していないと思います.私の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] 
于 2016-05-19T20:44:21.043 に答える