高解像度タイム スタンプの取得

Windows には、高解像度のタイム スタンプの取得や時間間隔の測定に使用できる API が用意されています。 ネイティブ コードのプライマリ API は QueryPerformanceCounter (QPC) です。 デバイス ドライバーの場合、カーネル モード API は KeQueryPerformanceCounter です。 マネージド コードの場合、 System.Diagnostics.Stopwatch クラスは正確な時間ベースとして QPC を使用します。

QPC は、外部時刻参照とは独立しており、同期されません。 高解像度の時刻測定で使用する協定世界時 (UTC) など、外部のタイム リファレンスに同期できるタイム スタンプを取得するには、 GetSystemTimePreciseAsFileTime を使用します。

タイム スタンプと時間間隔の測定は、コンピューターとネットワークのパフォーマンス測定に不可欠な部分です。 これらのパフォーマンス測定操作には、応答時間、スループット、待機時間の計算、およびコード実行のプロファイリングが含まれます。 これらの各操作には、開始時刻と終了イベントによって定義される時間間隔中に発生するアクティビティの測定が含まれます。このイベントは、外部の時刻参照に依存しません。

QPC は、通常、イベントをタイムスタンプし、同じシステムまたは仮想マシンで発生する小さな時間間隔を測定するために使用する最適な方法です。 各マシンがネットワーク タイム プロトコル (NTP) などの時刻同期スキームに参加している場合は、複数のマシン間でイベントをタイムスタンプする場合は 、GetSystemTimePreciseAsFileTime を使用することを検討してください。 QPC は、プロセッサのタイム スタンプ カウンター (TSC) を直接読み取るなど、他の時間測定方法で発生する可能性がある困難を回避するのに役立ちます。

Windows バージョンでの QPC サポート

QPC は Windows 2000 および Windows XP で導入され、ハードウェア プラットフォームとプロセッサの機能強化を活用するために進化しました。 ここでは、これらの Windows バージョンで実行されるソフトウェアを維持するのに役立つ、さまざまな Windows バージョンでの QPC の特性について説明します。

Windows XP と Windows 2000

QPC は Windows XP と Windows 2000 で使用でき、ほとんどのシステムで適切に動作します。 ただし、一部のハードウェア システムの BIOS では、ハードウェアの CPU 特性が正しく示されていません (不変でない TSC)、一部のマルチコアまたはマルチプロセッサ システムでは、コア間で同期できない TSC を搭載したプロセッサが使用されました。 これらのバージョンの Windows を実行するファームウェアの欠陥があるシステムでは、 QPC の基礎として TSC を使用した場合、異なるコアで同じ QPC 読み取りが提供されない場合があります。

Windows Vista と Windows Server 2008

Windows Vista および Windows Server 2008 に付属するすべてのコンピューターでは、プラットフォーム カウンター (高精度イベント タイマー (HPET)) または ACPI 電源管理タイマー (PM タイマー) を QPC の基礎として使用しました。 このようなプラットフォーム タイマーは、TSC よりもアクセス待ち時間が長く、複数のプロセッサ間で共有されます。 これにより、複数のプロセッサから同時に呼び出される場合、 QPC のスケーラビリティが制限されます。

Windows 7 と Windows Server 2008 R2

Windows 7 および Windows Server 2008 R2 コンピューターの大部分には、一定レートの TSC を備えたプロセッサがあり、 QPC の基礎としてこれらのカウンターを使用します。 TSC は、非常に短い待機時間とオーバーヘッド (プロセッサの種類に応じて 10 または 100 台のマシン サイクルの順序) でアクセスできる、プロセッサごとの高解像度ハードウェア カウンターです。 Windows 7 および Windows Server 2008 R2 は、オペレーティング システム (またはハイパーバイザー) がシステムの初期化中にすべてのプロセッサ間で個々の TSC を緊密に同期できる単一クロック ドメイン システムの QPC の基礎として TSC を使用します。 このようなシステムでは、パフォーマンス カウンターを読み取るコストは、プラットフォーム カウンターを使用するシステムに比べて大幅に低くなります。 さらに、同時呼び出しのオーバーヘッドは追加されません。また、ユーザー モード クエリではシステム呼び出しがバイパスされることが多いため、オーバーヘッドがさらに軽減されます。 TSC がタイムキーピングに適していないシステムでは、Windows は QPC の基礎としてプラットフォーム カウンター (HPET タイマーまたは ACPI PM タイマー) を自動的に選択します。

R2 のWindows 8、Windows 8.1、Windows Server 2012、Windows Server 2012

Windows 8、Windows 8.1、Windows Server 2012、Windows Server 2012 R2 では、パフォーマンス カウンターの基礎として TSC が使用されます。 TSC 同期アルゴリズムは、多くのプロセッサを搭載した大規模なシステムに対応するために大幅に改善されました。 さらに、新しい正確な時刻 API のサポートが追加されました。これにより、オペレーティング システムから正確な壁時計タイム スタンプを取得できます。 詳細については、「 GetSystemTimePreciseAsFileTime」を参照してください。 Arm プロセッサを使用するWindows RTおよびWindows 11デバイスとWindows 10デバイスでは、パフォーマンス カウンターは、プラットフォームが装備されている場合は、独自のプラットフォーム カウンターまたは Arm 汎用タイマーによって提供されるシステム カウンターに基づいています。

