获取高分辨率时间戳

Windows提供了可用于获取高分辨率时间戳或测量时间间隔的 API。 本机代码的主要 API 是 QueryPerformanceCounter (QPC) 。 对于设备驱动程序,内核模式 API 是 KeQueryPerformanceCounter。 对于托管代码, System.Diagnostics.Stopwatch 类使用 QPC 作为其精确的时间基础。

QPC 独立于任何外部时间引用,并且不会同步到任何外部时间引用。 若要检索可以同步到外部时间引用的时间戳,例如协调世界时 (UTC) 用于高分辨率日度量,请使用 GetSystemTimePreciseAsFileTime

时间戳和时间间隔度量是计算机和网络性能度量不可或缺的一部分。 这些性能度量操作包括响应时间、吞吐量和延迟的计算,以及分析代码执行。 其中每个操作都涉及一个度量活动,这些活动在时间间隔内由开始和结束事件定义,该事件可以独立于任何外部的一天引用。

QPC 通常是用于时间戳事件的最佳方法,用于测量在同一系统或虚拟机上发生的小型时间间隔。 如果要跨多台计算机执行时间戳事件,请考虑使用 GetSystemTimePreciseAsFileTime ,前提是每台计算机都参与时间同步方案,例如网络时间协议 (NTP) 。 QPC 可帮助你避免遇到其他时间测量方法的困难,例如直接读取处理器的时间戳计数器 (TSC) 。

Windows版本中的 QPC 支持

QPC 是在 2000 Windows 引入的,Windows XP,并已演变为利用硬件平台和处理器的改进。 在这里,我们将介绍不同Windows版本的 QPC 的特征,以帮助维护在这些Windows版本上运行的软件。

Windows XP 和 Windows 2000

QPC 在 Windows XP 和 Windows 2000 上可用,适用于大多数系统。 但是,某些硬件系统的 BIOS 未正确指示硬件 CPU 特征 (非固定 TSC) ,某些多核或多处理器系统使用具有无法跨核心同步的 TSC 的处理器。 如果系统使用 TSC 作为 QPC 的基础,则运行这些版本的Windows的固件的系统可能无法在不同的核心上提供相同的 QPC 读取。

Windows Vista 和 Windows Server 2008

Windows Vista 和 Windows Server 2008 随附的所有计算机都使用平台计数器 (高精度事件计时器 (HPET) ) 或 ACPI 电源管理计时器 (PM 计时器) 作为 QPC 的基础。 此类平台计时器的访问延迟高于 TSC,在多个处理器之间共享。 如果从多个处理器并发调用 QPC,则这会限制 QPC 的可伸缩性。

Windows 7 和 Windows Server 2008 R2

