第2章 性能测量

理解应用程序性能的第一步是学会对它进行测量。

与绝大多数功能问题相比,性能问题通常很难跟踪和复现。

任何关注过性能评估的人可能都知道公允地进行性能测量并从中得到准确结论是多么困难。

因为在测量中存在误差,性能分析通常需要统计方法进行处理。

开展公允地性能实验是获得精确及有意义结果的基本步骤。设计性能测试和配置测试环境都是性能评估工作的重要组成部分。

2.1 现代系统中的噪声

动态频率调节是一个硬件特性,但是测量结果差异还有可能来自软件功能。

不幸的是,测量偏差还不只来自环境配置。Unix环境变量的大小(即存储环境变量所需要的字节数)和链接顺序(提供给链接器的目标文件顺序)能够对性能产生不可预知的影响。

在运行时有效且重复地将代码、堆栈和堆对象随机放置,可以消除由内存排布引起的测量偏差。

获得一致的测量结果需要所有基准测试都在同样的条件下进行。

消除系统的不确定性有助于进行定义明确、稳定的性能测试,需要控制基准测试中大部分变量,包括输入、环境配置等。

当估计实际程序的性能优化效果时,不建议去除系统的不确定的行为。工程师应当尝试复制被优化的目标系统的配置,在被测系统中引入人为调整会导致用户在实际使用中的结果不一致。此外,任何性能分析工作-包括采样,都应当在与实际部署最接近的系统下进行。

2.2 生产环境中的性能测量

随着虚拟化和容器等技术的日渐流行,公有云供应商也尝试最大化服务器资源的利用率。但是这种环境为性能测量带来了新的困难,因为与相邻进程共享资源会对性能测量产生不可预知的影响。

大型服务提供商通过部署遥测系统来监控用户设备的性能已经成为一种趋势。

测量开销是生产环境监控的一个重要问题。由于任何监控都会影响正在运行的服务的性能,因此应该使用尽可能轻量的性能剖析方法。

通常可以接受整体不超过1%的性能损失的检测开销,减少监控开销的办法包括限制被监控的机器数量和使用更小的监控时间间隔。

2.3 自动检测性能退化问题

软件供应商提高产品的部署频率逐渐成为一种趋势,但是软件的性能缺陷会以惊人的速度蔓延到生产环境中。

软件性能退化是指软件从一个版本演进到下一个版本时被错误地引入缺陷。解决办法如下:
        1. 安排人员看图来比较结果,不过这种办法很快就被抛弃了,因为人很容易因为注意力不集中而错过性能退化缺陷。
        2. 设定1个简单的阈值阀门。缺点在于选择合适的阈值门限是非常困难的事情,并且不能保证误报率低。阈值设定过低会导致误报一些由随机噪声引起的而不是代码变化引起的性能退化数据,阈值设定过高会导致过滤不出真正存在的性能退化问题。

无论使用何种算法来检测性能退化问题,典型的CI系统都应当能够自动进行以下动作:
        1. 配置待测试系统。
        2. 运行程序;
        3. 报告运行结果;
        4. 判断性能是否发生变化;
        5. 将结果可视化。

CI系统应当能够同时支持自动基准测试和手动基准测试,产生可复现的结果,并对发现的性能退化问题生成工单。迅速检测性能退化问题也非常重要。

2.4 手动性能测试

本地性能评估的基本建议:
        1. 多次测量基线性能;
        2. 多次测量修改后的程序的性能;
        3. 对2者进行比较;
使用统计分布图的一个优势是可以发现基准测试中的不良行为。如果数据分布是双峰的,基准测试会表现出两类不同的行为,引起双峰分布的常见原因是代码有快、有慢两条执行路径,例如访存缓存、获取锁等。解决这些问题的方法是隔离不同的功能模块并分别进行基准测试。

性能数据分布的可视化展示可以帮助我们发现某些异常,但我们不应当同它来进行加速比的计算。假设检验非常适合用来确定性能加速(减速)的表现是否具有随机性。

一旦通过假设检验方法确定2组数据存在统计上显著的差异,就可以使用算术平均或几何平均的方法来计算加速比。注意对于小样本采样,均值和几何均值会受到异常值影响。除非数据分布具有小方差,否则不应当只考虑使用均值。

如果测量值的方差与均值大小在同一个数量级,那么均值就不是具有代表性的指标。

为了准确地计算加速比,最重要的工作之一就是收集大量的样本数据。这听上去很容易,但有时并不可行,太多基准测试叠加下来的测试时间太长了。

需要收集多少样本数据才满足统计分布需要呢?这取决于对比测试的精确到要求。分布数据中样本的方差越小,需要的样本数越少。实施自适应策略,收集样本直到标准差达到特定的范围。

另一个需要特别小心的是异常值的存在。对某些类型的基准测试而言,异常值可能是重要的指标。

2.5 软件计时器和硬件计时器

系统级高分辨率计时器:通过统计自某任意时间起开始流逝的滴答数而实现。系统级计时器分辨率是ns级别,并且在所有CPU上都是一致的,它适合用来测量持续时间超过1us的事件。
时间戳计时器TSC:通过硬件寄存器实现的硬件计时器,它适合用来测量持续时间从ns到1 min之间的事件,可以用编译器的内置函数__rdtsc查询。

如果需要测量的时间很短暂,则TSC可以提供更好的准确度。相反,如果需要测量的时间长达数小时,则TSC测量毫无意义。除非真的需要时钟周期的精度,否则大部分情况下选择系统计时器通常就足够了。

2.6 微基准测试

微基准测试程序是在优化某些特定功能时跟踪优化进展的手段。对于C++而言,使用Google benchmark库,C#则是BenchmarkDotNet库,Julia则是BenchmarkTools库,Java则是Java Microbenchmark Harness。

定义一个基准测试优劣的依据是,它能否在真实条件下测试将来要使用的功能的性能。

如果基准测试使用的合成输入与实际使用的输入不同,那么基准测试可能会误导你。所以,在根据单元测试的结果总结结论时要小心。

2.7 本章小结

1. 由于测试的不稳定性,调试性能通常比调试功能更为困难。
2.确定预期目标,需要为如何衡量该目标设定有意义的定义和指标。根据关心的内容,它可能是吞吐量、延迟、每秒操作数(屋顶线模型)等。
3.再生产部署中衡量性能时,为了处理环境噪声的问题,需要使用统计方法分析结果。
4. 越来越多的大型分布式软件供应商选择直接在生产系统上剖析和监控性能,这要求只能使用轻量级的剖析技术。
5. 采用自动化性能跟踪系统有助于防止性能退化问题渗透到生产软件系统中,此类CI系统应能够运行自动化性能测试,可视化结果并标记潜在缺陷,这也是向受众展示性能结果的稳妥办法。
6. 性能数据分布之间的统计关系可以通过假设检验方法来识别和发现。
7. 系统级高分辨率计时器适合测量持续时间超过1us的事件,若需要高精度测量短事件,则可以使用时间戳计时器。
8. 微基准测试适合迅速证明一些事情,但是你应该始终在实际条件下用真实的程序验证你的想法。

你可能感兴趣的:(现代CPU性能分析与优化,Bakhvalov,计算机体系结构,性能优化,并行计算)