タイム スタンプを取得するためのガイダンス

Windows は、信頼性が高く効率的なパフォーマンス カウンターの提供に投資し続けます。 解像度が 1 マイクロ秒以上のタイム スタンプが必要で、タイム スタンプを外部タイム リファレンスと同期する必要がない場合は、 QueryPerformanceCounterKeQueryPerformanceCounter、または KeQueryInterruptTimePrecise を選択します。 解像度が 1 マイクロ秒以上の UTC 同期タイムスタンプが必要な場合は、 GetSystemTimePreciseAsFileTime または KeQuerySystemTimePrecise を選択します。

たとえば、「ハードウェア タイマー情報」で説明されている理由から、TSC レジスタを QPC ベースとして使用できないプラットフォームの数が比較的少ない場合、解像度の低いタイム スタンプを取得するよりも、高解像度のタイム スタンプを取得する方が大幅にコストが高くなる可能性があります。 10 から 16 ミリ秒の解決で十分な場合は、 GetTickCount64QueryInterruptTimeQueryUnbiasedInterruptTimeKeQueryInterruptTime、または KeQueryUnbiasedInterruptTime を使用して、外部タイム 参照に同期されていないタイム スタンプを取得できます。 UTC 同期タイム スタンプの場合は、 GetSystemTimeAsFileTime または KeQuerySystemTime を使用します。 より高い解像度が必要な場合は、 QueryInterruptTimePreciseQueryUnbiasedInterruptTimePrecise、または KeQueryInterruptTimePrecise を使用して、代わりにタイム スタンプを取得できます。

一般に、パフォーマンス カウンターの結果は、異なるスレッドまたはプロセスで測定された場合でも、マルチコア およびマルチプロセッサ システムのすべてのプロセッサで一貫しています。 この規則の例外をいくつか次に示します。

  • 特定のプロセッサで実行される Windows Vista 以前のオペレーティング システムは、次のいずれかの理由により、この一貫性に違反する可能性があります。

    • ハードウェア プロセッサには不変でない TSC があり、BIOS はこの状態を正しく示していません。
    • 使用された TSC 同期アルゴリズムは、プロセッサの数が多いシステムには適していませんでした。
  • 異なるスレッドから取得されたパフォーマンス カウンターの結果を比較する場合は、1 ティック±異なる値を考慮して、順序があいまいになります。 タイムスタンプが同じスレッドから取得された場合、この± 1 ティックの不確実性は適用されません。 このコンテキストでは、ティックという用語は、1 ÷に等しい期間 ( QueryPerformanceFrequency から取得されたパフォーマンス カウンターの頻度) を指します。

ハードウェアで同期されていない複数クロック ドメインを持つ大規模なサーバー システムでパフォーマンス カウンターを使用すると、Windows は TSC をタイミングの目的で使用できないことを判断し、 QPC の基礎としてプラットフォーム カウンターを選択します。 このシナリオでは信頼性の高いタイム スタンプが引き続き生成されますが、アクセスの待機時間とスケーラビリティは悪影響を受けます。 したがって、前述の使用ガイダンスで前述したように、このような解決が必要な場合は、1 マイクロ秒以上の解像度を提供する API のみを使用します。 TSC は、すべてのプロセッサ クロック ドメインのハードウェア同期を含むマルチクロック ドメイン システム上の QPC の基礎として使用されます。これにより、1 つのクロック ドメイン システムとして効果的に機能します。

パフォーマンス カウンターの頻度はシステムの起動時に固定され、すべてのプロセッサで一貫性があるため、 QueryPerformanceFrequency から頻度をクエリして、アプリケーションが初期化するときにだけクエリを実行し、結果をキャッシュする必要があります。

仮想化

パフォーマンス カウンターは、正しく実装されたハイパーバイザーで実行されているすべてのゲスト仮想マシンで確実に動作することが期待されます。 ただし、ハイパーバイザー バージョン 1.0 インターフェイスに準拠し、参照時間の対応を示すハイパーバイザーは、オーバーヘッドを大幅に削減できます。 ハイパーバイザー インターフェイスと対応の詳細については、「 ハイパーバイザーの仕様」を参照してください。

TSC の直接使用

RDTSC または RDTSCP プロセッサ命令を使用して TSC に直接クエリを実行することを強くお勧めします。これは、一部のバージョンの Windows、仮想マシンのライブ マイグレーション、および不変または緊密に同期された TSC のないハードウェア システムでは信頼性の高い結果が得られないためです。 代わりに、 QPC を使用して、提供される抽象化、一貫性、移植性を活用することをお勧めします。