大多数Windows 7 和 Windows Server 2008 R2 计算机都有具有常量速率 TSC 的处理器,并使用这些计数器作为 QPC 的基础。 TSC 是每处理器硬件计数器的高分辨率,可以根据处理器类型) ,以非常低的延迟和开销 ( (。 Windows 7 和 Windows Server 2008 R2 使用 TSC 作为单时钟域系统的 QPC 的基础,操作系统 (或虚拟机监控程序) 能够在系统初始化期间在所有处理器之间紧密同步各个 TSC。 在此类系统上,与使用平台计数器的系统相比,读取性能计数器的成本明显降低。 此外,并发调用和用户模式查询没有增加开销,通常绕过系统调用,这进一步降低了开销。 在 TSC 不适合计时的系统上,Windows会自动选择平台计数器, (HPET 计时器或 ACPI PM 计时器) 作为 QPC 的基础。

Windows 8、Windows 8.1、Windows Server 2012 和 Windows Server 2012 R2

Windows 8、Windows 8.1、Windows Server 2012和Windows Server 2012 R2 使用 TSC 作为性能计数器的基础。 TSC 同步算法得到了显著改进,以更好地容纳具有许多处理器的大型系统。 此外,添加了对新的精确日时间 API 的支持,该 API 支持从操作系统获取精确的时钟时间戳。 有关详细信息,请参阅 GetSystemTimePreciseAsFileTime。 在Windows RT电脑平台上,性能计数器基于专有平台计数器,或者Windows RT电脑通用计时器提供的系统计数器(如果平台装备如此)。

获取时间戳指南

Windows将继续投资提供可靠高效的性能计数器。 如果需要具有 1 微秒或更好分辨率的时间戳,并且不需要时间戳同步到外部时间引用,请选择 QueryPerformanceCounterKeQueryPerformanceCounterKeQueryInterruptTimePrecise。 如果需要 UTC 同步的时间戳,分辨率为 1 微秒或更高版本,请选择 GetSystemTimePreciseAsFileTimeKeQuerySystemTimePrecise

例如,由于硬件计时器信息中解释的原因,在相对较少的平台上,无法使用 TSC 注册作为 QPC 基础的平台,获取高分辨率时间戳比获取分辨率较低的时间戳要高得多。 如果 10 到 16 毫秒的分辨率足够,则可以使用 GetTickCount64QueryInterruptTimeQueryUnbiasedInterruptTimeKeQueryInterruptTime 或 KeQueryUnbiasedInterruptTime 获取未同步到外部时间引用的时间戳。 对于 UTC 同步的时间戳,请使用 GetSystemTimeAsFileTimeKeQuerySystemTime。 如果需要更高的分辨率,则可以改用 QueryInterruptTimePreciseQueryUnbiasedInterruptTimePreciseKeQueryInterruptTimePrecise 来获取时间戳。

一般情况下,即使在不同的线程或进程上测量,性能计数器结果在多核和多处理器系统中的所有处理器中都是一致的。 下面是此规则的一些例外:

  • 预Windows在某些处理器上运行的 Vista 操作系统可能会违反此一致性,原因如下:

    • 硬件处理器具有非固定 TSC,BIOS 未正确指示此条件。
    • 使用的 TSC 同步算法不适合具有大量处理器的系统。
  • 比较从不同线程获取的性能计数器结果时,请考虑± 1 刻度线的值有一个不明确的顺序。 如果时间戳取自同一线程,则此± 1 个刻度不确定性不适用。 在此上下文中,术语刻度是指一段时间等于 1,÷ (从 QueryPerformanceFrequency) 获取的性能计数器的频率。

在大型服务器系统上将性能计数器用于硬件中未同步的多时钟域时,Windows确定 TSC 不能用于计时目的,并选择平台计数器作为 QPC 的基础。 虽然此方案仍会产生可靠的时间戳,但访问延迟和可伸缩性受到不利影响。 因此,如前面的使用指南中所述,只有在需要此类解析时,才使用提供 1 微秒或更好分辨率的 API。 TSC 用作多时钟域系统上 QPC 的基础,这些系统包括所有处理器时钟域的硬件同步,这实际上使它们充当单个时钟域系统。

性能计数器的频率在系统启动时固定,在所有处理器之间保持一致,因此只需在应用程序初始化时查询 QueryPerformanceFrequency 的频率,然后缓存结果。

虚拟化

性能计数器预计将在正确实现的虚拟机监控程序上运行的所有来宾虚拟机上可靠地工作。 但是,符合虚拟机监控程序版本 1.0 接口的虚拟机监控程序,并显示参考时间启发可以大幅降低开销。 有关虚拟机监控程序接口和启发式的详细信息,请参阅 虚拟机监控程序规范

直接 TSC 用法

我们强烈建议不要使用 RDTSCRDTSCP 处理器指令直接查询 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 的一般常见问题解答

下面是有关 QPC 和 TSC 的常见问题的解答。

QueryPerformanceCounter () 是否与 Win32 GetTickCount () 或 GetTickCount64 () 函数相同?

不是。 GetTickCountGetTickCount64QPC 无关。 GetTickCountGetTickCount64 返回自系统启动以来的毫秒数。

我应该使用 QPC 还是直接调用 RDTSC /RDTSCP 指令?

为了避免错误和可移植性问题,强烈建议使用 QPC,而不是使用 TSC 寄存器或 RDTSC 或 RDTSCP 处理器指令。

QPC 与外部时间纪元的关系是什么?是否可以将其同步到外部纪元,例如 UTC?

QPC 基于无法同步到外部时间引用的硬件计数器,例如 UTC。 对于可以同步到外部 UTC 引用的精确一天时间戳,请使用 GetSystemTimePreciseAsFileTime

QPC 是否受夏令时、飞跃秒、时区或管理员所做的系统时间更改的影响?

不是。 QPC 完全独立于系统时间和 UTC。

QPC 准确性是否受电源管理或 Turbo Boost 技术导致的处理器频率更改的影响?

不是。 如果处理器具有固定 TSC, 则 QPC 不受此类更改的影响。 如果处理器没有固定 TSC, QPC 将还原为不受处理器频率更改或 Turbo Boost 技术影响的平台硬件计时器。

QPC 是否可靠地处理多处理器系统、多核系统和具有超线程的系统?

如何实现确定并验证 QPC 是否在我的计算机上工作?

无需执行此类检查。

哪些处理器具有非固定 TSC?如何检查系统是否具有非固定 TSC?

无需自行执行此检查。 Windows操作系统在系统初始化时执行多个检查,以确定 TSC 是否适合作为 QPC 的基础。 但是,出于参考目的,可以使用以下任一方法确定处理器是否具有固定 TSC:

  • Windows Sysinternals 中的Coreinfo.exe实用工具
  • 检查与 TSC 特征相关的 CPUID 指令返回的值
  • 处理器制造商的文档

下面显示了由 Windows Sysinternals Coreinfo.exe 实用工具提供的 TSC-INVARIANT 信息 (www.sysinternals.com) 。 星号表示“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 指令所需的时间。 此时间范围从 10 个 CPU 周期到数百个 CPU 周期,具体取决于使用的处理器。 如果无法使用 TSC,系统将选择不同的硬件时间基础。 由于这些时间基础位于主板 (,例如,在 PCI 南桥或 PCH) 上,因此每调用计算成本高于 TSC,并且经常在 0.8 - 1.0 微秒附近,具体取决于处理器速度和其他硬件因素。 这种成本主要取决于访问主板上的硬件设备所需的时间。

QPC 是否需要内核转换 (系统调用) ?

如果系统可以使用 TSC 注册作为 QPC 的基础,则不需要内核转换。 如果系统必须使用其他时间基数(如 HPET 或 PM 计时器),则需要系统调用。

性能计数器单调 (非减少) 吗?

性能计数器是否可以用于及时订购事件?

是的。 但是,比较从不同线程获取的性能计数器结果时,与 ± 1 刻度不同的值具有不明确的顺序,就像它们具有相同的时间戳一样。

性能计数器有多准确?

答案取决于各种因素。 有关详细信息,请参阅 低级别硬件时钟特征

有关使用 QPC 和 TSC 编程的常见问题解答

下面是有关 使用 QPC 和 TSC 编程的常见问题的解答。

我需要将 QPC 输出转换为毫秒。如何避免在转换为双精度或浮点时丢失精度?

对整数性能计数器执行计算时,需要牢记以下几点:

  • 整数除法将丢失余数。 在某些情况下,这可能会导致精度丢失。
  • 64 位整数与浮点之间的转换 (双) 可能会导致精度损失,因为浮点 mantissa 不能表示所有可能的整数值。
  • 64 位整数的乘法可能会导致整数溢出。

一般原则是,尽可能延迟这些计算和转换,以避免使引入的错误复杂化。

如何将 QPC 转换为 100 纳秒刻度,以便我可以将其添加到 FILETIME?

文件时间是一个 64 位值,表示自 1601 年 1 月 1 日凌晨 12:00 A.M.M.1,1601 协调世界时 (UTC) 以来已经过的 100 纳秒间隔数。 Win32 API 调用使用文件时间,这些调用返回一天的时间,例如 GetSystemTimeAsFileTimeGetSystemTimePreciseAsFileTime。 相比之下, QueryPerformanceCounter 返回表示从 QueryPerformanceFrequency) 获取的性能计数器的频率(以 1/ ()的值。 两者之间的转换需要计算 QPC 间隔与 100 纳秒间隔的比率。 请小心避免丢失精度,因为值可能较小, (0.0000001/0.000000340) 。

为什么从 QPC 返回的时间戳是带符号整数?

涉及 QPC 时间戳的计算可能涉及减法。 通过使用带符号值,可以处理可能会产生负值的计算。

如何从托管代码获取高分辨率时间戳?

System.Diagnostics.Stopwatch 类调用 Stopwatch.GetTimeStamp 方法。 有关如何使用 Stopwatch.GetTimeStamp 的示例,请参阅 从托管代码获取高分辨率时间戳

在什么情况下,QueryPerformanceFrequency 返回 FALSE,或者 QueryPerformanceCounter 返回零?

这不会发生在运行 Windows XP 或更高版本的任何系统上。

是否需要将线程相关性设置为单个核心才能使用 QPC?

不是。 有关详细信息,请参阅 获取时间戳的指南。 此方案既不必要,也不需要。 如果多个线程在调用 QueryPerformanceCounter 时将相关性设置为同一核心,则执行此方案可能会对应用程序的性能产生不利影响,方法是将处理限制为一个核心,或者在单个核心上创建瓶颈。

低级别硬件时钟特征

这些部分显示了低级别硬件时钟特征。

绝对时钟和差异时钟

绝对时钟提供准确的日读数。 它们通常基于协调世界时 (UTC) ,因此其准确性部分取决于同步到外部时间引用的方式。 差异时钟测量时间间隔,通常不基于外部时间纪元。 QPC 是一个差异时钟,不会同步到外部时间纪元或引用。 将 QPC 用于时间间隔度量时,通常比使用从绝对时钟派生的时间戳获得更好的准确度。 这是因为同步绝对时钟时间的过程可能会引入阶段和频率移位,从而增加短期时间间隔度量的不确定性。

分辨率、精度、准确性和稳定性

QPC 使用硬件计数器作为其基础。 硬件计时器由三个部分组成:刻度生成器、计数刻度计数器和检索计数器值的方法。 这三个组件的特征决定了 QPC 的分辨率、精度、准确性和稳定性。

如果硬件生成器以固定速率提供刻度,只需计算这些刻度即可测量时间间隔。 生成时钟周期的速率称为频率,以 Hertz (Hz) 表示。 频率的倒数称为周期或刻度间隔,以适当的国际单位系统 (SI) 时间单位 (表示,例如秒、毫秒、微秒或纳米秒) 。

time interval

计时器的分辨率等于时间段。 解决方法确定区分任意两个时间戳的能力,并将下限放在可测量的最小时间间隔上。 这有时称为刻度解析。

时间的数字测量引入了± 1 刻度的度量不确定性,因为数字计数器在离散步骤中前进,而时间会持续推进。 这种不确定性称为量化错误。 对于典型的时间间隔度量,通常可以忽略此效果,因为量化错误比测量的时间间隔小得多。

digital time measurement

但是,如果所测量的时间段较小且接近计时器的解析,则需要考虑此量化错误。 引入的错误的大小是一个时钟周期的大小。

以下两个关系图演示了使用分辨率为 1 时间单位的计时器来± 1 刻度不确定性的影响。

tick uncertainty

QueryPerformanceFrequency 返回 QPC 的频率,句点和分辨率等于此值的对等值。 QueryPerformanceFrequency 返回的性能计数器频率在系统初始化期间确定,在系统运行时不会更改。

注意

如果 QueryPerformanceFrequency 不返回硬件刻度生成器的实际频率,则可能存在这种情况。 例如,在许多情况下,QueryPerformanceFrequency 返回除以 1024 的 TSC 频率;在 Hyper-V 上,当来宾虚拟机在实现虚拟机监控程序版本 1.0 接口的虚拟机监控程序下运行时,性能计数器频率始终为 10 MHz。 因此,不要假定 QueryPerformanceFrequency 将返回精确的 TSC 频率。

 

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 的两次连续调用返回的值的差值为 5。 两次调用之间花费了多少时间? 5 个刻度乘以 320 纳米秒产生 1.6 微秒。

ElapsedTime = Ticks * 刻度间隔

ElapsedTime = 5 * 320 ns = 1.6μs

访问 (从软件读取) 刻度计数器所需的时间,此访问时间可以减少时间测量的精度。 这是因为最小间隔时间 (可以测量的最小时间间隔,) 是分辨率和访问时间越大。

精度 = MAX [ Resolution, AccessTime]

例如,请考虑具有 100 纳秒分辨率和 800 纳米秒访问时间的假设硬件计时器。 如果使用平台计时器而不是 TSC 注册作为 QPC 的基础,则可能是这种情况。 因此,精度为 800 纳秒,而不是 100 纳秒,如此计算所示。

精度 = MAX [800 ns,100 ns] = 800 ns

这两个数字描绘了这种效果。

qpc access time

如果访问时间大于分辨率,请不要尝试通过猜测来提高精度。 换句话说,假设时间戳在中间或调用的开头或末尾精确执行,这是一个错误。

相比之下,请考虑以下示例,其中 QPC 访问时间仅为 20 纳秒,硬件时钟分辨率为 100 纳秒。 如果 TSC 寄存器用作 QPC 的基础,则可能是这种情况。 此处的精度受时钟分辨率的限制。

qpc precision

在实践中,可以找到读取计数器所需的时间大于或小于分辨率的时间源。 在任一情况下,精度都将是两者中的较大值。

此表提供有关各种时钟的近似分辨率、访问时间和精度的信息。 请注意,某些值因不同的处理器、硬件平台和处理器速度而异。

时钟源 名义时钟频率 时钟分辨率 访问时间 (典型) 精度
电脑 RTC 64 Hz 15.625 毫秒 不适用 不可用
使用具有 3 GHz 处理器时钟的 TSC 查询性能计数器 3 MHz 333 纳米秒 30 纳秒 333 纳米秒
系统上具有 3 GHz 周期时间的 RDTSC 计算机指令 3 GHz 333 picoseconds 30 纳秒 30 纳秒

 

由于 QPC 使用硬件计数器,因此当你了解硬件计数器的一些基本特征时,你将了解 QPC 的功能和限制。

最常用的硬件滴答生成器是水晶晶体晶体。 晶体是一小块硅或其他陶瓷材料,它表现出压电特征,提供廉价的频率参考,具有出色的稳定性和准确性。 此频率用于生成时钟计数的刻度。

计时器的准确性是指符合真实值或标准值的程度。 这主要取决于晶体晶体硅提供指定频率的滴答能力。 如果振荡频率过高,时钟将“快速运行”,测量间隔的显示时间将比实际长:如果频率太低,时钟将“运行缓慢”,测量间隔看起来比它们真的短。

对于持续时间较短的典型时间间隔度量 (例如响应时间度量、网络延迟度量等) ,硬件整容的准确性通常足够。 但是,对于某些度量,振动频率准确度变得很重要,尤其是对于较长的时间间隔,或者想要比较不同计算机上的度量值。 本部分的其余部分探讨准确度的影响。

晶体的振荡频率在制造过程中设置,由制造商根据指定的频率加上或减去以“每百万部分”表示的制造容忍度, (ppm) ,称为最大频率偏移量。 如果其实际频率介于 999,990 Hz 和 1,000,010 Hz 之间的实际频率介于 999,990 Hz 和 1,000,010 Hz 之间,则最大频率偏移量为 ± 1000,010 ppm。

通过将每百万个短语部分替换为秒微秒,我们可以将此频率偏移误差应用于时间间隔度量。 偏移量为 +10 ppm 偏移量时,每秒误差为 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 秒

 

上表显示,对于较小的时间间隔,通常可以忽略频率偏移错误。 但是,在较长的时间间隔内,即使是较小的频率偏移也可能导致大量测量不确定性。

在个人电脑和服务器中使用的晶体晶体通常以频率容忍度±每百万 30 到 50 个零件,很少,晶体可以关闭多达 500 ppm。 虽然具有更严格的频率偏移容差的晶体可用,但它们成本更高,因此在大多数计算机中不使用。

为了减少此频率偏移错误的不利影响,最新版本的Windows(尤其是Windows 8)使用多个硬件计时器来检测频率偏移并尽可能补偿它。 启动Windows时将执行此校准过程。

如以下示例所示,硬件时钟的频率偏移误差会影响可实现的准确性,时钟分辨率可能不那么重要。

frequency offset error influences achievable accuracy

示例 1

假设使用分辨率为 1 微秒的 1 MHz 振动器执行时间间隔测量,最大频率偏移误差为 ±50 ppm。 现在,让我们假设偏移量正好是 +50 ppm。 这意味着实际频率为 1,000,050 Hz。 如果我们测量的时间间隔为 24 小时,则测量时间将太短 4.3 秒, (23:59:55.700000 测量,而不是 24:00:00.000000 实际) 。

一天中的秒数 = 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。 尽管分辨率令人印象深刻,但时间间隔测量时间仍为 4.3 秒太短。 (测量的 23:59:55:55.7000000000000 与 24:00:00.00000000000 实际) 。

一天中的秒数 = 86400

频率偏移错误 = 50 ppm = 0.00005

86,400 秒 * 0.00005 = 4.3 秒

这表明高分辨率 TSC 时钟不一定比分辨率较低的时钟提供更准确的度量。

示例 3

请考虑使用两台不同的计算机来测量相同的 24 小时时间间隔。 这两台计算机都有一个± 50 ppm 的最大频率偏移量。 在这两个系统上测量同一时间间隔的距离有多大? 与前面的示例中一样,± 50 ppm 在 24 小时后的最大错误± 4.3 秒。 如果一个系统运行 4.3 秒快,另一个 4.3 秒慢,则 24 小时后的最大错误可能是 8.6 秒。

一天中的秒数 = 86400

频率偏移错误 = ±50 ppm = ±0.00005

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

两个系统之间的最大偏移量 = 8.6 秒

总之,测量长时间间隔和比较不同系统之间的度量值时,频率偏移误差变得越来越重要。

计时器的稳定性描述了时钟周期频率是否随时间变化,例如温度变化的结果。 用作计算机上的滴答发电机的硅晶体将以温度的作用表现出较小的频率变化。 与常见温度范围的频率偏移误差相比,热偏移引起的误差通常很小。 但是,便携式设备或设备的软件设计者可能需要考虑这种影响。

硬件计时器信息

TSC 寄存器

某些 Intel 和 AMD 处理器包含 TSC 寄存器,该寄存器是一个 64 位寄存器,该寄存器以高速率增加,通常等于处理器时钟。 可以通过 RDTSCRDTSCP 计算机指令读取此计数器的值,根据处理器,按数十或数百台计算机周期的顺序提供非常低的访问时间和计算成本。

尽管 TSC 寄存器似乎是一种理想的时间戳机制,但在这种情况下,它无法可靠地执行计时目的:

  • 并非所有处理器都有 TSC 寄存器,因此在软件中使用 TSC 寄存器直接会产生可移植性问题。 在这种情况下, (Windows将为 QPC 选择替代时间源,从而避免可移植性问题。)
  • 某些处理器可能会改变 TSC 时钟的频率或停止 TSC 寄存器的进步,这使得 TSC 不适合这些处理器的计时目的。 据说这些处理器具有非固定 TSC 寄存器。 (Windows会自动检测此情况,并为 QPC) 选择备用时间源。
  • 在多处理器或多核系统上,某些处理器和系统无法将每个核心上的时钟同步到相同的值。 (Windows会自动检测此情况,并为 QPC) 选择备用时间源。
  • 在某些大型多处理器系统上,即使处理器具有固定 TSC,也可能无法将处理器时钟同步到相同的值。 (Windows会自动检测此情况,并为 QPC) 选择备用时间源。
  • 某些处理器将按顺序执行指令。 当 RDTSC 用于时间指令序列时,这可能会导致周期计数不正确,因为 RDTSC 指令可能在与程序中指定的时间不同时执行。 RDTSCP 指令已在一些处理器上引入,以响应此问题。

与其他计时器一样,TSC 基于一种晶体晶体,其确切频率在提前未知且有频率偏移误差。 因此,在使用之前,必须使用另一个计时引用对其进行校准。

在系统初始化期间,Windows检查 TSC 是否适合计时目的,并执行必要的频率校准和核心同步。

PM 时钟

ACPI 计时器(也称为 PM 时钟)已添加到系统体系结构中,以独立于处理器速度提供可靠的时间戳。 由于这是此计时器的单一目标,因此它在单个时钟周期中提供时间戳,但它不提供任何其他功能。

HPET 计时器

Intel 和 Microsoft 联合开发的高精度事件计时器 (HPET) ,以满足多媒体和其他时间敏感应用程序的计时要求。 HPET 支持自 Windows Vista 以来一直处于Windows中,Windows 7 和 Windows 8 硬件徽标认证要求在硬件平台中提供 HPET 支持。