2. 性能度量与基准:定义关键性能指标
性能优化这件事,说白了就是「先测量,再动手」。
我在项目里见过太多团队,一上来就闷头改代码,改完发现性能没提升,甚至更差了。为什么?因为没有基准。你连起点在哪都不知道,怎么知道终点在哪?
这一章,我们就来聊聊怎么定义性能指标,怎么建立一套靠谱的基准测试流程。嗯,这些都是我踩过坑之后总结出来的。
2.1 关键性能指标(KPI)
汽车软件里,我们最关心的指标其实就四个:延迟、吞吐量、CPU负载、内存占用。别小看这四个,每个背后都有门道。
2.1.1 延迟(Latency)
延迟就是「从请求发出到响应回来」的时间。在汽车里,这直接关系到安全。比如刹车信号,延迟超过10毫秒,可能就撞上了。
我个人习惯把延迟拆成三部分来看:
- 端到端延迟:从传感器采集到执行器动作的完整时间。
- 通信延迟:数据在总线或网络上传输的时间。
- 处理延迟:ECU内部计算、调度、排队的时间。
我曾经在一个项目中,发现某个功能偶尔会卡顿。查了半天,原来是任务调度优先级设错了。一个低优先级的诊断任务,把高优先级的控制任务堵住了。你看,延迟问题往往藏在调度里。
关键点:延迟要关注「最坏情况」,不是平均值。汽车里,P99(99%分位延迟)比平均延迟重要得多。
2.1.2 吞吐量(Throughput)
吞吐量就是「单位时间内能处理多少事」。比如CAN总线每秒能发多少帧,或者一个ADAS算法每秒能处理多少帧图像。
吞吐量和延迟是两回事。高吞吐量不一定低延迟,反过来也一样。我见过一个系统,吞吐量很高,但每个请求都要排队等很久。这就是典型的「吞吐量好看,延迟难看」。
在汽车里,吞吐量通常用这些单位衡量:
- 消息/秒(msg/s)
- 帧/秒(fps)
- 字节/秒(B/s)
我的建议:定义吞吐量时,一定要明确「在什么负载下」。空载和满载的吞吐量,差好几倍呢。
2.1.3 CPU负载(CPU Load)
CPU负载,说白了就是CPU有多忙。但这里有个坑:CPU负载高,不一定代表系统有问题。关键是看「峰值负载」和「平均负载」。
我习惯用这两个指标:
- 瞬时负载:某个瞬间的CPU使用率。看它会不会超过阈值(比如90%)。
- 平均负载:一段时间内的平均使用率。看它是否稳定。
我曾经遇到一个项目,平均负载只有30%,但偶尔会飙到95%。后来发现是一个中断处理函数写得不好,每次触发都要跑很久。嗯,这种问题,只看平均负载是发现不了的。
注意:CPU负载超过70%就要警惕了。因为一旦有突发任务,系统可能来不及响应。汽车里,这可能导致功能降级甚至失效。
2.1.4 内存占用(Memory Usage)
内存占用,不只是看「用了多少」,更要看「怎么用的」。我把它分成三类:
- 代码段:程序本身占的空间。一般固定不变。
- 数据段:全局变量、静态变量。也是固定的。
- 堆栈:动态分配和函数调用用的。这个最容易出问题。
我记得有一次,一个功能在测试时一切正常,但一上路就崩溃。查了三天,发现是栈溢出。一个递归函数在特定路况下调用深度太大,把栈撑爆了。从那以后,我每次做内存评估,都会留出至少30%的余量。
核心原则:内存占用要关注「峰值」,不是「当前值」。而且,动态内存分配在汽车里要尽量避免。用静态分配,更安全。
2.2 建立性能基准测试流程
指标定义好了,接下来就是怎么测。基准测试不是随便跑跑就行的,得有流程。我总结了一套「五步法」,分享给你。
2.2.1 第一步:确定测试场景
测试场景要贴近实际。比如:
- 怠速场景:发动机转速800rpm,空调关闭。
- 城市拥堵:走走停停,频繁启停。
- 高速巡航:120km/h,定速巡航开启。
每个场景的负载不一样,性能表现也不同。我建议至少覆盖3-5个典型场景。
2.2.2 第二步:搭建测试环境
环境要稳定、可重复。硬件、软件版本、网络拓扑都要固定。我曾经犯过一个错:在开发板上测的性能,和量产板差了一倍。后来发现,开发板的CPU频率设置不一样。嗯,这种低级错误,犯一次就够了。
2.2.3 第三步:编写测试脚本
测试要自动化,不能手动点。下面是一个简单的延迟测试脚本示例:
# 延迟测试脚本(伪代码)
def measure_latency():
start = get_timestamp()
send_request()
wait_for_response()
end = get_timestamp()
return end - start
# 运行1000次,取P99
latencies = []
for i in range(1000):
lat = measure_latency()
latencies.append(lat)
p99 = sorted(latencies)[int(1000 * 0.99)]
print(f"P99 Latency: {p99} ms")
小技巧:测试次数要足够多。我一般跑1000次以上,这样统计结果才有意义。
2.2.4 第四步:执行测试并记录数据
执行时要注意:
- 每次测试前,先让系统稳定运行几分钟。
- 记录所有原始数据,不要只记平均值。
- 同时记录系统状态(温度、电压等),这些会影响性能。
我习惯用表格来记录基准数据:
| 测试场景 | 平均延迟(ms) | P99延迟(ms) | 吞吐量(msg/s) | CPU负载(%) | 内存占用(KB) |
|---|---|---|---|---|---|
| 怠速 | 2.1 | 3.5 | 500 | 25 | 128 |
| 城市拥堵 | 3.8 | 6.2 | 420 | 45 | 156 |
| 高速巡航 | 1.9 | 2.8 | 580 | 20 | 120 |
2.2.5 第五步:分析结果,建立基线
数据拿到后,要分析。看哪些指标超标,哪些在正常范围。然后把这些数据作为「基线」,保存下来。
以后每次改代码,都要重新跑一遍基准测试,和基线对比。如果性能变差了,说明改的有问题。如果变好了,恭喜你,优化成功了。
避坑指南:我曾经有一次,改完代码后性能提升了20%,高兴得不行。结果第二天发现,是因为测试时空调没开,负载低了。所以,每次测试的环境条件必须完全一致,否则数据不可比。
2.3 小结
这一章我们聊了四个关键指标:延迟、吞吐量、CPU负载、内存占用。每个指标都有它的侧重点,不能只看一个。基准测试流程呢,就是「定场景、搭环境、写脚本、跑数据、建基线」这五步。
记住一句话:没有基准的优化,都是瞎优化。你想想看,是不是这个道理?
下一章,我们会深入聊聊怎么用工具来采集这些性能数据。到时候,我会分享一些我常用的工具和技巧。
公众号:蓝海资料掘金营,微信deep3321