タイム スタンプを取得する例

これらのセクションのさまざまなコード例では、タイム スタンプを取得する方法を示します。

ネイティブ コードでの QPC の使用

この例では、C および C++ ネイティブ コードで QPC を使用する方法を示します。

LARGE_INTEGER StartingTime, EndingTime, ElapsedMicroseconds;
LARGE_INTEGER Frequency;

QueryPerformanceFrequency(&Frequency); 
QueryPerformanceCounter(&StartingTime);

// Activity to be timed

QueryPerformanceCounter(&EndingTime);
ElapsedMicroseconds.QuadPart = EndingTime.QuadPart - StartingTime.QuadPart;


//
// We now have the elapsed number of ticks, along with the
// number of ticks-per-second. We use these values
// to convert to the number of elapsed microseconds.
// To guard against loss-of-precision, we convert
// to microseconds *before* dividing by ticks-per-second.
//

ElapsedMicroseconds.QuadPart *= 1000000;
ElapsedMicroseconds.QuadPart /= Frequency.QuadPart;

マネージド コードから高解像度のタイム スタンプを取得する

この例では、マネージド コード System.Diagnostics.Stopwatch クラスを使用する 方法を示します。

using System.Diagnostics;

long StartingTime = Stopwatch.GetTimestamp();

// Activity to be timed

long EndingTime  = Stopwatch.GetTimestamp();
long ElapsedTime = EndingTime - StartingTime;

double ElapsedSeconds = ElapsedTime * (1.0 / Stopwatch.Frequency);

System.Diagnostics.Stopwatch クラスには、時間間隔の測定を実行するための便利なメソッドがいくつか用意されています。

カーネル モードからの QPC の使用

Windows カーネルは、パフォーマンス カウンターとパフォーマンス頻度の両方を取得できる KeQueryPerformanceCounter を介して、パフォーマンス カウンターへのカーネル モード アクセスを提供します。 KeQueryPerformanceCounter はカーネル モードでのみ使用でき、デバイス ドライバーやその他のカーネル モード コンポーネントのライターに提供されます。

この例では、C および C++ カーネル モードで KeQueryPerformanceCounter を 使用する方法を示します。

LARGE_INTEGER StartingTime, EndingTime, ElapsedMicroseconds;
LARGE_INTEGER Frequency;

StartingTime = KeQueryPerformanceCounter(&Frequency);

// Activity to be timed

EndingTime = KeQueryPerformanceCounter(NULL);
ElapsedMicroseconds.QuadPart = EndingTime.QuadPart - StartingTime.QuadPart;
ElapsedMicroseconds.QuadPart *= 1000000;
ElapsedMicroseconds.QuadPart /= Frequency.QuadPart;

QPC と TSC に関する一般的な FAQ

QPC と TSC 全般に関してよく寄せられる質問への回答を次に示します。

QueryPerformanceCounter() は Win32 GetTickCount() または GetTickCount64() 関数と同じですか?

いいえ。 GetTickCountGetTickCount64QPC とは関係ありません。 GetTickCountGetTickCount64 は、システムが開始されてからのミリ秒数を返します。

QPC を使用するか、RDTSC/RDTSCP 命令を直接呼び出す必要がありますか?

誤りや移植性の問題を回避するために、TSC レジスタまたは RDTSC または RDTSCP プロセッサ命令を使用する代わりに QPC を使用することを強くお勧めします。

QPC と外部タイム エポックとの関係は何ですか?UTC などの外部エポックに同期できますか?

QPC は、UTC などの外部時刻参照に同期できないハードウェア カウンターに基づいています。 外部 UTC 参照に同期できる正確な時刻タイム スタンプについては、 GetSystemTimePreciseAsFileTime を使用します。

QPC は、管理者が行った夏時間、うるう秒、タイム ゾーン、またはシステム時刻の変更の影響を受けますか?

いいえ。 QPC は、システム時刻と UTC とは完全に独立しています。

QPCの精度は、電源管理またはターボブースト技術によって引き起こされるプロセッサ周波数の変化の影響を受けますか?

いいえ。 プロセッサに不変の TSC がある場合、 QPC はこのような変更の影響を受けません。 プロセッサに不変の TSC がない場合、 QPC は、プロセッサの周波数変更やターボ ブースト テクノロジの影響を受けないプラットフォーム ハードウェア タイマーに戻ります。

QPC は、マルチプロセッサ システム、マルチコア システム、およびハイパースレッディングを使用するシステムで確実に機能しますか?

はい。

QPC がコンピューターで動作することを確認して検証操作方法。

このようなチェックを実行する必要はありません。

非インバリアント TSC を持つプロセッサはどれですか?システムに不変でない TSC がある場合、どのようにチェックできますか?

このチェックを自分で実行する必要はありません。 Windows オペレーティング システムは、システムの初期化時にいくつかのチェックを実行して、TSC が QPC の基礎として適しているかどうかを判断します。 ただし、参照のために、プロセッサに不変の TSC があるかどうかを確認するには、次のいずれかを使用します。

  • Windows Sysinternals のCoreinfo.exe ユーティリティ
  • TSC 特性に関連する CPUID 命令によって返される値の確認
  • プロセッサの製造元のドキュメント

