我使用标准库为我的Haskell函数编写基准测试。现在,我正在在C中实现相同的算法,以将性能与Haskell进行比较。问题是我该如何可靠地做?Criterion做了很多花哨的事情,例如会计时钟呼叫开销和对结果进行统计分析。我想,如果我只测量C函数所需的时间,它将与标准返回的结果相提并论。布莱恩·奥沙利文(Bryan O'Sullivan)在他的原始文章中写道:"甚至应该很容易使用标准来基准C代码和命令行程序。"问题是如何?takayuki muranushi通过产卵线程并调用可执行文件将DFT的C实现与Haskell进行了比较,但我担心这会增加很多额外的开销(创建新线程,运行应用程序,运行应用程序,输出到STDIO,然后从中读取),这使结果无与伦比。我还考虑使用FFI,但我再次担心,额外的开销会使这种比较不公平。
如果无法使用标准可靠地基准C,那么您会推荐哪些方法进行基准测试?我在这里阅读了一些问题,看来有许多不同的功能可以衡量系统时间,但是它们要么以毫秒为单位,要么在开销上都有大的呼叫。
ffi可以以这种方式使用,以至于它不会添加太多开销。考虑以下程序(此处可用的完整代码):
foreign import ccall unsafe "mean" c_mean :: Ptr CInt -> CUInt -> IO CFloat
main :: IO ()
main = do
buf <- mallocBytes (bufSize * sizeOfCInt)
fillBuffer buf 0
m <- c_mean buf (fromIntegral bufSize)
print $ realToFrac m
c调用被编译为以下CMM:
s2ni_ret() { ... }
c2qy:
Hp = Hp + 12;
if (Hp > I32[BaseReg + 92]) goto c2qC;
_c2qD::I32 = I32[Sp + 4];
(_s2m3::F32,) = foreign "ccall"
mean((_c2qD::I32, PtrHint), (100,));
这是集会:
s2ni_info:
.Lc2qy:
addl $12,%edi
cmpl 92(%ebx),%edi
ja .Lc2qC
movl 4(%ebp),%eax
subl $4,%esp
pushl $100
pushl %eax
ffree %st(0) ;ffree %st(1) ;ffree %st(2) ;ffree %st(3)
ffree %st(4) ;ffree %st(5)
call mean
因此,如果您将C导入标记为unsafe
,并且在测量前进行所有编组,则您的C调用基本上只是一个内联call
指令 - 就像您在C中进行所有基准测试。基准一个无助的C函数:
benchmarking c_nothing
mean: 13.99036 ns, lb 13.65144 ns, ub 14.62640 ns, ci 0.950
std dev: 2.306218 ns, lb 1.406215 ns, ub 3.541156 ns, ci 0.950
found 10 outliers among 100 samples (10.0%)
9 (9.0%) high severe
variance introduced by outliers: 91.513%
variance is severely inflated by outliers
这比我的计算机上的估计时钟分辨率(〜5.5 US)小约400倍。为了进行比较,这是计算100个整数的算术平均值的函数的基准数据:
benchmarking c_mean
mean: 184.1270 ns, lb 183.5749 ns, ub 185.0947 ns, ci 0.950
std dev: 3.651747 ns, lb 2.430552 ns, ub 5.885120 ns, ci 0.950
found 6 outliers among 100 samples (6.0%)
5 (5.0%) high severe
variance introduced by outliers: 12.329%
variance is moderately inflated by outliers