性能测量

测量方法

外部测量

利用外部工具对程序进行测量,通常不需要修改程序

  • time ( /usr/bin/time )
  • Linux perf
  • Intel EMON

程序运行时间分为:

  • 真实时间(real time) :也称挂钟时间(wall clock time),指程序开始到结束真实世界经过的时间
  • CPU时间(CPU time) :指程序占用CPU进行运算的时间。根据CPU的状态,还以细分为:
    • 用户态时间
    • 内核态时间

在多核下运行的并行程序中,CPU时间为多个线程的CPU时间之和,该时间一般小于真实时间。

内部(插桩)测量

内部测量(internal measurement) ,或叫插桩(instrumentation) ,是通过修改程序的源代码或二进制文件,在程序中插入时间测量代码或性能分析工具来测量程序的性能。

适用范围:只对程序某一部分的性能感兴趣,而非整个程序。

间隔计时器:在需测量程序代码段的开始和结尾各插入一个计时器(插桩点, instrumentation point),用两次计时的间隔来表示所测量程序的运行时间。

  • clock_gettime(CLOCK_MONOTONIC, …)
  • gettimeofday()
  • rdtsc()
  • 推荐使用clock_gettime(CLOCK_MONOTONIC, …)
    • 时钟类型 CLOCK_MONOTONIC 表示该时钟是从系统启动开始计时,计数值单调不变(不会回退)
    • 能获得 ns 级别的时间戳
  • 不推荐使用 ② gettimeofday() 或 ③ rdtsc
    • gettimeofday() 使用的时钟类型是 CLOCK_REALTIME,会随着时区改变而改变,并且用户可以手动修改
    • gettimeofday() 只能获得 μs 级别的时间戳
    • TSC 计数器的值在处理器不同核心上计数值是不同的
    • TSC 计数差值到真实时间的换算有时并不容易
    • TSC 是硬件计数器,可能会溢出

仿真测量

仿真测量(simulation measurement) 是使用计算机模型或仿真工具来模拟程序、系统或硬件在不同条件下的行为,以评估其性能和稳定性等行为。

Valgrind:用于软件内存泄漏检测、性能分析的一套工具

  • 本质:使用即时编译(Just-In-Time, JIT)技术的虚拟机

数据收集策略

计数型

计数(counting)型策略是用计数器(counter)对特定事件发生的绝对次数进行收集。

  • 软件计数器:操作系统内核或用户进程在内存中维护的变量。
  • 硬件计数器: 计算机硬件内真实存在的寄存器。

采样型

采样(sampling)型策略是在程序运行过程中,对系统有规律地进行采样,采样时刻将收集系统的状态信息形成若干样本,最终形成性能数据的统计信息。

  • 特点:开销可控。

追踪型

追踪(tracing)型策略记录了程序的执行过程中的每个事件和函数调用,提供了详细的时间序列信息。

  • 事件驱动,需要记录特定事件发生的时间以及其他用户关心的状态信息(计数型仅需要更新计数器)。
  • 如果事件发生较为频繁,追踪将造成显著开销。

性能可变性

在性能测量中,可变性具体表现在多次性能测量的结果存在波动。

性能可变性的来源:

  • 软件层面:
    • 后台任务
    • 中断
    • 进程/线程运行时调度
    • CPU或内存绑定
    • 多租户(multitenancy)
    • 代码或数据对齐 等
  • 硬件层面:
    • 超线程(HyperThreading, HT)
    • 动态电压和频率调节(Dynamic Voltage and Frequency Scaling, DVFS)
    • 睿频(Turbo Boost)
    • 网络流量 等

控制可变性的方法——系统静默(quiescing):

  • 软件层面:
    • 关闭后台任务
    • 绑定工作进程/线程(taskset或numactl)等
  • 硬件层面:
    • 关闭HT / DVFS / Turbo Boost 等

配置优化

即配置软件使其在特定的使用场景(如不同平台、不同架构等)获得更优的性能。

特征建模

  • 一种模型驱动的方法
  • 具有形式化的表示方法
  • 支持使用现成的约束求解器进行自动分析

通过特征建模和约束求解,便可以得到特定目标的特征依赖,从而得到软件的优化策略。

组合爆炸

在特征数量较多的时候,通过组合选取特征的方法穷举特征选择,具有很高的难度。

特征交互

不同的特征之间可能存在交互,即加入一个特征会影响到另一个特征的优化效果或性能。

测试类型

  • 简单测试:不考虑特征交互,对每一个模块进行分别测试
  • 全阶乘测试:考虑所有特征交互,穷举每个特征启用/禁用的情况,复杂度达到$2^k$
  • 部分阶乘测试:选取全阶乘中的部分情况进行测试,比全阶乘的耗时更少,但无法穷举所有选择情况
  • 机器学习方法:如CART(Classification And Regression Trees)、随机森林、贝叶斯优化等
  • 自动调优:OpenTuner等