Windows Sysinternals Coreinfo.exe ユーティリティ (www.sysinternals.com) によって提供される TSC-INVARIANT 情報を次に示します。 アスタリスクは "True" を意味します。

> Coreinfo.exe 

Coreinfo v3.2 - Dump information on system CPU and memory topology
Copyright (C) 2008-2012 Mark Russinovich
Sysinternals - www.sysinternals.com

 <unrelated text removed>

RDTSCP          * Supports RDTSCP instruction
TSC             * Supports RDTSC instruction
TSC-DEADLINE    - Local APIC supports one-shot deadline timer
TSC-INVARIANT   * TSC runs at constant rate

QPC は、Windows RTハードウェア プラットフォームで確実に機能しますか?

はい。

QPC はどのくらいの頻度でロールオーバーされますか?

最新のシステム ブートから 100 年未満で、使用される基になるハードウェア タイマーに基づいて長くなる可能性があります。 ほとんどのアプリケーションでは、ロールオーバーは問題ではありません。

QPC を呼び出す場合の計算コストは何ですか?

QPC の計算呼び出しコストは、主に基になるハードウェア プラットフォームによって決定されます。 TSC レジスタが QPC の基礎として使用される場合、計算コストは主に、プロセッサが RDTSC 命令を処理するのにかかる時間によって決まります。 この時間は、使用されるプロセッサに応じて、CPU サイクルの 10 から数百 CPU サイクルの範囲です。 TSC を使用できない場合、システムは別のハードウェア時間ベースを選択します。 これらのタイム ベースはマザーボード (PCI サウス ブリッジや PCH など) に配置されるため、呼び出しあたりの計算コストは TSC よりも高く、プロセッサの速度やその他のハードウェア要因に応じて 0.8 ~ 1.0 マイクロ秒付近に頻繁に存在します。 このコストは、マザーボード上のハードウェア デバイスにアクセスするために必要な時間によって支配されます。

QPC にはカーネル切り替え (システム呼び出し) が必要ですか?

システムが QPC の基礎として TSC レジスタを使用できる場合、カーネル遷移は必要ありません。 HPET タイマーや PM タイマーなど、システムで別の時間ベースを使用する必要がある場合は、システム呼び出しが必要です。

パフォーマンス カウンターは単調 (減少しない) ですか?

はい。 QPC は後方に移動しません。

パフォーマンス カウンターを使用して、イベントを時間内に並べ替えることができますか?

はい。 ただし、異なるスレッドから取得されたパフォーマンス カウンターの結果を比較すると、1 ティック±異なる値は、同じタイム スタンプを持っているかのようにあいまいな順序になります。

パフォーマンス カウンターの精度はどのくらいですか?

答えは、さまざまな要因によって異なります。 詳細については、「 低レベルのハードウェア クロック特性」を参照してください。

QPC と TSC を使用したプログラミングに関する FAQ

QPC と TSC を使用したプログラミングに関してよく寄せられる質問への回答を次に示します。

QPC 出力をミリ秒に変換する必要があります。double または float への変換で精度が失われるのを回避するにはどうすればよいですか?

整数パフォーマンス カウンターで計算を実行する場合は、次の点に注意してください。

  • 整数除算は剰余を失います。 これにより、場合によっては精度が失われる可能性があります。
  • 64 ビット整数と浮動小数点 (double) の間の変換では、浮動小数点仮数が可能なすべての整数値を表すことができるため、精度が失われる可能性があります。
  • 64 ビット整数を乗算すると、整数オーバーフローが発生する可能性があります。

一般的な原則として、これらの計算と変換を可能な限り遅らせ、発生したエラーの複合化を回避します。

QPC を 100 ナノ秒ティックに変換して FILETIME に追加するにはどうすればよいですか?

ファイル時刻は、1601 年 1 月 1 日午前 12 時から経過した 100 ナノ秒間隔 (UTC) の数を表す 64 ビット値です。 ファイル時刻は、 GetSystemTimeAsFileTime や GetSystemTimePreciseAsFileTime などの時刻を返す Win32 API 呼び出しで使用 されます。 これに対し、 QueryPerformanceCounter は、時間を 1/( QueryPerformanceFrequency から取得したパフォーマンス カウンターの頻度) 単位で表す値を返します。 2 つの間の変換には、 QPC 間隔と 100 ナノ秒間隔の比率を計算する必要があります。 値が小さい (0.0000001 / 0.000000340) 可能性があるため、精度が低下しないように注意してください。

QPC から返されるタイム スタンプが符号付き整数であるのはなぜですか?

QPC タイム スタンプを含む計算には、減算が含まれる場合があります。 符号付き値を使用すると、負の値を生成する可能性がある計算を処理できます。

