2013-04-01 11 views
5

chrono::steady_clockを使用して、プログラム内のコードブロック間の経過秒数を測定しようとしています。測定時間は0または0.001の戻り値になります

auto start = std::chrono::steady_clock::now(); 
// block of code to time 
auto end = std::chrono::stead_clock::now(); 

auto difference = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() 

std::cout << "seconds since start: " << ((double) difference/1000000); 

プログラムのみ00.001の値を出力します:そうは次のように私は私のプログラムの中に同じアイデアを実装する場合

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

int main() 
{ 
    auto start = std::chrono::steady_clock::now(); 
    for (unsigned long long int i = 0; i < 10000; ++i) { 
     std::vector<int> v(i, 1); 
    } 
    auto end = std::chrono::steady_clock::now(); 

    auto difference = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count(); 

    std::cout << "seconds since start: " << ((double)difference/1000000); 
} 

:私はLiveWorkSpace(http://liveworkspace.org/code/YT1I$9)での作業のコードブロックを持っています。コードブロックの実行時間が常に0または1000マイクロ秒に等しいことは非常に疑問です。この丸めをどのように考慮しているのでしょうか。それを除去して適切な分数値を得る方法はありますか?

これはWindowsプログラムです。

+0

代わりに 'std :: chrono :: high_resolution_clock'を試してみてください。 –

+0

@KerrekSB:これは良い提案ですが、 'steady_clock :: now()'はすでに正確にナノ秒、または少なくともティック(100ナノ秒の間隔)であるべきです。私はここに数学の問題があると思う。 –

+0

@RobertHarvey:ああ、たぶんキャストの間違ったかっこですか? –

答えて

2

MSVC2012でいくつかのテストを実行した後、私はMicrosoftの実装のC++ 11クロックが十分に高い解像度を持っていないことを確認できました。この問題に関するバグレポートについては、C++ header's high_resolution_clock does not have high resolutionを参照してください。

#include <iostream> 
#include <Windows.h> 

int main() 
{ 
    LARGE_INTEGER frequency; 
    QueryPerformanceFrequency(&frequency); 

    LARGE_INTEGER start; 
    QueryPerformanceCounter(&start); 

    // Put code here to time 

    LARGE_INTEGER end; 
    QueryPerformanceCounter(&end); 

    // for microseconds use 1000000.0 
    double interval = static_cast<double>(end.QuadPart- start.QuadPart)/
         frequency.QuadPart; // in seconds 
    std::cout << interval; 
} 
+0

ああ、それは正しく動作していなかったのだろうか。私は 'QueryPerformanceFrequency()'関数と実際に何をしているのかについてもっと理解したいと思います。タイマーを起動する前に必ずその関数を呼び出すか、プログラム中に一度だけ呼び出す必要がある関数ですか?周波数を正しく分割しましたか?結果は現在、数百秒で秒を出していますが、どちらも正しいとは思われません。 – raphnguyen

+0

@ graphnguyen: 'QueryPerformanceFrequency'は、周波数を取得するためにプログラム中に一度だけ呼び出されるべきです。私が示した例は '秒で' 1000000.0 'を削除したい場合は 'マイクロ秒'です。コードを秒に変更しました。 –

+0

@ graphnguyen: 'QueryPerformanceFrequency'は頻度を1秒あたりのカウント数で返します。したがって、カウント数をそれで割ると、秒が得られます。 –

5

この質問はすでに良い答えを持っている:彼らはバグを修正するまで

ので、残念ながら、高解像度のタイマーのために、あなたはそうのような直接boost::chronoまたはQueryPerformanceCounterのを使用する必要があります。しかし、別の提案を追加したいと思います。

<chrono>フレームワーク内で作業してください。あなた自身の時計を造る。独自のtime_pointを構築する。独自の期間を構築する。 <chrono>フレームワークは非常にカスタマイズ可能です。そのシステム内で作業することで、std::chronoを学ぶだけでなく、ベンダーがあなたが満足している時計の出荷を開始すると、コードをstd::high_resolution_clock(または何でも)にクロノクロール::クロックから移行するのは簡単です。

あなたの元のコードについてのマイナーな批判は、しかし最初に:あなた自身があなたが正しくchronoを使用していない、あなたが望む結果を得るために(1000000など)の変換定数を導入見るたび

std::cout << "seconds since start: " << ((double) difference/1000000); 

。あなたのコードは、壊れやすいだけではありません。 あなたはその定数にゼロの正しい数を持っていますか?

も、この単純な例では、自分自身に言う必要があります。

私はダブルで表さ秒の条件で出力を見てみたいです。

次に、chronoを使用してください。

typedef std::chrono::duration<double> sec; 
sec difference = end - start; 
std::cout << "seconds since start: " << difference.count() << '\n'; 

最初の行は、1秒の周期で2倍で表される型を作成します。

2行目はtime_pointsを減算し、それをあなたのカスタム期間タイプに割り当てます。 steady_clock::time_pointの単位からカスタム期間(2秒間)への変換は、chronoライブラリによって自動的に行われます。これは、よりはるかに簡単です:

auto difference = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() 

そして最後に、あなただけの.count()メンバ関数を使用して、結果をプリントアウト。これは、再びよりもはるかに簡単です:

std::cout << "seconds since start: " << ((double) difference/1000000); 


しかし、あなたはstd::chrono::steady_clockの精度で満足していない、とあなたはQueryPerformanceCounterのへのアクセス権を持っているので、あなたはより良い行うことができます。あなたはQueryPerformanceCounterの上に独自のクロックを構築することができます。

<disclaimer>

私は、上の次のコードをテストするには、Windowsのシステムを持っていません。

</disclaimer>

struct my_clock 
{ 
    typedef double        rep; 
    typedef std::ratio<1>      period; 
    typedef std::chrono::duration<rep, period> duration; 
    typedef std::chrono::time_point<my_clock> time_point; 
    static const bool is_steady =    false; 

    static time_point now() 
    { 
     static const long long frequency = init_frequency(); 
     long long t; 
     QueryPerformanceCounter(&t); 
     return time_point(duration(static_cast<rep>(t)/frequency)); 
    } 
private: 
    static long long init_frequency() 
    { 
     long long f; 
     QueryPerformanceFrequency(&f); 
     return f; 
    } 
}; 

あなたは二重の第二の面であなたの出力を望んでいたので、私はこのクロックのrepdoubleperiod 1秒を作りました。 repと同じように簡単に作ることができ、periodマイクロ秒やナノ秒のような他の単位を作ることもできます。 typedef秒をQueryPerformanceCounterからdurationまでnow()に調整してください。

そして今、あなたのコードは非常にあなたの元のコードのように見えることができますあなたのためのなし

int main() 
{ 
    auto start = my_clock::now(); 
    for (unsigned long long int i = 0; i < 10000; ++i) { 
     std::vector<int> v(i, 1); 
    } 
    auto end = my_clock::now(); 

    auto difference = end - start; 
    std::cout << "seconds since start: " << difference.count() << '\n'; 
} 

しかしハンドコーディング変換定数、および(私が望んでいることである)十分な精度ニーズ。また、を使用すれば、より容易にstd::chrono::steady_clockの実装への移植パスがより容易になります。

<chrono>は、伸長可能なライブラリーであるように設計された。それを拡張してください。 :-)

関連する問題