【问题标题】:Is there a standard constant *nix benchmark, and if not, how to make a `bogobench`?是否有标准常量 *nix 基准,如果没有,如何制作“bogobench”?
【发布时间】:2017-03-18 19:44:21
【问题描述】:

普通的单线程*nix程序可以用time之类的工具进行基准测试,即:

# how long does `seq` take to count to 100,000,000
/usr/bin/time seq 100000000 > /dev/null

输出:

1.16user 0.06system 0:01.23elapsed 100%CPU (0avgtext+0avgdata 1944maxresident)k
0inputs+0outputs (0major+80minor)pagefaults 0swaps

...但是返回的数字始终取决于系统,这在某种意义上也衡量了用户的硬件。

是否有一些非相对的基准测试方法或命令行实用程序可以在任何系统(或至少相当大的系统子集)上返回大致相同的虚拟计时数?就像grep -m1 bogo /proc/cpuinfo 返回a roughly approximate but stable unit 一样,这样的基准测试也应该返回一个有点相似的持续时间单位。

假设为了对普通命令进行基准测试,我们有一个神奇的工具 bogobench(其中“bogo”是一个表示“有点虚假的状态”的形容词,但不一定有BogoMIPs 的共同算法):

bogobench foo bar.data

我们在两个物理上独立的系统上运行它:

  1. 1996 奔腾 II
  2. 2015 至强

所需的输出类似于:

21 bogo-seconds

所以bogobench 在这两种情况下应该返回大致相同的数字,即使它在第二个系统上可能会在更短的时间内完成。


qemu 这样的硬件模拟器可能是一种方法,但不一定是唯一的方法:

  1. 将要进行基准测试的代码插入包装脚本bogo.sh
  2. bogo.sh 复制到可引导的Linux 磁盘映像bootimage.iso,在bogo.sh 将自动运行的目录中,然后立即关闭模拟器。在此期间,它会输出某种形式的计时数据以解析为 bogo-seconds
  3. 使用qemu 的最小-machine 选项之一运行bootimage.iso

    qemu-system-i386 -machine type=isapc bootimage.iso
    

但我不确定如何让qemu 使用虚拟时钟,而不是主机 CPU 的时钟,而qemu 本身对于看似简单的任务来说似乎是一个沉重的工具。 (对于这样的任务,真的 MAMEMESS 将是比 qemu 更通用的模拟器 - 但我不擅长 MAME,虽然 MAME currently has some capacity for 80486 PC emulation.)

在线我们有时会比较和对比在机器 X 上进行的基于时间的基准测试和在 机器 Y 上进行的基准测试。而我希望用户 XY 都能够在虚拟 machine Z 上进行基准测试,并获得奖励积分来模拟 X 或 Y(如 MAME)如果需要,除非不考虑 XY 的真实运行时间,(与 MAME 不同,其中仿真通常可以播放)。通过这种方式,用户可以报告程序在有趣的情况下的执行情况,而程序员不必担心结果会因用户硬件的特性而产生偏差,例如 CPU 怪癖、后台进程占用资源等。

确实,即使在用户自己的硬件上,基于time 的基准测试也可能不可靠,因为用户通常无法确定某些后台进程(或错误或硬件错误,例如坏扇区或病毒)可能不会降低性能的某些方面。而更虚拟的基准应该不太容易受到这种影响。

