性能基准测试方法归纳总结
做性能优化,第一件事不是改代码,而是先把“现在跑多快”搞清楚。我见过太多人一上来就调参数、换算法,结果优化完发现还不如原来——因为没有基准线。
说白了,基准测试就是给性能“拍一张X光片”。你总得知道病在哪,才能开药方。本章我把常用的方法、工具、以及我在项目中踩过的坑,一次性揉碎了讲清楚。
测试前的三件事
先别急着跑脚本。我个人习惯,动手前先问自己三个问题:
- 测什么?——CPU? 内存? 还是两者都要?
- 什么场景?——SDK初始化? 每次调用? 还是长时间运行?
- 怎么算准?——单次还是多次? 均值还是中位数?
嗯,这三个问题答不上来,测出来的数据就是废纸。我曾经有个项目,团队测了三天发现SDK内存泄漏,结果只是忘了清缓存,白白浪费一周。
四大类测试方法
实际工作中,我常用下面这四类方法。它们各有各的适用场景,别搞混了。
| 方法 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 微基准测试 | 单函数、单接口 | 结果精细,容易定位 | 脱离真实上下文 |
| 宏基准测试 | 完整业务链路 | 贴近真实用户 | 结果受干扰多 |
| 压力测试 | 极限负载 | 暴露瓶颈 | 环境要求高 |
| A/B对比测试 | 方案选型 | 结论直接 | 需要对照组 |
你想想看,如果只做微基准,调优一个函数快了10倍,结果整个链路卡在别的地方——那不就是白干吗?所以我建议至少跑一轮宏基准,确认真实效果。
CPU与内存的关键指标
我们做SDK优化,最关心的指标就三个方向:
- CPU耗时——用户会感觉“卡不卡”。建议用
clock_gettime或perf采用户态时间。 - 峰值内存——Android里叫PSS,iOS里叫resident_size。我习惯在测试前后各打一次
getrusage()。 - 内存分配次数——很多优化其实是在减少malloc调用,比单纯降峰值更实用。
一个最简单的基准测试框架
下面是我自己常用的一个Python脚本骨架,测一个函数的CPU耗时和内存。你可以直接套用。
import time
import tracemalloc
import statistics
def benchmark_cpu_memory(func, iterations=10, warmup=3):
# 热身
for _ in range(warmup):
func()
times = []
mems = []
for _ in range(iterations):
# 记录内存起始
tracemalloc.start()
start = time.perf_counter()
func()
end = time.perf_counter()
current, peak = tracemalloc.get_traced_memory()
tracemalloc.stop()
times.append(end - start)
mems.append(peak)
return {
'cpu_ms': statistics.median([t*1000 for t in times]),
'mem_kb': statistics.median([m/1024 for m in mems])
}
# 举个栗子
def test_sdk_init():
# 这里替换成你的SDK初始化代码
pass
result = benchmark_cpu_memory(test_sdk_init, iterations=7)
print(f"中位数耗时: {result['cpu_ms']:.2f} ms")
print(f"中位数峰值内存: {result['mem_kb']:.2f} KB")
time.time() 做高精度计时!它受系统时钟调整影响。我一直用 time.perf_counter(),它能保证单调递增,精度也够。另外 tracemalloc 在Python 3.4+才有,老版本得用 memory_profiler 替代。
统计分析:为什么中位数比平均值靠谱
你可能觉得“取平均不就完了吗”?我刚开始也这么想,直到有一次做压力测试,结果里有一个异常值直接把平均拉高了5倍。排查半天发现是GC线程引起的。
我个人习惯:最少跑10轮,去掉前3轮热身,然后取中位数。中位数不受两端异常值影响,更能代表“典型性能”。如果要看波动范围,再加上P90和P10。
表格对比一下:
| 统计量 | 用处 | 注意点 |
|---|---|---|
| 中位数(P50) | 典型性能 | 适用于大多数场景 |
| 平均值 | 总体趋势 | 容易被极值污染 |
| P90/P99 | 尾部延迟 | 用户感知的长尾问题 |
| 标准差 | 稳定性 | 值小说明结果一致 |
性能基准测试的完整流程
下面这张图是我自己画的标准流程,每次做测试就按这个走,基本不会漏东西。
环境控制:最容易忽略的变量
说白了,基准测试最难的不是代码,而是让环境“不变”。手机电量从80%降到20%,CPU频率就可能降一半。我有个血的教训:拿自己电脑测了一整晚,第二天发现笔记本在插电和电池模式下性能差30%——白测了。
所以我建议:
- 测试机和被测App,保证每次都是同一个版本
- 如果有Android设备,用
adb shell setprop persist.sys.cpufreq.max_freq锁频 - iOS需要在Xcode里关掉App Thinning和Bitcode
- 每次跑测试前重启手机,消除后台进程干扰
好啦,这一章的内容就是这样。记住:没有基准的优化都是瞎蒙。你按上面的流程走一遍,至少能保证数据是可信的,后面优化起来心里才有底。