C ++でコードスニペットの実行時間を計算する方法


121

C ++コードスニペットの実行時間を秒単位で計算する必要があります。WindowsまたはUnixマシンで動作している必要があります。

これを行うには、次のコードを使用します。(前にインポート)

clock_t startTime = clock();
// some code here
// to compute its execution duration in runtime
cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << endl;

ただし、a = a + 1などの小さな入力または短いステートメントの場合、「0秒」という結果が得られます。0.0000001秒くらいかなと思います。

System.nanoTime()この場合、Javaではうまく機能することを覚えています。しかしclock()、C ++の関数から同じ正確な機能を取得することはできません。

解決策はありますか?


29
OSがスレッドを最初から最後まで実行しない可能性があるため、時間差に基づく比較は不正確になる可能性があることに注意してください。それはそれを中断し、あなたのスレッドとインターレースされた他のスレッドを実行するかもしれません。それはあなたの操作を完了するのにかかる実際の時間に大きな影響を与えます。複数回実行して、結果の平均を取ることができます。実行中の他のプロセスの数を最小限に抑えることができます。しかし、これらのどれもスレッドの停止効果を完全に排除しません。
モルダチャイ2009

14
モルダチ、なぜそれを排除したいのですか?スレッドが中断されることのない魔法の領域ではなく、実際の環境で関数がどのように機能するかを確認する必要があります。数回実行して平均を作成する限り、非常に正確です。
Thomas Bonini、

はい私はそれを数回実行し、結果を平均します。
AhmetB-Google

14
アンドレアス、モルダチャイのコメントは、OPが彼のコードのパフォーマンスを別のアルゴリズムと比較したい場合に関連しています。たとえば、彼が今日の午後にいくつかのクロックテストを実行してから、明日の朝に別のアルゴリズムをテストする場合、午前中よりも午後に多くのプロセスとリソースを共有している可能性があるため、彼の比較は信頼できない可能性があります。または、1つのコードセットにより、OSが処理時間を短縮できる場合があります。彼が時間ベースの比較を実行したい場合、このタイプのパフォーマンス測定が信頼できない理由は数多くあります。
weberc2 2012

4
@Mordachai私は古いコメントに返信していることを知っていますが、私がそうしたようにこれにつまずく人のために-アルゴリズムのパフォーマンスを時間どおりに測定するには、平均ではなく、最低限数回実行する必要があります。これは、OSによる中断が最も少なかったものであり、ほとんどの場合、コードのタイミングを計ります。
Baruch、

回答:


115

私が書いたこの関数を使用できます。を呼び出すGetTimeMs64()と、Unixエポックからシステムクロックを使用して経過したミリ秒数が返されます- time(NULL)ミリ秒を除いてと同じです。

WindowsとLinuxの両方で動作します。スレッドセーフです。

Windowsでは粒度が15ミリ秒であることに注意してください。Linuxでは、実装に依存しますが、通常は15ミリ秒です。

#ifdef _WIN32
#include <Windows.h>
#else
#include <sys/time.h>
#include <ctime>
#endif

/* Remove if already defined */
typedef long long int64; typedef unsigned long long uint64;

/* Returns the amount of milliseconds elapsed since the UNIX epoch. Works on both
 * windows and linux. */

uint64 GetTimeMs64()
{
#ifdef _WIN32
 /* Windows */
 FILETIME ft;
 LARGE_INTEGER li;

 /* Get the amount of 100 nano seconds intervals elapsed since January 1, 1601 (UTC) and copy it
  * to a LARGE_INTEGER structure. */
 GetSystemTimeAsFileTime(&ft);
 li.LowPart = ft.dwLowDateTime;
 li.HighPart = ft.dwHighDateTime;

 uint64 ret = li.QuadPart;
 ret -= 116444736000000000LL; /* Convert from file time to UNIX epoch time. */
 ret /= 10000; /* From 100 nano seconds (10^-7) to 1 millisecond (10^-3) intervals */

 return ret;
#else
 /* Linux */
 struct timeval tv;

 gettimeofday(&tv, NULL);

 uint64 ret = tv.tv_usec;
 /* Convert from micro seconds (10^-6) to milliseconds (10^-3) */
 ret /= 1000;

 /* Adds the seconds (10^0) after converting them to milliseconds (10^-3) */
 ret += (tv.tv_sec * 1000);

 return ret;
#endif
}