【问题讨论】:

  • 没有。你想测量什么?基准是无限可替代的;跨机器的结果很少具有可比性。您的测试假设有多少 CPU?机器上有多少内存?测试使用了多少内存?机器上有多少磁盘?它有多快?它有多固态?测试运行时还发生了什么?等等等等。恐怕问题是,太宽泛了,不适合 SO。
  • 啊,standards.
  • @shellter,我稍微调整了 OP。这样一个 util 的价值是如此普遍,以至于它就像要求 bc 的特定用途一样。一种非常规的用法可能被称为反向基准测试,其中系统Y可以尝试计算一个合理的良好估计值(实时) util 需要在 system X 上运行。
  • @PeterCordes,感谢您的反馈和投票——我想要一个相当近似但不一定完美的非主观命令行基准工具。 如何它可能工作是次要的。 emulator/simulator 想法是一种方法,但认为它是唯一 可能的方法似乎还为时过早——我将 emulators 更多地称为“ brute force”方法来证明它在技术上并非不可能。同意 模拟 可能不完美,但这并不意味着它完全无用或无法改进。
  • 编译器优化不相关,因为它与错误的抽象级别有关——要消除这个级别,只需假设 foo 包括将寄存器递增 100000000 次,即假设foo 可证明不受编译器优化的影响。所以bogobench 会测量那个级别的代码。 任何代码可能被优化(无论是手动还是编译器——最终都是手动完成的,因为人类编写编译器)这一事实并不相关。

标签: linux time emulation benchmarking qemu


【解决方案1】:

我认为实现这一点的唯一合理方法是使用用于某种硬件设计的周期精确模拟器。

AFAIK,不存在针对现代 x86 硬件的公开可用的周期精确模拟器,因为它非常复杂,尽管已知很多关于 x86 微架构内部的东西(Agner Fog 的东西,英特尔和 AMD 自己的优化指南,和 标签 wiki 中的其他内容),足够的行为仍然是一个充满 CPU 设计商业秘密的黑匣子,充其量只能模拟类似的东西。 (例如,分支预测绝对是最秘密但非常重要的部分之一)。

虽然应该可以接近模拟 Intel Sandybridge 或 Haswell 的实际管道和无序内核/ROB/RS(比实时慢得多),但据我所知,没有人做过。


但其他硬件设计的周期精确模拟器确实存在Donald Knuth's MMIX architecture 是一个干净的 RISC 设计,实际上可以在硅片中构建,但目前只存在于纸。

从那个链接:

特别感兴趣的是 MMMIX 元模拟器,它能够对复杂的管道进行动态调度,允许使用任意数量的功能单元以及多种缓存和分支预测等进行超标量执行,包括详细的实现硬中断和软中断。

因此,您可以将其用作每个人运行基准测试的参考机器,每个人都可以获得可比较的结果,这些结果将告诉您在 MMIX 上运行的速度有多快(在使用 gcc 为 MMIX 编译之后)。但不是它在 x86 上运行的速度有多快(可能也使用 gcc 编译),即使对于以不同方式完成相同工作的两个程序,这也可能存在显着差异。


针对编程难题和 Code Golf 网站上的 [fastest-code] 挑战,@orlp created the GOLF architecture with a simulator that prints timing results 正是为此目的而设计的。这是一个玩具架构,通过存储到0xffffffffffffffff 来打印到标准输出等内容,因此它不一定会告诉您任何东西在任何真实硬件上的运行速度。

没有针对 GOLF、AFAIK 的完整 C 实现,因此您只能将它与手写 asm 一起使用。这与优化编译器所针对的 MMIX 有很大不同。