マネージド コードから高解像度のタイム スタンプを取得するにはどうすればよいですか?

System.Diagnostics.Stopwatch クラスから Stopwatch.GetTimeStamp メソッドを呼び出します。 Stopwatch.GetTimeStamp の使用方法の例については、「マネージド コードから高解像度のタイム スタンプを取得する」を参照してください。

どのような状況で QueryPerformanceFrequency は FALSE を返すか、QueryPerformanceCounter は 0 を返しますか?

これは、Windows XP 以降を実行するシステムでは発生しません。

QPC を使用するには、スレッド アフィニティを 1 つのコアに設定する必要がありますか?

いいえ。 詳細については、「 タイム スタンプを取得するためのガイダンス」を参照してください。 このシナリオは、必要でも望ましくもありません。 このシナリオを実行すると、処理を 1 つのコアに制限するか、 QueryPerformanceCounter を呼び出すときに複数のスレッドが同じコアにアフィニティを設定した場合に 1 つのコアにボトルネックを作成することで、アプリケーションのパフォーマンスに悪影響を及ぼす可能性があります。

低レベルのハードウェア クロック特性

これらのセクションでは、低レベルのハードウェア クロック特性を示します。

絶対クロックと差分クロック

絶対時計は正確な時刻の読み取りを提供します。 通常は協定世界時 (UTC) に基づいているため、その精度は、外部時刻参照との同期の程度によって一部異なります。 差分クロックは時間間隔を測定し、通常は外部のタイム エポックに基づくわけではありません。 QPC は差分クロックであり、外部タイム エポックまたは参照には同期されません。 時間間隔の測定に QPC を使用すると、通常、絶対クロックから派生したタイム スタンプを使用するよりも精度が高くなります。 これは、絶対クロックの時刻を同期するプロセスによって位相と周波数のシフトが発生し、短期的な時間間隔測定の不確実性を高めることができるためです。

解像度、精度、精度、安定性

QPC では、その基礎としてハードウェア カウンターが使用されます。 ハードウェア タイマーは、ティック ジェネレーター、ティックをカウントするカウンター、カウンター値を取得する手段の 3 つの部分で構成されます。 これら 3 つのコンポーネントの特性によって、 QPC の解像度、精度、精度、安定性が決まります。

ハードウェア ジェネレーターが一定の速度でティックを提供する場合は、これらのティックをカウントするだけで時間間隔を測定できます。 ティックが生成されるレートは周波数と呼ばれ、Hertz (Hz) で表されます。 頻度の逆数はピリオドまたはティック間隔と呼ばれ、適切な国際単位 (SI) の時間単位 (second、millisecond、microsecond、nanosecond など) で表されます。

時間間隔

タイマーの解像度は、期間と等しくなります。 解像度は、任意の 2 つのタイム スタンプを区別する機能を決定し、測定できる最小の時間間隔に下限を配置します。 これはティック解像度と呼ばれることもあります。

時間のデジタル測定は、時間が継続的に進んでいる間、デジタルカウンタが離散ステップで進むので、±1ティックの不確実性を導入します。 この不確実性は量子化誤差と呼ばれます。 一般的な時間間隔の測定では、量子化誤差が測定される時間間隔よりもはるかに小さいため、この効果は無視されることがよくあります。

デジタル時間測定

ただし、測定される期間が小さく、タイマーの解像度に近づく場合は、この量子化エラーを考慮する必要があります。 発生したエラーのサイズは、1 つのクロック期間のサイズです。

次の 2 つの図は、1 時間単位の解像度のタイマーを使用して、± 1 ティックの不確実性の影響を示しています。

ティックの不確実性

QueryPerformanceFrequencyQPC の頻度を返し、期間と解決はこの値の逆数と等しくなります。 QueryPerformanceFrequency が返すパフォーマンス カウンターの頻度は、システムの初期化中に決定され、システムの実行中は変更されません。

注意

多くの場合 、QueryPerformanceFrequency はハードウェア ティック ジェネレーターの実際の頻度を返しません。 たとえば、以前のバージョンの Windows では、QueryPerformanceFrequency は TSC 頻度を 1024 で割って返します。ハイパーバイザー バージョン 1.0 インターフェイス (または常に新しいバージョンの Windows) を実装するハイパーバイザーで実行している場合、パフォーマンス カウンターの頻度は 10 MHz に固定されます。 その結果、 QueryPerformanceFrequency がハードウェアの頻度から派生した値を返すと想定しないでください。

 

QueryPerformanceCounter はパフォーマンス カウンターを読み取り、マシンがスタンバイ、休止状態、コネクト スタンバイなどのスリープ状態だった時間を含め、Windows オペレーティング システムの起動後に発生したティックの合計数を返します。

これらの例では、ティック間隔と解像度を計算する方法と、ティック数を時間値に変換する方法を示します。

例 1

