假设我用编译语言(例如C ++)编写自己的StringBuilder
。
衡量各种实施表现的最佳方法是什么?简单地计算几十万次运行会产生高度不一致的结果:从一个批次到另一个批次的时间差异可能高达15%,这使得无法准确评估潜在的性能改进,从而产生比这更小的性能增益。
我做了以下事情:
这有点稳定了结果。还有其他想法吗?
答案 0 :(得分:7)
我以这种方式取得了100%一致的结果:
cli
/ sti
指令包装基准代码(请注意,此更改后二进制文件不会在现代操作系统上运行。)rdtsc
增量进行计时。样本应在cli
... sti
说明中。
结果似乎完全是确定性的,但不是对整体表现的准确评估(详见Osman Turan答案的讨论)。
作为奖励提示,这是与Bochs共享文件的简单方法(因此您不必每次都卸载/重建/重新安装软盘映像):
在Windows上,Bochs将锁定软盘映像文件,但该文件仍以共享写入模式打开。这意味着您无法覆盖该文件,但您可以写入该文件。 (我认为* nix操作系统可能会导致覆盖创建一个新文件,就文件描述符而言。)诀窍是使用dd
。我设置了以下批处理脚本:
... benchmark build commands here ...
copy /Y C:\Path\To\Benchmark\Project\test2dos.exe floppy\test2.exe
bfi -t=288 -f=floppysrc.img floppy
dd if=floppysrc.img of=floppy.img
bfi
是Bart的Build Floppy Image。
然后,只需在Bochs中安装floppy.img
。
奖金提示#2:为避免每次在Bochs中手动启动基准测试,请在软盘目录中放置一个空go.txt
文件,然后在Bochs中运行此批处理:
@echo off
A:
:loop
choice /T:y,1 > nul
if not exist go.txt goto loop
del go.txt
echo ---------------------------------------------------
test2
goto loop
每次检测到新的软盘映像时,它都会启动测试程序。这样,您就可以在单个脚本中自动执行基准测试。
更新:此方法不太可靠。有时通过重新排序某些测试,时间会改变200%(使用原始问题中描述的方法在真实硬件上运行时未观察到这些时序变化)。
答案 1 :(得分:1)
我过去一直关注这个问题,而且我已经认识到只有一个完美理想的解决方案,虽然需要大量的工作,(主要是准备工作) ,)所以我从来没有这样做过。
解决方案是使用386仿真器运行代码,该仿真器将告诉您确切执行了多少操作。你应该能够在那里找到一个开源的386仿真器。它对指令是准确的,并且需要一次测试。如果你这样做,请发布你的表现!
答案 2 :(得分:1)
精确测量一段代码真的很难。对于此类要求,我建议您查看Agner Fog's test suite。通过使用它,您可以测量时钟周期并收集一些重要因素(例如缓存未命中,分支错误预测等)。
另外,我建议您查看Agner网站上的PDF document。这是一个非常宝贵的文档,可以实现这种微优化。
作为旁注,实际性能不是“时钟周期”的函数。缓存未命中可以改变实际应用程序中每次运行的所有内容。所以,我会首先优化缓存未命中。只需为相同的内存部分多次运行一段代码,就可以大大减少缓存未命中。因此,它很难精确测量。整个应用程序调整通常是更好的想法IMO。英特尔VTune和其他工具非常适合这种用法。