【讨论】:

  • 公平地说,您并不真的需要现代 x86 硬件的周期精确模拟器来满足 OPs bogobench 的至少某些用途。您只需要一个涵盖足够您试图定位的硬件类型的行为的模拟器。例如,只需将宽度和指令延迟固定在一些合理的值,并使用合理的缓存模型。假设这是一个长期稳定的基准测试工具,您甚至不会真的想要编码太多当前的怪癖,因为它们会随着时间而变化。
  • 例如,如果您在早期 Pentium 的指令配对的怪癖中编程,那么今天它不会很有用。 x86 的趋势在很多方面似乎都朝着更通用的调度、更多标准延迟、更少的疯狂停顿等方向发展。因此,一个相当简单的模型可能与 10 年后的机器一样接近或更接近,而不是 Haswell 的周期精确模拟。
  • @BeeOnRope:是的,接近准确就足够了,我同意减少怪癖的趋势可能会继续下去。我的观点是,针对当前硬件以外的东西进行调整并不一定能帮助您在当前的真实硬件上快速运行,并使用当前的真实编译器对其进行调整。否则,请选择任何东西,例如 MMIX。不过,让它在某种程度上接近您关心的硬件是很有用的,特别是如果您可以合理地对缓存行为进行建模,理想情况下甚至可以模拟具有实际同步成本的多核机器。
  • 我可以看到很多非常棒的用途,除了调优。例如,您目前无法真正编写测试性能回归的持续集成测试,因为您没有稳定的确定性基准函数:long time = f(x86 binary) 每次都输出相同的数字。 实际上计时代码对于通过/失败的事情来说不够稳定,并且在机器之间不一致(甚至在一台机器上运行时不一致),但是这个 bogobench 会给出每次都是一样的结果。世界上每个人都可以得到相同的结果。
  • 想想IACA - 尽管非常有限,它已经非常有用(特别是它不运行代码,所以它只对基本块有用)。这就像类固醇上的 IACA。您还可以想象它对于诸如 STOKE 之类的东西的“成本”函数或通常任何需要确定性性能数字的东西很有用。当然,它永远不会取代用于调优目的的实际测试。
【解决方案2】:

一种可以(也许?)随着时间推移变得更加准确的实用方法是使用现有工具来测量被测代码的一些硬件不变性能指标,然后应用公式得出您的bogoseconds 分数。

不幸的是,最容易测量的硬件指标并非不变 - 相反,它们取决于硬件。然而,一个明显的应该是不变的,是“指令退休”。如果代码每次运行都采用相同的代码路径,则所有硬件上的指令退出计数应该相同1

然后你应用某种标称时钟速度(比如 1 GHz)和标称 CPI(比如 1.0)来获得你的 bogoseconds - 如果你测量 15e9 指令,你输出的结果是 15 bogoseconds。

这里的主要缺陷是名义 CPI 可能与实际 CPI 相差甚远!虽然大多数程序徘徊在 1 CPI 左右,但很容易找到它们可以接近 0.25 或任何宽度的倒数的示例,或者如果有许多冗长的停顿,则可以选择为 10 或更多。当然,这样的极端程序可能是您想要进行基准测试的 - 即使您没有问题,如果您使用基准测试来评估代码更改,它将忽略 CPI 的任何改进或回归,并且只查看指令数.

尽管如此,它仍然可以满足您的要求,因为它有效地模拟了一个每个周期恰好执行 1 条指令的机器,这也许是一种合理的宽泛方法。使用 perf stat -e instructions 之类的工具很容易实现(比如 one-liner easy)。

要修补漏洞,您可以尝试使公式更好 - 假设您可以添加缓存未命中的因素来解释大量的停顿来源。不幸的是,您将如何以硬件不变的方式测量缓存未命中?性能计数器无济于事——它们依赖于本地缓存的行为和大小。好吧,您可以使用cachegrind 以独立于机器的方式模拟缓存。事实证明,cachegrind 甚至涵盖了分支预测。因此,也许您可​​以将指令计数、缓存未命中和分支未命中数代入一个更好的公式(例如,使用典型的 L2、L3、RAM 延迟和分支未命中的典型成本)。

我想这就是这个简单的方法所能带给你的。之后,您不妨拆开任何现有的 x862 模拟器,并在其中添加您的简单机器模型。您不需要精确循环,只需选择一个标称宽度并对其进行建模。可能无论底层仿真 cachegrind 是什么都可能是一个很好的匹配,并且您已经免费获得了缓存和分支预测建模。


1当然,这不排除指令计数机制中的错误或不准确。

2 你没有标记你的问题x86 - 但我假设这是你的目标,因为你只提到了英特尔芯片。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-19
    • 2017-02-17
    • 1970-01-01
    • 1970-01-01
    • 2014-08-24
    • 1970-01-01
    相关资源
    最近更新 更多