0

次のコードは、関数のランタイムとして 0 を指定します。誰でもエラーを指摘できますか?

struct timeval start,end;
long seconds,useconds;
gettimeofday(&start, NULL);
int optimalpfs=optimal(n,ref,count);
gettimeofday(&end, NULL);
seconds  = end.tv_sec  - start.tv_sec;
useconds = end.tv_usec - start.tv_usec;
long opt_runtime = ((seconds) * 1000 + useconds/1000.0) + 0.5;
cout<<"\nOptimal Runtime is "<<opt_runtime<<"\n";

開始時間と終了時間の両方を同じものとして取得します。次の出力が得られます

Optimal Runtime is 0

エラーを教えてください。

4

4 に答える 4

1

POSIX 1003.1b-1993 では、clock_gettime()(および) のインターフェイスが指定されており、MON オプションを使用すると、値がclock_getres()のクロック タイプを使用できることが示されています (タイマーがシステム時間の調整の影響を受けないようにするため)。システムで利用可能な場合、これらの関数は 1 ナノ秒までの潜在的な分解能を持つ構造体を返しますが、後者の関数はクロックの分解能を正確に示します。clockid_tCLOCK_MONOTONIC

 struct timespec {
         time_t  tv_sec;         /* seconds */
         long    tv_nsec;        /* and nanoseconds */
 };

クロックがその分解能を超えて経過した時間を記録するために、ループ内でテスト関数を何度も実行する必要があるかもしれません。時計の解像度。

ただし、どうやら Linux の人々は POSIX.1b 仕様を読み違えたり、単調に増加するタイム クロックの定義を理解していなかったりしたCLOCK_MONOTONICようです。彼らのクロックはシステム時間の調整の影響を受けるため、彼らの発明した非標準CLOCK_MONOTONIC_RAWクロックを使用して、実際の単調なタイム クロックを取得します。

別の方法として、関連する POSIX.1timer_settime()呼び出しを使用して、タイマーの実行を設定し、シグナル ハンドラーを使用してタイマーによって配信されたシグナルをキャッチし、シグナルtimer_getoverrun()のキューイングから最終的な配信までの経過時間を調べてから、タイマーが切れるまでループを実行し、設定された時間間隔内の反復回数とオーバーランをカウントします。

もちろん、プリエンプティブなマルチタスク システムでは、これらのクロックとタイマーはプロセスが実行されていないときでも実行されるため、ベンチマークにはあまり役立ちません。

わずかに珍しいのは、オプションの POSIX.1-1999clockid_t値のです。 fromCLOCK_PROCESS_CPUTIME_IDの存在によって示されます。これは、呼び出しプロセスの CPU タイム クロックを表し、呼び出しプロセスの実行時間を表す値を提供します。(さらに珍しいのは、マクロで示されるofの TCT オプションです。これは、CPU タイム クロックを表し、呼び出しスレッドの実行時間を表す値を提供します。)_POSIX_CPUTIME<time.h>clockid_tCLOCK_THREAD_CPUTIME_ID_POSIX_THREAD_CPUTIME

残念ながら、POSIX では、これらのいわゆる CPUTIME クロックがユーザー時間だけをカウントするのか、プロセスまたはスレッドによって蓄積されたユーザー時間とシステム (および割り込み) 時間の両方をカウントするのかについて言及していません。カーネル モードで費やされた時間は、表示される場合と表示されない場合があります。

さらに悪いことに、マルチプロセッサ システムでは、プロセスが実行中にある CPU から別の CPU にたまたま移行した場合、CPUTIME クロックの値が完全に偽物になる可能性があります。これらの CPUTIME クロックを実装するタイマーは、さまざまな CPU コアでさまざまな速度で実行され、さまざまな時間に実行される可能性があり、その意味がさらに複雑になります。つまり、これらは実際の壁時計時間に関連するものではなく、CPU サイクル数の指標にすぎない可能性があります (相対時間が常に使用され、ユーザーが実行時間が外的要因によって異なります)。さらに悪いことに、Linux CPU では TimeStampCounter ベースの CPUTIME クロックがプロセスがスリープした時間を報告することさえあると報告されています。

システムに適切に機能するシステム コールがある場合は、プロセスの実行中にプロセスが消費した実際のユーザー時間とシステム時間のそれぞれgetrusage()を提供できることを願っています。ただし、これによりせいぜいマイクロ秒のクロックに戻るため、より正確なタイミングを取得するには、テストコードを十分な回数繰り返し実行する必要があります。struct timevalgetrusage()ループの前に 1 回、その後にもう一度、与えられた時間の差を計算します。単純なアルゴリズムの場合、これは何百万回、またはそれ以上実行することを意味する場合があります。また、多くのシステムでは、ユーザー時間とシステム時間の分割はある程度恣意的に行われ、繰り返されるループで別々に調べると、どちらか一方が逆方向に実行されているように見えることさえあることに注意してください。ただし、アルゴリズムがシステム コールを行わない場合でも、時間デルタを合計すると、コード実行の合計時間はかなり高くなるはずです。

ところで、時間値を比較するときは、@Nim が示唆するように、またはおそらく次のように (NetBSD から<sys/time.h>)オーバーフローしたり、フィールドで負の値になったりしないように注意してください。

    #define timersub(tvp, uvp, vvp)                             \
        do {                                                    \
            (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec;      \
            (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec;   \
            if ((vvp)->tv_usec < 0) {                           \
                (vvp)->tv_sec--;                                \
                (vvp)->tv_usec += 1000000;                      \
            }                                                   \
        } while (0)

tv_usec(範囲内でもっと偏執的になりたいと思うかもしれません)

ベンチマークに関するもう 1 つの重要な注意事項: 理想的には、コンパイラからのアセンブリ出力を調べて、関数が実際に呼び出されていることを確認してください。ドライバー ループとは別のソース モジュールで関数をコンパイルすると、通常、オプティマイザーが呼び出しを保持するようになります。もう 1 つのトリックは、ループ内で として定義された変数に割り当てる値を返すようにすることですvolatile

于 2012-11-20T13:24:23.527 に答える
0

ここでは、float と int の奇妙な組み合わせがあります。

long opt_runtime = ((seconds) * 1000 + useconds/1000.0) + 0.5;

使用してみてください:

long opt_runtime = (long)(seconds * 1000 + (float)useconds/1000);

これにより、ミリ秒単位で結果が得られます。

于 2012-11-20T09:08:54.747 に答える
0

私は通常、次のような計算を行います。

long long ss = start.tv_sec * 1000000LL + start.tv_usec;
long long es = end.tv_sec * 1000000LL + end.tv_usec;

次に、違いを行います

long long microsec_diff = es - ss;

必要に応じて変換します。

double seconds = microsec_diff / 1000000.;

通常、最後のステップは気にせず、すべてのタイミングをマイクロ秒単位で行います。

于 2012-11-20T10:46:55.550 に答える
0

の実行時間はoptimal(...)、 の粒度よりも短くなっていgettimeofday(...)ます。これは Windows で発生する可能性があります。Windows では、一般的な粒度は最大 20 ミリ秒です。関連する gettimeofday(...) の質問here に回答しました。Linuxの場合、Linux gettimeofday() のマイクロ秒時間はどのように取得され、その精度はどのくらいですか? そして良い結果を得ました。

正確なタイミングを取得する方法の詳細については、このSO 回答を参照してください。

于 2012-11-20T10:42:19.387 に答える