c++ - 找出 CPU 时钟频率(每个内核、每个处理器)

标签 c++ cpu cpu-speed

CPUz 之类的程序非常擅长提供有关系统的深度信息(总线速度、内存时序等)

但是,是否有一种编程方法可以计算每个内核(以及每个处理器,在每个 CPU 具有多个内核的多处理器系统中)频率,而无需处理 CPU 特定信息。

我正在尝试开发一种反作弊工具(用于时钟有限的基准测试竞赛),它能够在系统中所有事件内核(跨所有处理器)的基准测试运行期间记录 CPU 时钟。

最佳答案

我将在这里扩展我的评论。这对我来说太大而深入,无法放入评论中。

您尝试做的事情非常困难 - 由于以下原因而变得不切实际:

  • 没有可移植的方法来获取处理器频率。 rdtsc 不是 由于 SpeedStep 和 Turbo Boost 等效果,始终提供正确的频率。
  • 所有已知的测量频率的方法都需要准确的时间测量。然而,一个坚定的作弊者可以篡改系统中的所有时钟和计时器。
  • 以防篡改的方式准确读取处理器频率和时间将需要内核级访问。这意味着 Windows 的驱动程序签名。


  • 没有获得处理器频率的可移植方法:

    获取 CPU 频率的“简单”方法是调用 rdtsc 两次,中间有固定的持续时间。然后除以差异将为您提供频率。

    问题是rdtsc没有给出处理器的真实频率。因为游戏等实时应用依赖于它,rdtsc需要通过 CPU 节流和 Turbo Boost 保持一致。所以一旦你的系统启动,rdtsc将始终以相同的速率运行(除非你开始用 SetFSB 或其他东西来弄乱总线速度)。

    例如,在我的 Core i7 2600K 上,rdtsc将始终在 3.4 GHz 处显示频率.但实际上,它在1.6 GHz处闲置和时钟高达 4.6 GHz通过超频 Turbo Boost 倍频器在负载下 46x .

    但是,一旦找到测量真实频率的方法(或者您对 rdtsc 感到满意),您就可以使用 thread-affinities 轻松获得每个内核的频率。 .

    获取真实频率:

    要获得处理器的真实频率,您需要访问 MSR(特定于模型的寄存器)或硬件性能计数器。

    这些是内核级指令,因此需要使用驱动程序。如果您出于分发目的在 Windows 中尝试此操作,则您需要通过正确的驱动程序签名协议(protocol)。此外,代码会因处理器品牌和型号而异,因此您需要为每一代处理器提供不同的检测代码。

    一旦到了这个阶段,有多种方法可以读取频率。

    在 Intel 处理器上,硬件计数器可让您计算原始 CPU 周期。结合精确测量实时的方法(下一节),您可以计算出真实频率。通过 MSR,您可以访问其他信息,例如 CPU 倍频器。

    所有已知的频率测量方法都需要准确的时间测量:

    这也许是更大的问题。您需要一个计时器才能测量频率。有能力的黑客将能够篡改您可以在 C/C++ 中使用的所有时钟。
    这包括以下所有内容:
  • clock()
  • gettimeofday()
  • QueryPerformanceCounter()
  • 等等...

  • 这份 list 不胜枚举。换句话说,您不能相信任何计时器,因为有能力的黑客将能够欺骗所有计时器。例如 clock()gettimeofday()可以通过直接在操作系统内更改系统时钟来欺骗。糊涂QueryPerformanceCounter()更难。

    获得真正的时间测量:

    上面列出的所有时钟都很脆弱,因为它们通常以某种方式从同一个系统基本时钟派生而来。并且该系统基本时钟通常与系统基本时钟相关联 - 可以在系统启动后通过超频实用程序进行更改。

    因此,获得可靠且防篡改的时间测量的唯一方法是读取外部时钟,例如 HPETACPI .不幸的是,这些似乎也需要内核级访问。

    总结:

    构建任何类型的防篡改基准几乎肯定需要编写内核模式驱动程序,该驱动程序需要为 Windows 进行证书签名。对于随意的基准测试作者来说,这通常是太多的负担。

    这导致了防篡改基准的短缺,这可能是近年来竞争性超频社区整体衰落的原因之一。

    关于c++ - 找出 CPU 时钟频率(每个内核、每个处理器),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8351944/

    相关文章:

    .net - 标准 C++ 中的垃圾收集是自动的吗?

    performance - 使用 CPU 与 GPU 训练模型 - 速度与内存

    performance - 在大多数现代 64 位处理器上, `mulq` 的速度是否取决于操作数?

    c++ - 将大文件保存到 char 数组中是否正确?

    c++ - Win32 中的全局(进程范围)属性

    c++ - 如何为变化的 `std::map` 计算签名

    android - 如何在 Android 屏幕关闭时让 CPU 远离 'sleeping'?

    performance - 如何计算CPU的理论峰值性能

    c++ - 使用伪代码协助 C++(溢出/下溢)

    c - MLF 是一种公平的调度协议(protocol)吗?