1
将来の参考のために、私はそれをヘッダーファイルに入れて使用します。それを持ってうれしい。
Daniel Handojo 2016

1
gettimeofdayシステムクロックが変更された場合、この方法では意図しない結果が生じる可能性があると思います。これが問題になる場合は、clock_gettime代わりに確認することをお勧めします。
Azmisov 2016年

このWindowsの方法には、何か利点がありGetTickCountますか?
マイクロウイルス

を使用してコンパイルしないgcc -std=c99
Assimilater

@MicroVirus:はい、GetTickCountシステムが起動してからの経過時間ですが、私の関数はUNIXエポックからの時間を返します。つまり、日付と時刻に使用できます。2つのイベント間の経過時間のみに関心がある場合、それはint64であるため、鉱山を選択することをお勧めします。GetTickCountはint32であり、50日ごとにオーバーフローします。つまり、登録した2つのイベントがオーバーフローの間にある場合、奇妙な結果が得られる可能性があります。
Thomas Bonini、

43

マイクロ秒を使用する別の実用的な例(UNIX、POSIXなど)があります。

    #include <sys/time.h>
    typedef unsigned long long timestamp_t;

    static timestamp_t
    get_timestamp ()
    {
      struct timeval now;
      gettimeofday (&now, NULL);
      return  now.tv_usec + (timestamp_t)now.tv_sec * 1000000;
    }

    ...
    timestamp_t t0 = get_timestamp();
    // Process
    timestamp_t t1 = get_timestamp();

    double secs = (t1 - t0) / 1000000.0L;

これをコーディングしたファイルは次のとおりです。

https://github.com/arhuaco/junkcode/blob/master/emqbit-bench/bench.c


5
#include <sys/time.h>例の最初に追加する必要があります。
niekas

40

これは満足のいく解像度を与えるC ++ 11の簡単な解決策です。

#include <iostream>
#include <chrono>

class Timer
{
public:
    Timer() : beg_(clock_::now()) {}
    void reset() { beg_ = clock_::now(); }
    double elapsed() const { 
        return std::chrono::duration_cast<second_>
            (clock_::now() - beg_).count(); }

private:
    typedef std::chrono::high_resolution_clock clock_;
    typedef std::chrono::duration<double, std::ratio<1> > second_;
    std::chrono::time_point<clock_> beg_;
};

または* nixで、c ++ 03の場合

#include <iostream>
#include <ctime>

class Timer
{
public:
    Timer() { clock_gettime(CLOCK_REALTIME, &beg_); }

    double elapsed() {
        clock_gettime(CLOCK_REALTIME, &end_);
        return end_.tv_sec - beg_.tv_sec +
            (end_.tv_nsec - beg_.tv_nsec) / 1000000000.;
    }

    void reset() { clock_gettime(CLOCK_REALTIME, &beg_); }

private:
    timespec beg_, end_;
};

次に使用例を示します。

int main()
{
    Timer tmr;
    double t = tmr.elapsed();
    std::cout << t << std::endl;

    tmr.reset();
    t = tmr.elapsed();
    std::cout << t << std::endl;

    return 0;
}

https://gist.github.com/gongzhitaao/7062087から


:私はあなたのC ++ 11溶液を用いて、このエラー取得しています/usr/lib/x86_64-linux-gnu/libstdc++.so.6: version GLIBCXX_3.4.19 not found (required by ../cpu_2d/g500)
user9869932

@julianromeraどのプラットフォームを使用していますか?libstdc ++ライブラリとg ++をインストールしましたか?
gongzhitaao 2015

