104

もともとWin32API用に作成されたゲームをLinuxに移植しています(Win32ポートのOS XポートをLinuxに移植しています)。

QueryPerformanceCounterプロセスの開始以来、uSecondsを指定し て実装しました。

BOOL QueryPerformanceCounter(LARGE_INTEGER* performanceCount)
{
    gettimeofday(&currentTimeVal, NULL);
    performanceCount->QuadPart = (currentTimeVal.tv_sec - startTimeVal.tv_sec);
    performanceCount->QuadPart *= (1000 * 1000);
    performanceCount->QuadPart += (currentTimeVal.tv_usec - startTimeVal.tv_usec);

    return true;
}

これは、周波数として定数1000000を与えることと相まって、私のマシンQueryPerformanceFrequency()でうまく機能し、プログラムの起動以降に含まれる64ビット変数を与えてくれます。uSeconds

それで、これはポータブルですか?カーネルが特定の方法でコンパイルされた場合など、動作が異なることを知りたくありません。ただし、Linux以外には移植できないので問題ありません。

4

10 に答える 10

61

多分。しかし、あなたにはもっと大きな問題があります。gettimeofday()システムにタイマーを変更するプロセス(つまり、ntpd)がある場合、タイミングが正しくなくなる可能性があります。ただし、「通常の」Linuxでは、の解像度gettimeofday()は10usだと思います。その結果、システムで実行されているプロセスに基づいて、前後および時間にジャンプする可能性があります。これは事実上あなたの質問への答えをノーにします。

clock_gettime(CLOCK_MONOTONIC)タイミング間隔を調べる必要があります。マルチコアシステムや外部クロック設定などにより、いくつかの問題が少なくなります。

また、clock_getres()関数を調べてください。

于 2008-08-01T14:53:47.497 に答える
43

Intel プロセッサー向けの高解像度、低オーバーヘッドのタイミング

Intel ハードウェアを使用している場合、CPU リアルタイム命令カウンターを読み取る方法は次のとおりです。プロセッサが起動してから実行された CPU サイクルの数がわかります。これはおそらく、パフォーマンス測定用に取得できる最も細かいカウンターです。

これは CPU サイクルの数であることに注意してください。Linux では、/proc/cpuinfo から CPU 速度を取得し、除算して秒数を取得できます。これを double に変換すると非常に便利です。

これを自分のボックスで実行すると、

11867927879484732
11867927879692217
it took this long to call printf: 207485

これは、大量の詳細を提供するIntel 開発者ガイドです。

#include <stdio.h>
#include <stdint.h>

inline uint64_t rdtsc() {
    uint32_t lo, hi;
    __asm__ __volatile__ (
      "xorl %%eax, %%eax\n"
      "cpuid\n"
      "rdtsc\n"
      : "=a" (lo), "=d" (hi)
      :
      : "%ebx", "%ecx");
    return (uint64_t)hi << 32 | lo;
}

main()
{
    unsigned long long x;
    unsigned long long y;
    x = rdtsc();
    printf("%lld\n",x);
    y = rdtsc();
    printf("%lld\n",y);
    printf("it took this long to call printf: %lld\n",y-x);
}
于 2008-08-02T08:08:22.230 に答える
18

@バーナード:

認めざるを得ませんが、あなたの例のほとんどは頭から離れませんでした。ただし、コンパイルは実行され、動作するようです。これは SMP システムまたは SpeedStep に対して安全ですか?

それは良い質問です...コードは大丈夫だと思います。実用的な観点から、私たちは毎日それを私の会社で使用しており、2 コアから 8 コアまでの非常に幅広いボックスで実行しています。もちろん、YMMV などですが、信頼性が高く、オーバーヘッドが少ない (システム空間へのコンテキスト スイッチを行わないため) タイミングの方法のようです。

一般的に、その仕組みは次のとおりです。

  • コードのブロックをアセンブラーとして宣言します (揮発性であるため、オプティマイザーはそれをそのままにします)。
  • CPUID 命令を実行します。一部の CPU 情報を取得することに加えて (これについては何もしません)、タイミングが順不同の実行の影響を受けないように、CPU の実行バッファーを同期します。
  • rdtsc (タイムスタンプの読み取り) 実行を実行します。これは、プロセッサがリセットされてから実行されたマシン サイクルの数をフェッチします。これは 64 ビット値であるため、現在の CPU 速度では約 194 年ごとにラップアラウンドします。興味深いことに、元の Pentium リファレンスでは、約 5800 年ごとにラップアラウンドしていることに注目しています。
  • 最後の数行は、レジスタからの値を変数 hi と lo に格納し、それを 64 ビットの戻り値に入れます。