QueryPerformanceFrequency は、特定のコンピューターの値 3,125,000 を返します。 このマシンでの QPC 測定のティック間隔と解像度は何ですか? ティック間隔 (期間) は、3,125,000 の逆数で、0.000000320 (320 ナノ秒) です。 したがって、各ティックは 320 ナノ秒の受け渡しを表します。 320 ナノ秒未満の時間間隔は、このマシンでは測定できません。

ティック間隔 = 1/(パフォーマンス頻度)

ティック間隔 = 1/3,125,000 = 320 ns

例 2

前の例と同じコンピューターでは、 QPC への 2 回の連続する呼び出しから返される値の差は 5 です。 2 つの呼び出しの間にどれくらいの時間が経過しましたか? 5 ティックに 320 ナノ秒を掛けると、1.6 マイクロ秒が生成されます。

ElapsedTime = Ticks * Tick Interval

ElapsedTime = 5 * 320 ns = 1.6 μs

ソフトウェアからティックカウンターにアクセス(読み取り)するのに時間がかかり、このアクセス時間は時間測定の精度を下げる可能性があります。 これは、最小間隔時間 (測定できる最小の時間間隔) が解像度とアクセス時間の大きいためです。

Precision = MAX [ Resolution, AccessTime]

たとえば、100 ナノ秒の解像度と 800 ナノ秒のアクセス時間を持つ架空のハードウェア タイマーについて考えてみましょう。 これは、TSC レジスタの代わりにプラットフォーム タイマーが QPC の基礎として使用された場合に発生する可能性があります。 したがって、この計算に示すように、精度は 100 ナノ秒ではなく 800 ナノ秒になります。

Precision = MAX [800 ns,100 ns] = 800 ns

この 2 つの図は、この効果を表しています。

qpc アクセス時間

アクセス時間が解像度を超える場合は、 を推測して精度を向上させないでください。 言い換えると、タイム スタンプが正確に中央、または呼び出しの先頭または末尾に取られると仮定すると、エラーになります。

これに対し、 QPC アクセス時間が 20 ナノ秒で、ハードウェア クロック解像度が 100 ナノ秒である次の例を考えてみましょう。 これは、TSC レジスタが QPC の基礎として使用された場合に発生する可能性があります。 ここで、精度はクロック解像度によって制限されます。

qpc precision

実際には、カウンターの読み取りに必要な時間が解像度よりも大きいか小さい時間ソースを見つけることができます。 どちらの場合も、精度は 2 つの方が大きくなります。

この表では、さまざまなクロックのおおよその解像度、アクセス時間、および精度に関する情報を示します。 値の一部は、プロセッサ、ハードウェア プラットフォーム、プロセッサ速度によって異なります。

クロック ソース 公称クロック周波数 クロック解像度 アクセス時間 (標準) Precision
PC RTC 64 Hz 15.625 ミリ秒 該当なし 該当なし
3 GHz プロセッサ クロックで TSC を使用してパフォーマンス カウンターを照会する 3 MHz 333 ナノ秒 30 ナノ秒 333 ナノ秒
3 GHz サイクル時間のシステムでの RDTSC マシン命令 3 GHz 333 ピコ秒 30 ナノ秒 30 ナノ秒

 

QPC ではハードウェア カウンターが使用されるため、ハードウェア カウンターのいくつかの基本的な特性を理解すると、QPC の機能と制限事項について理解できます。

最も一般的に使用されるハードウェアティックジェネレータは、水晶発振器です。 この結晶は、優れた安定性と精度を有する安価な周波数基準を提供する圧電特性を示す石英または他のセラミック材料の小片である。 この周波数は、クロックによってカウントされるティックを生成するために使用されます。

タイマーの精度は、true または標準値への適合性の程度を指します。 これは主に、指定された周波数でティックを提供する水晶発振器の能力に依存します。 振動の周波数が高すぎると、クロックは「速く実行」され、測定された間隔は実際よりも長く表示されます。周波数が低すぎると、クロックは "遅く実行" され、測定された間隔は実際よりも短く表示されます。

短い期間の一般的な時間間隔測定 (応答時間の測定、ネットワーク待機時間の測定など) の場合、通常はハードウェア発振器の精度で十分です。 ただし、一部の測定では、特に時間間隔が長い場合や、異なるマシンで行われた測定値を比較する場合に、発振器の周波数精度が重要になります。 このセクションの残りの部分では、オシレーターの精度の影響について説明します。

振動の結晶の周波数は、製造プロセス中に設定され、指定された周波数プラスまたは最大周波数オフセットと呼ばれる「100万分の1の部品数」(ppm)で表される製造公差の観点からメーカーによって指定されます。 指定された周波数が 1,000,000 Hz で、最大周波数オフセットが ± 10 ppm の結晶は、実際の周波数が 999,990 Hz から 1,000,010 Hz の間であれば、仕様の範囲内になります。

100万個あたりの語句の部分をマイクロ秒/秒に置き換えることで、この周波数オフセット誤差を時間間隔測定に適用できます。 + 10 ppm オフセットの発振器では、1 秒あたり 10 マイクロ秒のエラーが発生します。 したがって、1 秒の間隔を測定すると、高速で実行され、1 秒の間隔が 0.999990 秒として測定されます。

