CCPUTicker v1.22 - 精确计时






4.44/5 (9投票s)
2000 年 3 月 4 日

157355

2080
适用于 Pentium 或更高 CPU 的超高精度 MFC 计时类。
引言
欢迎使用CCPUTicker
,这是一款适用于 Pentium 或更高 CPU 的超高精度 MFC 计时类,可用于分辨率计时。
特点 |
历史 |
API 参考 |
用法 |
联系作者 |
特点
此类实现了一个 MFC 封装类,用于 Pentium 特定的时间戳计数器,该计数器可以使用RDTSC
汇编语言指令进行访问。此计数器的分辨率以 PCLKS(处理器时钟)为单位,因此如果您拥有一个 200 MHz 的 CPU,此类将提供 200 MHz 的频率。返回的值是一个 64 位整数,因此假设您的 CPU 运行频率为 200 MHz,则该值大约需要 3000 年才能回绕。由于该值也从 0 开始计数,因此返回的值是自计算机开机以来经过的 CPU 滴答数,即“开机”时间。由于计时器是 CPU 硬件的一部分,因此不受处理器活动和工作负载的影响。此类仅在 Intel CPU 上进行了测试。欢迎提供关于其在其他 CPU 类型上行为的反馈。此类也可以在 Windows NT 上毫无问题地使用。
此类本身最初由 J.M.McGuiness 开发,并由两位作者共同开发。
源 zip 文件包含 CCPUTicker
源代码,还包含一个简单的基于 MFC 消息框的演示应用程序,该应用程序将计时 SDK 调用 Sleep(1000)
的精度,并报告您的计算机已“开机”多长时间。
历史
V1.0(1996 年 3 月 26 日)- 由 J.M.McGuiness 初次创建该类。
V1.1(1997 年 7 月 16 日)
- 支持在 Windows NT 上运行。
- 现在使用内置的 64 位数据类型
__int64
。 - 得益于上述改进,诊断信息得到了增强。
- 使用静态变量以提高效率。
- 添加了一个可以将 CPU 滴答数转换为秒的函数。
- 改进了对 MFC 编码风格和标准的遵循。
V1.2(1999 年 1 月 14 日)
- 修复了 David Green-Seed 发现的一个 bug,他在该 bug 中,当代码在 Pentium II 上启用优化编译时,会遇到访问冲突。问题在于(在 PII 上)
RDTSC
指令触及的寄存器比预期要多。现在通过在调用RDTSC
周围保存和恢复 EAX 和 EBX 寄存器来修复了此问题。 - 为该类提供了 HTML 文档(本文档)。
- 现在标配提供了一个 Visual C++ 5.0 工作区文件。
- 代码现在可以在警告级别 4 下干净地编译。
- 对 const 函数、参数等进行了通用代码清理。
- 示例程序现在还报告计算机的“开机”时间。
V1.21(1999 年 1 月 14 日)
- 未包含任何代码更改。仅更新了帮助文件,其中包含一些可能引起
CCPUTicker
用户兴趣的开发说明。
1999 年 1 月 21 日
- 未包含任何代码更改。仅更新了本文档,说明在 SMP 机器上的使用情况。
1999 年 1 月 27 日
- 未包含任何代码更改。仅更新了本文档,说明在 SMP 机器上的使用情况。
v1.22(1999 年 12 月 3 日)
- 修复了在 VC 6 中以发布模式编译时出现的一个问题。
API 参考
API 由CCPUTicker
类的以下公共方法组成
CCPUTicker()
operator=()
Measure()
GetTickCountAsSeconds()
GetTickCount()
GetCPUFrequency()
IsAvailable()
AssertValid()
Dump()
- CCPUTicker::CCPUTicker
- CCPUTicker();
CCPUTicker(const CCPUTicker &ticker);参数
- ticker -- CCPUTicker 的另一个实例
备注
类的标准构造函数和复制构造函数,它们仅初始化一些内部变量。 - CCPUTicker::operator=
- CCPUTicker& operator=(const CCPUTicker &ticker);
参数
- ticker -- CCPUTicker 的另一个实例
返回值
C++ operator= 函数的标准 this 指针引用。备注
类的标准 operator=。 - CCPUTicker::Measure
- void CCPUTicker::Measure();
备注
调用此函数可将 RDTSC 计数器的当前值检索到此 CCPUTicker 实例中。 - CCPUTicker::GetTickCountAsSeconds
- double GetTickCountAsSeconds() const;
返回值
以秒为单位的当前 RDTSC 计数器值。备注
调用此函数可从该实例检索以秒为单位存储的 RDTSC 计数器值。秒数是计算机的“开机”时间。由于计数器以时钟滴答数存储,因此当您的任何代码首次调用此函数时,处理器时钟频率将使用内部计时例程进行估算。请注意,这可能会导致当前进程挂起长达 20 秒。有关此函数的开发注意事项,请参阅下面的用法部分。 - CCPUTicker::GetTickCount
- __int64 CCPUTicker::GetTickCount() const;
返回值
以时钟滴答数为单位的当前 RDTSC 计数器值。备注
调用此函数可从该实例检索以时钟滴答数为单位存储的 RDTSC 计数器值。此函数是对类在其上次调用 Measure 方法时获得的值的简单访问器。 - CCPUTicker::GetCPUFrequency
- static BOOL GetCPUFrequency(double& frequency, double& target_ave_dev, unsigned long interval = 1000, unsigned int max_loops = 20) const;
参数
- frequency -- 成功返回后,将包含处理器时钟频率(赫兹)。
- target_ave_dev -- 成功返回后,将包含处理器时钟频率的估计平均偏差(赫兹)。
- interval -- 每个计时循环的间隔(毫秒)。
- max_loops -- 用于估算处理器时钟频率的最大计时循环次数。
返回值
如果 CPU 频率成功返回,则为 TRUE,否则为 FALSE。如果发生这种情况,请使用GetLastError()
确定原因。备注
此函数将处理器时钟频率计算到由目标平均偏差决定的特定精度。请注意,对于 90 MHz 的平均频率,结果的最坏平均偏差小于 5 MHz。因此,目标平均偏差仅在您需要更精确的结果时提供,它不会让您获得更差的结果。(单位是 Hz)。平均偏差比其近亲标准偏差更好、更稳健的度量。两者确定的项目本质上是相似的。有关更多详细信息,请参阅“数值食谱”(W.Press 等人)。此函数默认最多运行 20 秒,然后放弃改进平均偏差,实际实现的平均偏差将替换提供的目标值。使用“max_loops”进行更改。要提高函数收敛的值,请增加“interval”(单位是 ms,默认值为 1000ms)。有关此函数的开发注意事项,请参阅下面的用法部分。 - CCPUTicker::IsAvailable
- BOOL IsAvailable() const;
返回值
如果此计算机具有用于计时的“RDTSC”指令,则为 TRUE,否则为 FALSE。 - CCPUTicker::AssertValid
- virtual void AssertValid() const;
备注
标准 MFC 诊断函数。 - CCPUTicker::Dump
- virtual void Dump(CDumpContext& dc) const;
备注
标准 MFC 诊断函数。
用法
示例应用程序是一个简单的基于 MFC 消息框的演示,它将计时 SDK 调用Sleep(1000)
的精度,并报告您的计算机已“开机”多长时间。要在您的项目中使用的 CCPUTicker
,只需在测试应用程序中包含 cputicker.cpp 到您的应用程序中,并在您想使用该类的任何文件中 #include "cputicker.h"
。
在开发使用 CCPUTicker
的代码时,应牢记以下几点:
- 在 SMP 机器(对称多处理机器)上使用,即具有 2 个或更多 CPU 的 NT
- 考虑以下场景:我们打算通过两次读取 RDTSC 并使用差值/频率来获得某个时间(真实时间)的度量。假设第一次读取是从 CPU0 读取的,第二次读取是从 CPU1 读取的(进程不一定始终在同一 CPU 上运行)。由于 CPU 的 RDTSC 指令是独立的,一个 CPU 上的 RDTSC 与另一个 CPU 上的 RDTSC 完全无关,因此读数将完全无关!您应该在应用程序级别解决此问题。可以通过调用 GetSystemInfo SDK 函数并检查返回结构中的 dwNumberOfProcessors 来检测 SMP 机器。您还应该查看 SetProcessAffinityMask 函数,以确保您的代码始终只在一个 CPU 上运行。
- 关于 APM、ACPI、CPU 过热
- 在许多机器上,CPU 的时钟速度可以被这些技术减慢(然后再次提高)。因此,从时钟周期计算实际时间可能无效。(假设在第一次和第二次读取之间更改了时钟,或者假设时钟频率在一个速度下计算,然后又发生了更改……)。请注意,调用 GetCPUFrequency 和 GetTickCountAsSeconds 取决于计时器期间 CPU 频率的不变性。如果 CPU 频率随时间变化,则报告为秒的内容可能不准确。如果您只想检索计算机的开机时间,则应使用 GetTickCount SDK 函数。
联系作者
PJ Naughter电子邮件: pjn@indigo..ie
Web: