次の方法で共有


ゲームタイミングとマルチコアプロセッサ

現在のコンピューターでは電源管理テクノロジが一般的になり、高分解能の CPU タイミングを取得するために一般的に使用される方法である RDTSC 命令は、想定どおりに動作しなくなる可能性があります。 この記事では、Windows API QueryPerformanceCounter と QueryPerformanceFrequencyを使用して、高解像度の CPU タイミングを取得する、より正確で信頼性の高いソリューションを提案します。

バックグラウンド

x86 P5 命令セットが導入されて以来、多くのゲーム開発者は、RDTSC 命令である読み取りタイム スタンプ カウンターを使用して高解像度のタイミングを実行しています。 Windows マルチメディア タイマーは、サウンドとビデオの処理に十分な精度を備えますが、フレーム時間が 10 ミリ秒以下の場合、差分時間情報を提供するのに十分な解像度がありません。 多くのゲームでは、まだ起動時にマルチメディア タイマーを使用して CPU の周波数を確立し、その周波数値を使用して RDTSC からの結果をスケーリングして正確な時間を取得します。 RDTSC の制限により、Windows API では、QueryPerformanceCounterと QueryPerformanceFrequencyのルーチンを使用して、この機能にアクセスするためのより正しい方法公開されています。

タイミングに RDTSC を使用する場合、次の基本的な問題が発生します。

  • 不連続の値。 RDTSC を直接使用すると、スレッドは常に同じプロセッサで実行されていると想定されます。 マルチプロセッサ システムとデュアル コア システムでは、コア間でのサイクル カウンターの同期は保証されません。 これは、さまざまな時間にさまざまなコアをアイドル状態にして復元する最新の電源管理テクノロジと組み合わせると悪化し、通常はコアが同期されなくなります。 アプリケーションの場合、通常、スレッドがプロセッサ間をジャンプし、大きなデルタ、負のデルタ、または停止したタイミングの結果となるタイミング値を取得すると、グリッチまたは潜在的なクラッシュが発生します。
  • 専用ハードウェアの可用性。 RDTSC は、アプリケーションがプロセッサのサイクル カウンターに要求するタイミング情報をロックします。 長年にわたり、これは高精度のタイミング情報を得るための最良の方法でしたが、新しいマザーボードには、RDTSCの欠点なしに高解像度のタイミング情報を提供する専用のタイミングデバイスが含まれています。
  • CPU の周波数の変動。 多くの場合、プログラムの有効期間中に CPU の周波数が固定されていることが前提となります。 ただし、最新の電源管理テクノロジでは、これは正しくない前提です。 最初はラップトップコンピュータやその他のモバイルデバイスに限定されていましたが、CPUの周波数を変更する技術は、多くのハイエンドデスクトップPCで使用されています。一貫した頻度を維持するために機能を無効にすることは、通常、ユーザーには受け入れできません。

推奨 事項

ゲームには正確なタイミング情報が必要ですが、RDTSC の使用に関連する問題を回避する方法でタイミング コードを実装する必要もあります。 高解像度のタイミングを実装する場合は、次の手順を実行します。

  1. RDTSC の代わりに QueryPerformanceCounter使用し、QueryPerformanceFrequencyします。 これらの API は RDTSC を利用できますが、代わりに、マザーボード上のタイミング デバイスや、高品質の高解像度タイミング情報を提供するその他のシステム サービスを利用する場合があります。 RDTSC は QueryPerformanceCounter よりもはるかに高速ですが、後者は API 呼び出しであるため、顕著な影響を与えることなくフレームごとに数百回呼び出すことができる API です。 (ただし、開発者は、パフォーマンスの低下を回避するために、ゲーム QueryPerformanceCounter をできるだけ呼び出さないようにする必要があります)。

  2. 差分を計算するときは、タイミング値のバグによってクラッシュや不安定な時間関連の計算が発生しないように、値をクランプする必要があります。 クランプ範囲は 0 (負の差分値を防ぐため) から、予想される最小フレームレートに基づいて妥当な値に設定する必要があります。 クランプは、アプリケーションのデバッグで役立つ可能性がありますが、パフォーマンス分析を行ったり、最適化されていないモードでゲームを実行したりする場合は、必ず注意してください。

  3. 1 つのスレッドですべてのタイミングを計算します。 複数のスレッド (たとえば、特定のプロセッサに関連付けられている各スレッド) でのタイミングの計算により、マルチコア システムのパフォーマンスが大幅に低下します。

  4. Windows API SetThreadAffinityMaskを使用して、単一のスレッドを 1 つのプロセッサ上に残すよう設定します。 通常、これはメイン ゲーム スレッドです。 QueryPerformanceCounterQueryPerformanceFrequency は通常、複数のプロセッサに対して調整されますが、BIOS またはドライバーのバグにより、スレッドがプロセッサ間を移動すると、これらのルーチンが異なる値を返す可能性があります。 そのため、スレッドを 1 つのプロセッサに保持することをお勧めします。

    他のすべてのスレッドは、独自のタイマー データを収集せずに動作する必要があります。 同期のボトルネックになるため、ワーカー スレッドを使用してタイミングを計算することはお勧めしません。 代わりに、ワーカー スレッドはメイン スレッドからタイムスタンプを読み取る必要があり、ワーカー スレッドはタイムスタンプのみを読み取るため、重要なセクションを使用する必要はありません。

  5. QueryPerformanceFrequency 呼び出 は 1 回だけです。これは、システムの実行中に頻度が変化しないためです。

アプリケーションの互換性

多くの開発者は長年にわたって RDTSC の動作を想定しているため、タイミングの実装により、複数のプロセッサまたはコアを持つシステムで実行すると、一部の既存のアプリケーションで問題が発生する可能性が非常に高くなります。 これらの問題は、通常、グリッチやスローモーションの動きとして現れます。 電源管理を認識していないアプリケーションには簡単な解決策はありませんが、マルチプロセッサ システムの 1 つのプロセッサで常にアプリケーションを実行するように強制するための既存の shim があります。

この shim を作成するには、Windows アプリケーション互換性 から Microsoft Application Compatibility Toolkitダウンロードします。

ツールキットの一部である互換性管理者を使用して、アプリケーションと関連する修正プログラムのデータベースを作成します。 このデータベースの新しい互換モードを作成し、SingleProcAffinity 互換性修正プログラムを選択して、アプリケーションのすべてのスレッドを 1 つのプロセッサ/コアで強制的に実行します。 コマンドライン ツール Fixpack.exe (ツールキットの一部) を使用すると、このデータベースをインストール、テスト、および配布用のインストール可能なパッケージに変換できます。

互換性管理者の使用方法については、ツールキットのドキュメントを参照してください。 Fixpack.exeの構文と使用例については、コマンド ライン ヘルプを参照してください。

顧客指向の情報については、Microsoft のヘルプとサポートの次のサポート技術情報の記事を参照してください。