100 ppm の周波数誤差では、24 時間後に 8.64 秒の誤差が発生します。 この表は、より長い時間間隔の累積誤差による測定の不確実性を示しています。

時間間隔の期間 +/- 10 PPM 周波数許容範囲での累積誤差による測定不確かさ
1 マイクロ秒 ± 10 ピコ秒 (10 から 12)
1 ミリ秒 ± 10 ナノ秒 (10 から 9)
1 秒 ± 10 マイクロ秒
1 時間 ± 60 マイクロ秒
1 日 ± 0.86 秒
1 週間 ± 6.08 秒

 

前の表は、少ない時間間隔の場合、周波数オフセット エラーは無視されることがよくあります。 ただし、時間間隔が長い場合は、周波数オフセットが小さくても、測定に大きな不確実性が生じる可能性があります。

パーソナル コンピュータやサーバーで使用される水晶発振器は、通常、100 万個あたり 30 ~ 50 部±の周波数許容範囲で製造され、結晶を 500 ppm もオフにすることはほとんどありません。 周波数オフセット許容値が非常に厳しい結晶を使用できますが、コストが高いため、ほとんどのコンピュータでは使用されません。

この周波数オフセット エラーの悪影響を軽減するために、最近のバージョンの Windows (特にWindows 8) では、複数のハードウェア タイマーを使用して周波数オフセットを検出し、可能な限り補正します。 この調整プロセスは、Windows の起動時に実行されます。

次の例に示すように、ハードウェア クロックの周波数オフセット 誤差は達成可能な精度に影響を与え、クロックの解像度は重要でない場合があります。

周波数オフセット誤差が達成可能な精度に影響を与える

例 1

たとえば、分解能が 1 マイクロ秒、最大周波数オフセット 誤差が ±50 ppm の 1 MHz 発振器を使用して、時間間隔の測定を実行するとします。 ここで、オフセットが正確に +50 ppm であるとします。 つまり、実際の周波数は 1,000,050 Hz になります。 24 時間の時間間隔を測定した場合、測定は 4.3 秒短すぎます (23:59:55.7000000 の測定と実際の 24:00:00.000000)。

1 日の秒数 = 86400

周波数オフセット 誤差 = 50 ppm = 0.00005

86,400 秒 * 0.00005 = 4.3 秒

例 2

プロセッサの TSC クロックが水晶発振器によって制御され、3 GHz の周波数を指定したとします。 つまり、解像度は 1/3,000,000,000 または約 333 ピコ秒になります。 プロセッサ クロックの制御に使用される結晶の周波数許容値が ±50 ppm で、実際には +50 ppm であるとします。 印象的な解像度にもかかわらず、24時間の時間間隔測定はまだ4.3秒短すぎます。 (23:59:55.70000000000 は、実際の 24:00:00:00000000000 に対して測定されます)。

1 日の秒数 = 86400

周波数オフセット 誤差 = 50 ppm = 0.00005

86,400 秒 * 0.00005 = 4.3 秒

これは、高解像度の TSC クロックが、必ずしも低解像度クロックよりも正確な測定を提供するとは限らないことを示しています。

例 3

2 つの異なるコンピューターを使用して、同じ 24 時間の時間間隔を測定することを検討してください。 どちらのコンピュータも、最大周波数オフセットが50ppm±発振器を備えています。 これら 2 つのシステムで同じ時間間隔を測定できる距離はどのくらいですか? 前の例と同様に、± 50 ppm では、24 時間後± 4.3 秒の最大誤差が生成されます。 1 つのシステムの実行速度が 4.3 秒で、もう 4.3 秒遅い場合、24 時間後の最大エラーは 8.6 秒になる可能性があります。

1 日の秒数 = 86400

周波数オフセット 誤差 = ±50 ppm = ±0.00005

±(86,400 秒 * 0.00005) = ±4.3 秒

2 つのシステム間の最大オフセット = 8.6 秒

要約すると、長い時間間隔を測定するとき、および異なるシステム間の測定値を比較する場合、周波数オフセット誤差はますます重要になります。

タイマーの安定性は、たとえば温度の変化の結果として、時間の経過に伴ってティック周波数が変化するかどうかを示します。 コンピュータ上のティックジェネレータとして使用される石英結晶は、温度の関数として周波数の小さな変化を示す。 熱ドリフトによる誤差は、一般的な温度範囲の周波数オフセット誤差と比較して、通常は小さくなります。 ただし、温度変動が大きいポータブル機器や機器用ソフトウェアの設計者は、この効果を考慮する必要がある場合があります。

ハードウェア タイマー情報

TSC レジスタ (x86 および x64)

