我正在评估我的项目中的网络+渲染工作负载。
该程序持续运行一个主循环:
while (true) {
doSomething()
drawSomething()
doSomething2()
sendSomething()
}
主循环每秒运行超过60次。
我想看到性能分析,每个过程需要多少时间。
我担心如果我打印每个过程的进入和退出的时间间隔,会导致巨大的性能开销。
我好奇什么是一种惯用的性能测量方法。
打印日志足够好吗?
我正在评估我的项目中的网络+渲染工作负载。
该程序持续运行一个主循环:
while (true) {
doSomething()
drawSomething()
doSomething2()
sendSomething()
}
主循环每秒运行超过60次。
我想看到性能分析,每个过程需要多少时间。
我担心如果我打印每个过程的进入和退出的时间间隔,会导致巨大的性能开销。
我好奇什么是一种惯用的性能测量方法。
打印日志足够好吗?
或者,如果您坚持要计时每个单独的迭代,请将结果记录在数组中并稍后打印;您不希望在循环内调用重量级的打印代码。
这个问题太广泛了,无法提供更具体的信息。
许多编程语言都有基准测试包,可帮助您编写单个函数的微型基准测试。例如,对于Java,JMH会确保测试函数在进行定时运行之前已经预热并完全优化,并计算完成了多少次迭代。请参见如何编写正确的Java微型基准测试?获取更多信息。请使用它们。未预热代码/数据缓存等会导致在定时区域内触摸新内存或代码/数据缓存未命中的页面错误,这不是正常操作的一部分。(注意此效应的示例:性能:memset; 或者基于此错误的错误结论的示例)
如果没有写入过的内存(从内核获取的新内存)在读取时会将其所有页面复制到同一个系统范围的物理页面(4K或2M)上,该页面全为零。至少在Linux上是这样。因此,您可以获得高速缓存命中但TLB未命中。例如,来自new
/calloc
/malloc
的大型分配,或在.bss
的静态存储中的零初始化数组。使用非零初始化器或memset。
未给CPU时间以达到最大Turbo的故障:现代CPU会降低时钟速度以节省电力,在几毫秒后才会升高。(或更长,具体取决于操作系统/硬件)。
相关:在现代x86上,RDTSC计数参考周期,而不是核心时钟周期,因此它受到与挂钟时间相同的CPU频率变化效应的影响。
大多数整数和FP算术asm指令(除了除法和平方根,它们已经比其他指令慢)的性能(延迟和吞吐量)不取决于实际数据。除了次标准称为非正常浮点非常缓慢,在某些情况下(例如遗留x87但不是SSE2),还会产生NaN或Inf可能很慢。
在具有乱序执行的现代CPU上,有些东西太短而不能真正有意义地计时, 另请参见这个问题。一个小的汇编语言块的性能(例如由一个函数生成的编译器)不能用单个数字来描述,即使它不分支或访问内存(因此没有误判或缓存未命中的机会)。它具有从输入到输出的延迟,但如果使用独立输入重复运行,则具有不同的吞吐量更高。例如,Skylake CPU上的add
指令具有4/时钟吞吐量,但具有1周期延迟。因此,在循环中dummy = foo(x)
可以比x = foo(x);
快4倍。浮点指令的延迟比整数高,因此通常更重要。大多数CPU上的内存访问也是流水线化的,因此循环访问数组(易于计算下一个加载的地址)通常比遍历链接列表(下一个加载的地址直到前一个加载完成后才可用)快得多。
显然,性能可能因CPU而异;在大局观中,通常Intel上版本A较快,AMD上版本B较快,但在小规模中这很容易发生。在报告/记录基准测试数字时,请始终注意您测试的CPU。
与上述和下述点相关:一般情况下无法“基准测试C中的
与上述最后一点相关:如果函数的真实用例包括很多小输入,请不要仅针对大输入进行调整。
例如,一个memcpy
实现,虽然对于大输入非常好,但是要花费太长时间来确定如何处理小输入,可能不是很好。这是一个权衡;确保它足够好的大输入(对于“足够”的适当定义),但同时也确保小输入的开销较低。
检验方法:
如果在同一个程序中对两个函数进行基准测试:如果颠倒测试顺序会改变结果,那么你的基准测试就不公平。例如,函数A可能只看起来很慢,因为你首先测试它,而且热身不足。示例:为什么std::vector比数组慢?(实际上不是,无论哪个循环先运行,都必须为所有页面故障和缓存未命中付出代价;第二个只需快速填充相同的内存即可)。 增加重复循环的迭代次数应该线性增加总时间,并且不影响每次调用的计算时间。如果不是这样,那么你有非常大的测量开销或者你的代码已经被优化掉了(例如,提升出循环并且只运行一次而不是N次)。对于C/C++,还请参阅简单的for()循环基准测试在任何循环限制下都需要相同的时间,其中我更详细地介绍了微基准测试以及使用volatile
或asm
来防止gcc/clang优化掉重要工作。
cpufreq/scaling_governor
设置为performance
和cpu/intel_pstate/no_turbo
设置时),这种调整仍然会发生。 - undefined