Linux ubuntu 12のSlurmグリッドです。修正しました。リンカーの最後に-static-libstdc ++を追加しました。お礼を@gongzhitaaoを尋ねるために
user9869932

18
#include <boost/progress.hpp>

using namespace boost;

int main (int argc, const char * argv[])
{
  progress_timer timer;

  // do stuff, preferably in a 100x loop to make it take longer.

  return 0;
}

ときにprogress_timerスコープ外に出ることは、その作成からの経過時間を出力します。

更新:これはBoostなしで動作するバージョンです(macOS / iOSでテスト済み):

#include <chrono>
#include <string>
#include <iostream>
#include <math.h>
#include <unistd.h>

class NLTimerScoped {
private:
    const std::chrono::steady_clock::time_point start;
    const std::string name;

public:
    NLTimerScoped( const std::string & name ) : name( name ), start( std::chrono::steady_clock::now() ) {
    }


    ~NLTimerScoped() {
        const auto end(std::chrono::steady_clock::now());
        const auto duration_ms = std::chrono::duration_cast<std::chrono::milliseconds>( end - start ).count();

        std::cout << name << " duration: " << duration_ms << "ms" << std::endl;
    }

};

int main(int argc, const char * argv[]) {

    {
        NLTimerScoped timer( "sin sum" );

        float a = 0.0f;

        for ( int i=0; i < 1000000; i++ ) {
            a += sin( (float) i / 100 );
        }

        std::cout << "sin sum = " << a << std::endl;
    }



    {
        NLTimerScoped timer( "sleep( 4 )" );

        sleep( 4 );
    }



    return 0;
}

2
これは機能しますが、progress_timerは非推奨になっていることに注意してください(boost 1.50より前のいつか)-auto_cpu_timerの方が適切な場合があります。
davidA 2012

3
@meowsqueakうーん、auto_cpu_timerはBoostシステムライブラリをリンクする必要があるため、ヘッダーのみのソリューションではなくなりました。残念すぎる...他のオプションが突然魅力的になります。
Tomas Andrle 2012

1
はい、それは良い点です。まだBoostをリンクしていない場合、それは価値があるよりもトラブルになります。しかし、すでに実行している場合は、非常にうまく機能します。
davidA

@meowsqueakええ、またはいくつかの簡単なベンチマークテストでは、古いバージョンのBoostを入手してください。
Tomas Andrle 2013年

@TomasAndrleリンクは存在しません。
正月

5

WindowsにはQueryPerformanceCounter()関数があり、Unixにはgettimeofday()があります。どちらの関数も少なくとも1マイクロ秒の差を測定できます。


ただし、windows.hの使用は制限されています。同じコンパイル済みソースをWindowsとUnixの両方で実行する必要があります。この問題の処理方法は?
AhmetB-Google

2
そして、いくつかのラッパー・ライブラリーを探しstackoverflow.com/questions/1487695/...
キャプテンコミック

4
同じコンパイル済みソースは、両方のシステムで同じバイナリを実行したいように聞こえますが、そうではないようです。同じ情報源を意味する場合は#ifdef大丈夫である必要があり(そして、あなたが受け入れた回答から判断すると)、問題は発生しません#ifdef WIN32 #include <windows.h> ... #else ... #endif
2010

3

一部のプログラムでは、そのような目的でRDTSを使用しました。RDTSCは時間ではなく、プロセッサの開始からのサイクル数です。秒単位で結果を得るには、システムで調整する必要がありますが、パフォーマンスを評価する場合は非常に便利です。サイクル数を秒に戻そうとせずに、サイクル数を直接使用することをお勧めします。