最新のすべての Intel および AMD プロセッサには、高レートで増加する 64 ビット レジスタである TSC レジスタ (通常はプロセッサ クロックと等しい) が含まれています。 このカウンターの値は 、RDTSC または RDTSCP マシン命令を通じて読み取ることができ、プロセッサに応じて、数十または数百のマシン サイクルの順序で非常に低いアクセス時間と計算コストを提供します。

TSC レジスタは理想的なタイム スタンプ メカニズムのように見えますが、タイムキーピングの目的で確実に機能できない状況を次に示します。

  • すべてのプロセッサに使用可能な TSC レジスタがあるわけではないため、ソフトウェアで TSC レジスタを直接使用すると移植性の問題が発生します。 (この場合、Windows は QPC の代替タイム ソースを選択するため、移植性の問題を回避できます)。
  • 一部のプロセッサでは、TSC クロックの周波数を変更したり、TSC レジスタの進歩を停止したりできるため、TSC はこれらのプロセッサのタイミング目的に適していません。 これらのプロセッサには、不変でない TSC レジスタがあると言われます。 (Windows はこれを自動的に検出し、 QPC の代替タイム ソースを選択します)。
  • 仮想化ホストに使用可能な TSC がある場合でも、ターゲット仮想化ホストにハードウェア支援 TSC スケーリングがない場合や利用していない場合に、実行中の仮想マシンをライブ マイグレーションすると、ゲストに表示される TSC 頻度が変更される可能性があります。 (この種のライブ マイグレーションがゲストに対して可能な場合は、ハイパーバイザーが CPUID の不変 TSC 機能ビットをクリアすることが予想されます)。
  • マルチプロセッサまたはマルチコア システムでは、一部のプロセッサとシステムで各コアのクロックを同じ値に同期できません。 (Windows はこれを自動的に検出し、 QPC の代替タイム ソースを選択します)。
  • 一部の大規模なマルチプロセッサ システムでは、プロセッサに不変の TSC がある場合でも、プロセッサ クロックを同じ値に同期できない場合があります。 (Windows はこれを自動的に検出し、 QPC の代替タイム ソースを選択します)。
  • 一部のプロセッサでは、命令が順番に実行されます。 これにより、 RDTSC 命令がプログラムで指定された時間とは異なる時刻に実行される可能性があるため、 RDTSC を使用して命令シーケンスを実行すると、サイクル カウントが正しくない可能性があります。 この問題に対応するために、 RDTSCP 命令が一部のプロセッサで導入されました。

他のタイマーと同様に、TSCは正確な周波数が事前に知られていない周波数オフセット誤差を持つ水晶発振器に基づいています。 したがって、使用する前に、別のタイミング基準を使用して校正する必要があります。

システムの初期化中に、Windows は TSC がタイミングの目的に適しているかどうかを確認し、必要な周波数調整とコア同期を実行します。

PM Clock (x86 および x64)

ACPI タイマー (PM クロックとも呼ばれます) は、プロセッサ速度とは無関係に信頼性の高いタイム スタンプを提供するために、システム アーキテクチャに追加されました。 これはこのタイマーの単一の目標であるため、1 つのクロック サイクルでタイム スタンプを提供しますが、他の機能は提供されません。

HPET タイマー (x86 および x64)

高精度イベント タイマー (HPET) は、マルチメディアやその他の時間に依存するアプリケーションのタイミング要件を満たすために、Intel と Microsoft が共同で開発しました。 プロセッサごとのリソースである TSC とは異なり、HPET はプラットフォーム全体で共有されるリソースですが、システムには複数の HPET が含まれる場合があります。 Windows Vista 以降、HPET のサポートは Windows で行われ、Windows 7 および Windows 8 ハードウェア ロゴ認定にはハードウェア プラットフォームでの HPET サポートが必要です。

汎用タイマー システム カウンター (Arm)

Arm ベースのプラットフォームには、Intel ベースまたは AMD ベースのプラットフォーム上にあるように、TSC、HPET、または PM クロックはありません。 代わりに、Arm プロセッサは、システム カウンター レジスタ (たとえば、CNTVCT_EL0) を含む汎用タイマー (汎用間隔タイマーまたは GIT とも呼ばれます) を提供します。 汎用タイマー システム カウンターは、固定周波数プラットフォーム全体のタイム ソースです。 起動時にゼロから始まり、高いレートで増加します。 Armv8.6 以降では、これは正確に 1 GHz として定義されますが、初期ブート ファームウェアによって設定されたクロック周波数レジスタを読み取ることによって決定する必要があります。 詳細については、「A プロファイル アーキテクチャの Arm アーキテクチャ リファレンス マニュアル」(DDI 0487) の「AArch64 状態の汎用タイマー」の章を参照してください。

サイクル カウンター (Arm)

Arm ベースのプラットフォームでは、パフォーマンス モニター サイクル カウンター レジスタ (たとえば、PMCCNTR_EL0) が提供されます。 このカウンターは、プロセッサのクロック サイクルをカウントします。 非不変であり、その単位がリアルタイムに関連付けられない場合があります。 このレジスタを使用してタイムスタンプを取得することはお勧めしません。