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