web-dev-qa-db-ja.com

std :: chrono :: high_resolution_clockの解像度が測定値に対応していません

このテストプログラムで質問してみましょう。

#include <iostream>
#include <chrono>

using std::chrono::nanoseconds;
using std::chrono::duration_cast;

int main(int argc, char* argv[])
{
    std::cout << "resolution (nano) = " << (double) std::chrono::high_resolution_clock::period::num
        / std::chrono::high_resolution_clock::period::den * 1000 * 1000 * 1000 << std::endl;

    auto t1 = std::chrono::high_resolution_clock::now();
    std::cout << "how much nanoseconds std::cout takes?" << std::endl;
    auto t2 = std::chrono::high_resolution_clock::now();


    auto diff = t2-t1;
    nanoseconds ns = duration_cast<nanoseconds>(diff);

    std::cout << "std::cout takes " << ns.count() << " nanoseconds" << std::endl;
    return 0;
}

私のマシンでの出力:

解像度(ナノ)= 100

std :: coutにかかるナノ秒数は?

std :: coutには1000200ナノ秒かかります

結果として1000200または1000300または1000400または1000500または1000600または2000600のいずれか(= 1または2マイクロ秒)を受け取ります。明らかにstd::chronoの解像度はnot 100ナノ秒またはstd::coutの時間を測定する方法が間違っています。 (なぜ1500000?のように1〜2マイクロ秒の間に何かを受信しないのですか?)

C++で高解像度のタイマーが必要です。同じマシンでC#Stopwatchクラスを使用してマイクロ秒の精度で物事を測定できるため、OS自体が高解像度タイマーを提供します。そのため、OSに搭載されている高解像度タイマーを正しく使用する必要があります。

予想される結果を得るためにプログラムを修正するにはどうすればよいですか?

30
javapowered

VS2012を使用していると思います。そうでない場合は、この答えを無視してください。 VS2012 typedefhigh_resolution_clockからsystem_clock。悲しいことに、これは安っぽい精度(約1ms)を持っていることを意味します。私はVS2012で使用するためにQueryPerformanceCounterを使用するより良い高解像度クロックを書きました...

HighResClock.h:

    struct HighResClock
    {
        typedef long long                               rep;
        typedef std::nano                               period;
        typedef std::chrono::duration<rep, period>      duration;
        typedef std::chrono::time_point<HighResClock>   time_point;
        static const bool is_steady = true;

        static time_point now();
    };

HighResClock.cpp:

namespace
{
    const long long g_Frequency = []() -> long long 
    {
        LARGE_INTEGER frequency;
        QueryPerformanceFrequency(&frequency);
        return frequency.QuadPart;
    }();
}

HighResClock::time_point HighResClock::now()
{
    LARGE_INTEGER count;
    QueryPerformanceCounter(&count);
    return time_point(duration(count.QuadPart * static_cast<rep>(period::den) / g_Frequency));
}

(アサートと#ifsを省き、上記のコードから2012年にコンパイルされているかどうかを確認します)

この時計は、どこでも標準時計と同じように使用できます。

52
David

クロックの分解能は、クロックが使用するデータ型で表すことができる最小の持続時間と必ずしも同じではありません。この場合、実装では100ナノ秒という短い期間を表すことができるデータ型を使用しますが、基になるクロックには実際にそのような解像度はありません。


Visual Studioの_high_resolution_clock_の低解像度は、数年前から問題となっています。 MicrosoftのC++標準ライブラリメンテナー、Stephan T. Lavavej、 示されています これはQueryPerformanceCounter()の使用によりVS2015で修正されました。

6
bames53

たぶん、実装は高解像度タイマーを実装していませんか?

あなたはWindowsを使用しているようです(C#に言及しています)ので、タイマーで実際にWindowsを使用している場合は、 QueryPerformanceFrequency および QueryPerformanceCounter を使用できます。

1
graham.reeds