特定のメモ:

  • 順不同の実行は誤った結果を引き起こす可能性があるため、「cpuid」命令を実行します。これは、CPU に関する情報を提供するだけでなく、順不同の命令実行を同期します。

  • ほとんどの OS は、起動時に CPU のカウンターを同期するため、答えは数ナノ秒以内です。

  • 冬眠のコメントはおそらく正しいですが、実際には、冬眠の境界を越えたタイミングは気にしないでしょう。

  • speedstep について: 新しい Intel CPU は速度の変化を補正し、調整されたカウントを返します。ネットワーク上のいくつかのボックスを簡単にスキャンしたところ、1 つのボックスだけが見つかりました。それは、古いデータベース サーバーを実行している Pentium 3 です。(これらは Linux ボックスなので、grep constant_tsc /proc/cpuinfo で確認しました)

  • AMD CPU についてはよくわかりません。私たちは主に Intel ショップですが、低レベルのシステムの専門家の何人かが AMD の評価を行ったことは知っています。

これがあなたの好奇心を満たしてくれることを願っています。これは興味深く、(IMHO) 十分に研究されていないプログラミング領域です。Jeff と Joel が、プログラマーが C を知っているべきかどうかについて話していたのを知っていますか? 私は彼らに叫んでいました。

于 2008-08-04T00:51:52.843 に答える
14

Linux FAQ に興味があるかもしれませんclock_gettime(CLOCK_REALTIME)

于 2008-08-18T15:51:01.877 に答える
11

Wine は実際に gettimeofday() を使用して QueryPerformanceCounter() を実装しており、多くの Windows ゲームを Linux および Mac で動作させることが知られています。

http://source.winehq.org/source/dlls/kernel32/cpu.c#L312を開始します

http://source.winehq.org/source/dlls/ntdll/time.c#L448につながります

于 2008-08-04T14:44:56.950 に答える
9

gettimeofday()の実際の解像度は、ハードウェアアーキテクチャによって異なります。IntelプロセッサとSPARCマシンは、マイクロ秒を測定する高解像度タイマーを提供します。他のハードウェアアーキテクチャは、システムのタイマーにフォールバックします。タイマーは通常100Hzに設定されています。このような場合、時間分解能は精度が低くなります。

この回答は、高解像度時間測定とタイマー、パートIから取得しました。

于 2008-08-01T14:55:08.477 に答える
9

したがって、明示的にマイクロ秒と表示されていますが、システム クロックの分解能は指定されていません。このコンテキストでの解決とは、これまでに増分される最小量を意味すると思いますか?

データ構造は測定単位としてマイクロ秒を持つように定義されていますが、それはクロックまたはオペレーティング システムが実際にそれを細かく測定できることを意味しません。

他の人が示唆しているようにgettimeofday()、時間を設定するとクロックのずれが発生し、計算が狂う可能性があるため、悪いです。 clock_gettime(CLOCK_MONOTONIC)あなたが望むものでありclock_getres()、あなたの時計の精度を教えてくれます。

于 2008-08-02T17:57:06.033 に答える
6

この答えは、調整されている時計の問題に言及しています。ティック単位を保証する問題と調整される時間の問題の両方が、<chrono>ライブラリを使用したC++11で解決されます。

時計std::chrono::steady_clockは調整されないことが保証されており、さらにリアルタイムに対して一定の速度で進むため、SpeedStepなどのテクノロジーが時計に影響を与えてはなりません。

std::chrono::durationタイプセーフな単位は、などの特殊化の1つに変換することで取得できますstd::chrono::microseconds。このタイプでは、ティック値によって使用される単位についてあいまいさはありません。ただし、時計が必ずしもこの解像度であるとは限らないことに注意してください。実際に正確な時計がなくても、継続時間をアト秒に変換できます。

于 2012-06-26T15:57:14.370 に答える
4

私の経験から、そして私がインターネットで読んだことから、答えは「いいえ」です、それは保証されていません。CPU速度、オペレーティングシステム、Linuxの種類などによって異なります。

于 2008-08-01T14:46:53.097 に答える
3

SMP システムでは、RDTSC の読み取りは信頼できません。各 CPU が独自のカウンターを維持し、各カウンターが別の CPU に対して同期されることが保証されていないためです。

試してみることをお勧めしclock_gettime(CLOCK_REALTIME)ます。posix マニュアルは、これをすべての準拠システムに実装する必要があることを示しています。ナノ秒のカウントを提供できますがclock_getres(CLOCK_REALTIME)、システムをチェックして、実際の解像度を確認することをお勧めします。

于 2008-08-18T15:40:14.173 に答える