89


18

gettimeofday()はマイクロ秒の分解能であることが保証されていますか?

私はもともとWin32 API用に書かれたゲームをLinuxに移植しています(よく、Win32ポートのOS XポートをLinuxに移植します)。

プロセスが起動してからuSecondsを与えることで `QueryPerformanceCounter`を実装しました:

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()`と相まって、私のマシン上で*うまく動作し、プログラムの起動時から `uSeconds`を含む64ビット変数を私に与えます。

それで、これは移植性がありますか?_カーネルが特定の方法でコンパイルされているか、そのようなものであるかによって、動作が異なることを発見したくありません。 私はそれがLinux以外のものに移植不可能であることは問題ない。

10 Answer


56


多分。 しかし、あなたはもっと大きな問題を抱えています。 システム上にタイマーを変更するプロセス(すなわちntpd)がある場合、 `gettimeofday()`は誤ったタイミングをもたらす可能性があります。 しかし、 "普通の" Linuxでは、 `gettimeofday()`の解像度は10usだと思います。 その結果、システム上で実行されているプロセスに基づいて、前後にジャンプすることができます。 これは事実上あなたの質問に対する答えをノーにします。

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

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


41


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

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

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

これを私の箱の上で走らせると、

11867927879484732 11867927879692217 printf:207485を呼び出すのにこの時間がかかりました

ここに インテルの開発者ガイドがあります。

#include #include

インラインuint64_t rdtsc(){uint32_t lo、こんにちは。 __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;符号なしlong long y。 x = rdtsc(); printf( "%lld \ n"、x); y = rdtsc(); printf( "%lld \ n"、y); printf( "printf:%lldの呼び出しに時間がかかりました\ n"、y-x)。 }


18


@バーナード:

私は認めざるを得ない、あなたの例のほとんどは私の頭の上にまっすぐに行った。 コンパイルはしますが、うまくいくようです。 これはSMPシステムまたはSpeedStepにとって安全ですか? __

それは良い質問です…​ コードは問題ないと思います。 実用的な観点から、私たちは毎日私の会社でそれを使っています、そして私達は2〜8コアからなる、かなり広い範囲の箱の上で走っています。 もちろん、YMMVなどですが、これは信頼性が高く、オーバーヘッドが少ない(コンテキストをシステムスペースに切り替えることができないため)タイミングの方法のようです。

一般的にどのように機能するかは、

  • コードブロックをアセンブラとして宣言します(そして揮発性なので、オプティマイザはそのままにします)。

  • CPUID命令を実行してください。 CPUの情報を取得することに加え(これについては何もしません)、タイミングがアウトオブオーダー実行の影響を受けないように、CPUの実行バッファを同期します。

  • rdtsc(read timestamp)を実行してください。 これは、プロセッサがリセットされてから実行されたマシンサイクル数を取得します。 これは64ビット値なので、現在のCPU速度では194年ごとにラップアラウンドします。 興味深いことに、Pentiumの最初の参考文献では、5800年ごとにラップされていることがわかりました。

  • 最後の数行は、レジスタからの値を変数hiとloに格納し、それを64ビットの戻り値に入れます。

特定のメモ:

  • アウトオブオーダ実行は不正確な結果を引き起こす可能性があるので、cpuに関する情報を提供することに加えて、アウトオブオーダ命令実行も同期させる "cpuid"命令を実行します。

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

  • 冬眠中のコメントはおそらく本当ですが、実際にはおそらく冬眠の境界を越えたタイミングを気にする必要はありません。

  • スピードステップに関して:新しいIntel CPUはスピードの変化を補正し、調整されたカウントを返します。 私たちのネットワーク上のいくつかのボックスをクイックスキャンしたところ、それを持っていないボックスが1つだけ見つかりました。それは、古いデータベースサーバーを実行しているPentium 3です。 (これらはLinuxの箱なので、私はチェックしました:grep constant_tsc / proc / cpuinfo)

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

これがあなたの好奇心を満たしてくれることを願っています。それは興味深く、(IMHO)研究不足の分野です。 プログラマがCを知っているべきかどうかについて、JeffとJoelが話していたのはいつですか。 私は彼らに向かって叫んでいました。 コンピュータが何をしているのか知りたいのなら、アセンブラはあなたが学ぶべきものです。」


14


あなたはhttp://juliusdavies.ca/posix_clocks/clock_realtime_linux_faq.html [clock_gettime(CLOCK_REALTIME) `に関するLinuxに関するよくある質問]に興味を持っているかもしれません]


11


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


10


_ したがって、マイクロ秒を明示的に示しますが、システムクロックの解像度は指定されていません。 私はこの文脈での決議はそれが今までにどれだけ最小量がそれまで増分されるかを意味すると思いますか? _

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

他の人が示唆しているように、 `gettimeofday()`は時間を設定することがクロックスキューを引き起こし、あなたの計算を遅らせる可能性があるので悪いです。 `clock_gettime(CLOCK_MONOTONIC)`はあなたが望むもので、 `clock_getres()`はあなたの時計の精度を教えてくれます。


9


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

私はhttp://web.archive.org/web/20160711223333/http://www.informit.com/guides/content.aspx?g=cplusplusからこの答えを得ました


5


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


5


https://stackoverflow.com/a/98/ [この回答]時計の調整に関する問題について述べています。 目盛り単位を保証する問題と調整される時間に関する問題の両方がC 11の ``ライブラリで解決されています。

クロック `std

chrono :: steady_clock`は調整されないことが保証されており、さらにそれはリアルタイムに対して一定の速度で進むので、SpeedStepのような技術はそれに影響を与えてはいけません。

型安全な単位は、 `std

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


3


各CPUがそれ自身のカウンタを維持し、各カウンタが他のCPUに関して同期化されることによって保証されないので、RDTSCを読むことはSMPシステムにおいて信頼できない。

私は* clock_gettime(CLOCK_REALTIME) *を試すことをお勧めします。 posixマニュアルは、これがすべての準拠システムに実装されるべきであることを示しています。 それはナノ秒のカウントを提供することができます、しかし実際の解像度が何であるかを見るためにあなたのシステム上でおそらく `` clock_getres(CLOCK_REALTIME) `*をチェックしたいでしょう。