(上記のリンクはフランスのウィキペディアのページですが、C ++コードサンプルがあり、英語版はこちらです


2

システムから時間情報を取得するには、標準ライブラリ関数を使用することをお勧めします。

より細かい解像度が必要な場合は、より多くの反復を実行します。プログラムを1回実行してサンプルを取得する代わりに、1000回以上実行します。


2

全体(ループ+パフォーマンスタイミング)を数回実行して平均化するよりも、パフォーマンスタイミングを1回だけ使用して内部ループを数回実行し、内部ループの繰り返しを分割して平均化する方が適切です。これにより、実際のプロファイルセクションに対してパフォーマンスタイミングコードのオーバーヘッドが削減されます。

適切なシステムのタイマー呼び出しをラップします。Windowsの場合、QueryPerformanceCounterはかなり高速で、「安全」に使用できます。

最新のX86 PCでも "rdtsc"を使用できますが、一部のマルチコアマシン(コアホッピングによりタイマーが変更される可能性があります)で問題が発生したり、何らかの速度ステップがオンになっている場合があります。


2

(Windows固有のソリューション)Windowsで正確なタイミングを取得する現在(2017年頃)の方法は、「QueryPerformanceCounter」を使用することです。このアプローチには、非常に正確な結果が得られるという利点があり、MSによって推奨されています。コードblobを新しいコンソールアプリに配置するだけで、実用的なサンプルを取得できます。ここで長い議論があります:高解像度タイムスタンプの取得

#include <iostream>
#include <tchar.h>
#include <windows.h>

int main()
{
constexpr int MAX_ITER{ 10000 };
constexpr __int64 us_per_hour{ 3600000000ull }; // 3.6e+09
constexpr __int64 us_per_min{ 60000000ull };
constexpr __int64 us_per_sec{ 1000000ull };
constexpr __int64 us_per_ms{ 1000ull };

// easy to work with
__int64 startTick, endTick, ticksPerSecond, totalTicks = 0ull;

QueryPerformanceFrequency((LARGE_INTEGER *)&ticksPerSecond);

for (int iter = 0; iter < MAX_ITER; ++iter) {// start looping
    QueryPerformanceCounter((LARGE_INTEGER *)&startTick); // Get start tick
    // code to be timed
    std::cout << "cur_tick = " << iter << "\n";
    QueryPerformanceCounter((LARGE_INTEGER *)&endTick); // Get end tick
    totalTicks += endTick - startTick; // accumulate time taken
}

// convert to elapsed microseconds
__int64 totalMicroSeconds =  (totalTicks * 1000000ull)/ ticksPerSecond;

__int64 hours = totalMicroSeconds / us_per_hour;
totalMicroSeconds %= us_per_hour;
__int64 minutes = totalMicroSeconds / us_per_min;
totalMicroSeconds %= us_per_min;
__int64 seconds = totalMicroSeconds / us_per_sec;
totalMicroSeconds %= us_per_sec;
__int64 milliseconds = totalMicroSeconds / us_per_ms;
totalMicroSeconds %= us_per_ms;


std::cout << "Total time: " << hours << "h ";
std::cout << minutes << "m " << seconds << "s " << milliseconds << "ms ";
std::cout << totalMicroSeconds << "us\n";

return 0;
}

2

スレッドスケジューリングの完全な解決策は、各テストで正確に同じ時間になるはずですが、プログラムをOSに依存しないようにコンパイルし、コンピューターを起動して、OSのない環境でプログラムを実行することです。しかし、これはほとんど非現実的であり、せいぜい困難です。

OSフリー化の良い代替策は、現在のスレッドのアフィニティを1コアに設定し、優先度を最高に設定することです。この代替手段は、一貫した十分な結果を提供するはずです。

また、デバッグを妨げる最適化をオフにする必要があります。これは、g ++またはgccの場合、コマンドラインに追加-Ogすること意味し、テストされるコードが最適化されないようにします。-O0それはこのようにコードの時限速度をスキュー、タイミング結果に含まれることになる余分な不要なオーバーヘッドを導入するためのフラグを使用すべきではありません。

逆に、最終的な製品ビルド-Ofastで使用する(または少なくとも-O3)ことを前提とし、「デッド」コードの除去の問題を無視する場合、どちらもに-Og比べて最適化をほとんど実行しません-Ofast。したがって-Og、最終製品のコードの実際の速度を誤って表す可能性があります。

さらに、すべての速度テストは(ある程度)偽証します:でコンパイルされた最終的な製品で-Ofastは、コードの各スニペット/セクション/関数は分離されません。むしろ、コードの各スニペットは継続的に次のスニペットに流れ込むため、コンパイラーはあらゆる場所からコードの断片を結合、マージ、および最適化することができます。

同時に、を頻繁に使用するコードスニペットをベンチマークしている場合realloc()、十分なメモリの断片化が発生している製品では、コードスニペットの実行が遅くなる可能性があります。したがって、「全体はその部分の合計よりも大きい」という表現がこの状況に適用されます。最終的な製品ビルドのコードは、速度テストしている個々のスニペットよりも著しく速くまたは遅く実行される可能性があるためです。

不整合を減らす可能性のある部分的な解決策は、デッドコード/ループの除去を防ぐためのテストに含まれる変数への-Ofast追加をasm volatile("" :: "r"(var))伴う速度テストに使用することです。

これは、Windowsコンピューターで平方根関数をベンチマークする方法の例です。

// set USE_ASM_TO_PREVENT_ELIMINATION  to 0 to prevent `asm volatile("" :: "r"(var))`
// set USE_ASM_TO_PREVENT_ELIMINATION  to 1 to enforce `asm volatile("" :: "r"(var))`
#define USE_ASM_TO_PREVENT_ELIMINATION 1

#include <iostream>
#include <iomanip>
#include <cstdio>
#include <chrono>
#include <cmath>
#include <windows.h>
#include <intrin.h>
#pragma intrinsic(__rdtsc)
#include <cstdint>

class Timer {
public:
    Timer() : beg_(clock_::now()) {}
    void reset() { beg_ = clock_::now(); }
    double elapsed() const { 
        return std::chrono::duration_cast<second_>
            (clock_::now() - beg_).count(); }
private:
    typedef std::chrono::high_resolution_clock clock_;
    typedef std::chrono::duration<double, std::ratio<1> > second_;
    std::chrono::time_point<clock_> beg_;
};

unsigned int guess_sqrt32(register unsigned int n) {
    register unsigned int g = 0x8000;
    if(g*g > n) {
        g ^= 0x8000;
    }
    g |= 0x4000;
    if(g*g > n) {
        g ^= 0x4000;
    }
    g |= 0x2000;
    if(g*g > n) {
        g ^= 0x2000;
    }
    g |= 0x1000;
    if(g*g > n) {
        g ^= 0x1000;
    }
    g |= 0x0800;
    if(g*g > n) {
        g ^= 0x0800;
    }
    g |= 0x0400;
    if(g*g > n) {
        g ^= 0x0400;
    }
    g |= 0x0200;
    if(g*g > n) {
        g ^= 0x0200;
    }
    g |= 0x0100;
    if(g*g > n) {
        g ^= 0x0100;
    }
    g |= 0x0080;
    if(g*g > n) {
        g ^= 0x0080;
    }
    g |= 0x0040;
    if(g*g > n) {
        g ^= 0x0040;
    }
    g |= 0x0020;
    if(g*g > n) {
        g ^= 0x0020;
    }
    g |= 0x0010;
    if(g*g > n) {
        g ^= 0x0010;
    }
    g |= 0x0008;
    if(g*g > n) {
        g ^= 0x0008;
    }
    g |= 0x0004;
    if(g*g > n) {
        g ^= 0x0004;
    }
    g |= 0x0002;
    if(g*g > n) {
        g ^= 0x0002;
    }
    g |= 0x0001;
    if(g*g > n) {
        g ^= 0x0001;
    }
    return g;
}

unsigned int empty_function( unsigned int _input ) {
    return _input;
}

unsigned long long empty_ticks=0;
double empty_seconds=0;
Timer my_time;

template<unsigned int benchmark_repetitions>
void benchmark( char* function_name, auto (*function_to_do)( auto ) ) {
    register unsigned int i=benchmark_repetitions;
    register unsigned long long start=0;
    my_time.reset();
    start=__rdtsc();
    while ( i-- ) {
        auto result = (*function_to_do)( i << 7 );
        #if USE_ASM_TO_PREVENT_ELIMINATION == 1
            asm volatile("" :: "r"(
                // There is no data type in C++ that is smaller than a char, so it will
                //  not throw a segmentation fault error to reinterpret any arbitrary
                //  data type as a char. Although, the compiler might not like it.
                result
            ));
        #endif
    }
    if ( function_name == nullptr ) {
        empty_ticks = (__rdtsc()-start);
        empty_seconds = my_time.elapsed();
        std::cout<< "Empty:\n" << empty_ticks
              << " ticks\n" << benchmark_repetitions << " repetitions\n"
               << std::setprecision(15) << empty_seconds
                << " seconds\n\n";
    } else {
        std::cout<< function_name<<":\n" << (__rdtsc()-start-empty_ticks)
              << " ticks\n" << benchmark_repetitions << " repetitions\n"
               << std::setprecision(15) << (my_time.elapsed()-empty_seconds)
                << " seconds\n\n";
    }
}


int main( void ) {
    void* Cur_Thread=   GetCurrentThread();
    void* Cur_Process=  GetCurrentProcess();
    unsigned long long  Current_Affinity;
    unsigned long long  System_Affinity;
    unsigned long long furthest_affinity;
    unsigned long long nearest_affinity;

    if( ! SetThreadPriority(Cur_Thread,THREAD_PRIORITY_TIME_CRITICAL) ) {
        SetThreadPriority( Cur_Thread, THREAD_PRIORITY_HIGHEST );
    }
    if( ! SetPriorityClass(Cur_Process,REALTIME_PRIORITY_CLASS) ) {
        SetPriorityClass( Cur_Process, HIGH_PRIORITY_CLASS );
    }
    GetProcessAffinityMask( Cur_Process, &Current_Affinity, &System_Affinity );
    furthest_affinity = 0x8000000000000000ULL>>__builtin_clzll(Current_Affinity);
    nearest_affinity  = 0x0000000000000001ULL<<__builtin_ctzll(Current_Affinity);
    SetProcessAffinityMask( Cur_Process, furthest_affinity );
    SetThreadAffinityMask( Cur_Thread, furthest_affinity );

    const int repetitions=524288;

    benchmark<repetitions>( nullptr, empty_function );
    benchmark<repetitions>( "Standard Square Root", standard_sqrt );
    benchmark<repetitions>( "Original Guess Square Root", original_guess_sqrt32 );
    benchmark<repetitions>( "New Guess Square Root", new_guess_sqrt32 );


    SetThreadPriority( Cur_Thread, THREAD_PRIORITY_IDLE );
    SetPriorityClass( Cur_Process, IDLE_PRIORITY_CLASS );
    SetProcessAffinityMask( Cur_Process, nearest_affinity );
    SetThreadAffinityMask( Cur_Thread, nearest_affinity );
    for (;;) { getchar(); }

    return 0;
}

また、タイマーについてはマイクジャービスの功績です。

より大きなコードスニペットを実行する場合は、コンピューターがフリーズしないように、反復回数を実際に減らす必要があることに注意してください(これは非常に重要です)。


2
最適化を無効にすることを除いて、良い答えです。ベンチマーク-O0コードは時間の大きな浪費であるためのオーバーヘッド-O0 の代わりに通常の-O2又は-O3 -march=native異なる乱暴コードとワークロードに応じ。たとえば、追加の名前付きtmp変数は、に時間がかかります-O0。オプティマイザからvolatile、非インライン関数、または空のインラインasmステートメントで物事を隠すなど、物事を最適化しないようにする他の方法があります。 -O0コードのボトルネックは異なり-O0、同じではありませんが悪化しているため、使用可能に近いとは言えません。
Peter Cordes

1
ええと、-Ogコードによっては、まだあまり現実的ではありません。少なくとも-O2-O3より現実的です。asm volatile("" ::: "+r"(var))または何かを使用して、コンパイラーにレジスター内の値を具体化させ、それによる定数伝搬を無効にします。
Peter Cordes

@PeterCordes洞察をありがとうございます。でコンテンツを-O3、でコードスニペットを更新しましたasm volatile("" ::: "+r"(var))
ジャックギフィン

1
asm volatile("" ::: "+r"( i ));不要のようです。最適化されたコードでは、コンパイラーにループ内iだけでなく実体化を強制する理由はありませんi<<7tmp -= 128毎回シフトするのではなく、最適化を停止します。ただし、関数呼び出しの結果を使用するのは、それがでない場合は適切voidです。のようにint result = (*function_to_do)( i << 7 );asmその結果についてステートメントを使用できます。
Peter Cordes

@PeterCordesありがとうございました。私のポストは今から戻り値の修正が含まれていますfunction_to_doので、function_to_do排除されずにインライン化することができます。他にご提案がございましたらお知らせください。
ジャックギフィン

1

実行されるたびに同じコードの時間を計測したい場合(たとえば、ボトルネックになっていると思われるプロファイリングコードの場合)に、Andreas Boniniの便利な関数のラッパー(わずかな変更)があります。

#ifdef _WIN32
#include <Windows.h>
#else
#include <sys/time.h>
#endif

/*
 *  A simple timer class to see how long a piece of code takes. 
 *  Usage:
 *
 *  {
 *      static Timer timer("name");
 *
 *      ...
 *
 *      timer.start()
 *      [ The code you want timed ]
 *      timer.stop()
 *
 *      ...
 *  }
 *
 *  At the end of execution, you will get output:
 *
 *  Time for name: XXX seconds
 */
class Timer
{
public:
    Timer(std::string name, bool start_running=false) : 
        _name(name), _accum(0), _running(false)
    {
        if (start_running) start();
    }

    ~Timer() { stop(); report(); }

    void start() {
        if (!_running) {
            _start_time = GetTimeMicroseconds();
            _running = true;
        }
    }
    void stop() {
        if (_running) {
            unsigned long long stop_time = GetTimeMicroseconds();
            _accum += stop_time - _start_time;
            _running = false;
        }
    }
    void report() { 
        std::cout<<"Time for "<<_name<<": " << _accum / 1.e6 << " seconds\n"; 
    }
private:
    // cf. http://stackoverflow.com/questions/1861294/how-to-calculate-execution-time-of-a-code-snippet-in-c
    unsigned long long GetTimeMicroseconds()
    {
#ifdef _WIN32
        /* Windows */
        FILETIME ft;
        LARGE_INTEGER li;

        /* Get the amount of 100 nano seconds intervals elapsed since January 1, 1601 (UTC) and copy it
         *   * to a LARGE_INTEGER structure. */
        GetSystemTimeAsFileTime(&ft);
        li.LowPart = ft.dwLowDateTime;
        li.HighPart = ft.dwHighDateTime;

        unsigned long long ret = li.QuadPart;
        ret -= 116444736000000000LL; /* Convert from file time to UNIX epoch time. */
        ret /= 10; /* From 100 nano seconds (10^-7) to 1 microsecond (10^-6) intervals */
#else
        /* Linux */
        struct timeval tv;

        gettimeofday(&tv, NULL);

        unsigned long long ret = tv.tv_usec;
        /* Adds the seconds (10^0) after converting them to microseconds (10^-6) */
        ret += (tv.tv_sec * 1000000);
#endif
        return ret;
    }
    std::string _name;
    long long _accum;
    unsigned long long _start_time;
    bool _running;
};

1

コードブロックをベンチマークする単純なクラス:

using namespace std::chrono;

class benchmark {
  public:
  time_point<high_resolution_clock>  t0, t1;
  unsigned int *d;
  benchmark(unsigned int *res) : d(res) { 
                 t0 = high_resolution_clock::now();
  }
  ~benchmark() { t1 = high_resolution_clock::now();
                  milliseconds dur = duration_cast<milliseconds>(t1 - t0);
                  *d = dur.count();
  }
};
// simple usage 
// unsigned int t;
// { // put the code in a block
//  benchmark bench(&t);
//  // ...
//  // code to benchmark
// }
// HERE the t contains time in milliseconds

// one way to use it can be :
#define BENCH(TITLE,CODEBLOCK) \
  unsigned int __time__##__LINE__ = 0;  \
  { benchmark bench(&__time__##__LINE__); \
      CODEBLOCK \
  } \
  printf("%s took %d ms\n",(TITLE),__time__##__LINE__);


int main(void) {
  BENCH("TITLE",{
    for(int n = 0; n < testcount; n++ )
      int a = n % 3;
  });
  return 0;
}

0

boost :: timerはおそらく必要なだけの精度を与えるでしょう。どれほど時間a = a+1;がかかるかを説明するのに十分正確ではありませんが、数ナノ秒かかるような時間を計らなければならない理由は何ですか?


これはclock()、C ++標準ヘッダーの関数に依存しています。
ペッター

0

関数呼び出しをN回呼び出して平均を返すラムダを作成しました。

double c = BENCHMARK_CNT(25, fillVectorDeque(variable));

ここに c ++ 11ヘッダーがあります


0

私は、クロノライブラリのhigh_resolution_clockを使用して、コードブロックのパフォーマンスを測定するシンプルなユーティリティを作成しました:https : //github.com/nfergu/codetimer

異なるキーに対してタイミングを記録でき、各キーのタイミングの集約ビューを表示できます。

使用法は次のとおりです。

#include <chrono>
#include <iostream>
#include "codetimer.h"

int main () {
    auto start = std::chrono::high_resolution_clock::now();
    // some code here
    CodeTimer::record("mykey", start);
    CodeTimer::printStats();
    return 0;
}

0

[cxx-rtimers][1]ローカル変数を作成できるコードブロックのランタイムに関する統計を収集するためのいくつかのヘッダーのみのルーチンを提供するGitHubでを確認することもできます。これらのタイマーには、C ++ 11でstd :: chronoを使用するバージョン、またはBoostライブラリのタイマー、または標準のPOSIXタイマー関数があります。これらのタイマーは、関数内で費やされた平均時間、最大時間、最小時間、および関数が呼び出された回数を報告します。次のように簡単に使用できます。

#include <rtimers/cxx11.hpp>

void expensiveFunction() {
    static rtimers::cxx11::DefaultTimer timer("expensive");
    auto scopedStartStop = timer.scopedStart();
    // Do something costly...
}

0

それは私がそれをする方法です、あまりコードではなく、理解しやすく、私のニーズに合います:

void bench(std::function<void()> fnBench, std::string name, size_t iterations)
{
    if (iterations == 0)
        return;
    if (fnBench == nullptr)
        return;
    std::chrono::high_resolution_clock::time_point start, end;
    if (iterations == 1)
    {
        start = std::chrono::high_resolution_clock::now();
        fnBench();
        end = std::chrono::high_resolution_clock::now();
    }
    else
    {
        start = std::chrono::high_resolution_clock::now();
        for (size_t i = 0; i < iterations; ++i)
            fnBench();
        end = std::chrono::high_resolution_clock::now();
    }
    printf
    (
        "bench(*, \"%s\", %u) = %4.6lfs\r\n",
        name.c_str(),
        iterations,
        std::chrono::duration_cast<std::chrono::duration<double>>(end - start).count()
    );
}

使用法:

bench
(
    []() -> void // function
    {
        // Put your code here
    },
    "the name of this", // name
    1000000 // iterations
);

0
#include <omp.h>

double start = omp_get_wtime();

// code 

double finish = omp_get_wtime();

double total_time = finish - start;

2
このコードは問題を解決する可能性がありますが、これが問題を解決する方法と理由の説明含めると、投稿の品質が向上し、おそらく投票数が増えることになります。あなたが今尋ねている人だけでなく、あなたが将来の読者のための質問に答えていることを忘れないでください。回答を編集して説明を追加し、適用される制限と前提を示してください。
ダーマン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.