汽车软件性能提升方法的工程化落地

当今的汽车与数年前的汽车相比,虽然作为载具的主要目的变化不大,但不论是在驾乘体验、智能化水平还是交互方式上,都发生了质的飞跃。

为了能支撑新一代汽车所提供的这种智能化服务水平,显而易见,需要将软件平台与硬件平台相互分离和抽象以提升灵活性,这种被称为软件定义汽车(Software Defined Vehicle,下文简称 SDV)的设计方法基于更加灵活和易于扩展的软件作为汽车的核心,将传统的汽车升级为拥有诸如智能驾驶、深度娱乐、个性化人机交互能力的 “第三空间”。

SDV 带来了一系列汽车设计的革命性跨越,同时也引入了各种新的困难。诸如性能、可靠性、安全性、易用性等在软件领域长期存在的跨领域、跨业务型挑战,随着 SDV 被一并引入了汽车领域。

为什么车企不容易做好软件性能

“车机卡顿”故障常年在汽车投诉榜单上拥有一席之地,性能问题除了影响乘驾体验,有些情况下甚至会造成危险,如导航系统的卡顿会严重干扰驾驶员的决策。

既然汽车行业和软件行业都已发展多年,那为什么在软件定义汽车之后,车企不容易做好软件性能呢?

无可避免的本质复杂性

软件领域没有新鲜事,从单体到分布式,从多任务到多实例,软件领域所面临的挑战总是伴随着业务形式和组织形式的发展。

一切问题源于复杂性。就像冤家路窄的扩展性和性能,随着软件规模的扩大,扩展性差会降低研发效率,而扩展性要求的层层抽象却会成为软件性能设计的掣肘。

由于软件本身的架构灵活性,其功能构造十分易于修改和扩展,这也使得在表面上看,软件的规模似乎可以不受限制的扩大。但人类大脑的认知边界限制导致了软件规模的扩大同样也意味着协作规模的扩大,这种大规模的软件协作体系,让软件的复杂度成倍提升。

任何软件在规模扩张的过程中都容易陷入两类本质复杂性的泥潭:

  • 晦涩性:软件研发的过程可以看做是知识传递和转换的过程,大规模软件的领域知识不掌握在任何单一个体的脑中,更复杂的分工也造成了知识传递过程中的失真。若不加以治理,这种晦涩性最终会导致整个软件系统无法被理解。
  • 依赖性:大规模软件通常都包含了十分复杂的层次结构,其模块和组件之间通过各种形式的接口耦合相互依赖从而形成整体。但这种依赖性绝大多数时候是级联的,一旦处理不好,某个边缘组件的修改可能突然导致其他看似毫不相关的组件发生故障。

不出意外,为了实现各种高阶智能化特性,SDV 驱动的汽车软件系统满足了复杂软件系统的一切特征。

图源:智能网联汽车电子电气架构产业技术路线图

以上图所示的汽车软件功能架构为例,汽车软件的架构具有业务繁杂、技术栈深、安全性要求高的特点。与其他行业如手机制造、互联网平台等的软硬件架构相比,汽车软件在各架构层级中的标准化程度更低,研发定制化的场景也更多,而整个汽车产业链中的各类供应商更是层出不穷。

以上现状决定了汽车软件研发过程中,业务交互复杂、架构设计复杂、团队协作复杂。

性能是一种横跨软件全业务、全生命周期的架构特性

架构特性(Architecture Characteristics)是架构师在设计软件时需要考虑的与领域或业务需求无关的软件特性,如可审计性、性能、安全性、可伸缩性、可靠性等等。在很多时候我们也会称之为非功能性需求(Nonfunctional Requirements)或质量属性(Quality Attributes)。

ISO/IEC 25010:2011 中,性能效率是软件质量模型中的一项关键架构特性,模型中将性能效率更具体的描述为软件的“时间特性”、“资源利用率”和“容量”等。

显然,软件性能作为一种横跨业务和软件生命周期的通用架构特性,性能的优劣在许多关键业务场景下都决定着客户的使用意愿,而为了构建高性能的软件系统,从软件的设计之初就需要开始考虑性能。

当性能特性需要横跨复杂的汽车软件系统时,就会面临跨技术领域、跨业务领域和跨团队领域的三类挑战。

以导航功能为例:导航作为车上非常关键的应用,如果出现迟滞、卡顿、退出等问题,会严重影响用户的驾车体验。因此为了确保导航使用的流畅性,在运行时需要有更多的系统资源,以及更稳定的运行环境。

操作响应快要求导航进程的调度优先级更高,连续读图要求 IO 排队时间短,画面渲染涉及如 Unity3D 等的第三方库以及 GPU 资源,另外导航中的一些辅助功能如AI语音,画面共享等则需要调用其他组件的能力。

因此对于导航这项关键功能,如果发现性能故障,其定位和优化的过程可能牵涉多个业务领域,以及包括应用层、中间件层和系统层等多个技术层,此外还可能会牵扯信息安全、体验一致性以及系统可靠性等诸多问题。

性能持续提升的工程化方法

性能作为一种在复杂软件环境下的跨领域架构特性,性能优化工作很容易陷入性能不佳 -> 问题拖延 -> 间歇性优化 -> 再次劣化的循环。我们期望通过一种工程化的方法,来管理和运营软件性能,从而实现持续的性能守护和提升。

工程化方法一般指通过科学的方法和标准化的流程,来提升项目的效率和质量。因此对于“性能优化”这样的课题,可以通过如下五个方面的实践来实现工程化,即性能工程。

  • 系统方法论:性能优化的体系化方法,可参照如《性能之巅》等的性能分析和优化方法论。
  • 标准化流程和规范:定义如性能建模以及自动化方法(如适应度函数)等的标准化流程,提升效率。
  • 成熟的技术支持:需要的知识、技术能力和人才,其中领域专家、性能专家和工程专家这三类角色非常关键。
  • 全生命周期管理:类似 DevOps 的方式,对软件全生命周期的性能优化活动进行定义。
  • 持续改进:通过持续观测、持续看护等手段将性能优化的实践持续运行。

有关性能工程更多的细节,请见《什么是性能工程》

下文将从性能观测、性能调优、性能团队三个角度,介绍上述工程化方法的五个方面在 SDV 研发中的落地实践。

持续性能观测

性能优化的前提是能够对性能进行客观的评估,通过构建对系统的观测能力,我们能尽可能多的了解系统现状,从而为之后的性能看护和优化提供评估依据。

建立评估模型

性能评估模型作为性能建模活动的产出物之一,在系统建设之初就可以着手开展,同时,评估模型也需要随着产品的不断迭代,融入更多业务和技术指标,以准确的描述系统性能要求。

指标模型一般可分为业务指标,系统指标和资源指标,业务指标更偏向于黑盒指标,以最贴近用户使用的角度描述产品性能特性。系统指标则更多地贴近白盒指标,描述系统运行过程中的内部状态,它们会间接影响到业务指标。而资源指标是作为前两种指标的补充,独立评估资源指标没有意义,但与其他指标相结合后能够更准确的描述系统状况。

尝试落地持续性能优化的过程中,最困难的部分就是建立评估模型,因为评估模型代表性能目标。(关于评估模型的建立,请参考《智能座舱软件性能与可靠性的评估和改进》

如果评估模型设计的有偏差,很容易导致花了不少时间建立的模型,关键的性能点没有纳入其中。基于这种模型进行优化迭代,会让团队产生一种错觉:花了大力气建设的观测系统,派不上用场,因为即使是观测到指标在改善,系统的性能看上去似乎仍旧不佳。

这也反过来会让团队产生怀疑:性能观测和性能优化到底有关系吗?在这种自我怀疑中,性能团队的工作就很容易陷入《性能之巅》中提到的一些反模式,如街灯讹方法或随机变动讹方法。

定制可扩展的观测工具

为了能有效地评估系统,观测工具是必不可少的。对于评估模型中的各类指标,大多数都可以通过既有的工具进行收集。而为了更好的发现问题,业内也存在众多可对系统进行剖析的追踪工具。

因此建立观测系统的主要目标是整合各类零散的观测工具,形成完整且易用的系统性能观测能力。除了传统的工具整合,观测系统的可定制化以及开销也值得关注。

最简单的观测系统可分为设备上的探针前端以及上位机或服务器上的分析后端。由于直接运行在设备上,探针自身的开销不容忽视,因此通常性能探针都包含细粒度的配置能力,在研发或测试阶段,打开全部或大部分开关,而在生产运行阶段只打开部分开销低的信息收集功能。

为了扩展探针的系统级观测能力,通过 eBPF 对内核行为进行观测是一种安全且高效的方式,基于 eBPF,可以方便的对调度、内存、IO和网络进行定制化观测。

除了开销,在生产运行阶段,还需要考虑数据的隐私合规以及网络流量等方面的限制。因此数据脱敏、加密和压缩也应作为重要的设计考量。

性能看护

拥有了评估模型后,通过模型建立系统的性能基线,就能够在系统迭代过程中不断地评估系统的性能是优化还是劣化。

从前文可知,评估模型包含了一组用于描述不同系统特征的指标,因此实际建立的性能基线就是一组指标向量。显然,性能指标基线的建立,需要反复地、大量的对系统进行性能测试,之后取统计值作为基线,才具有评估价值。

不论是建立性能基线,还是基于两组不同的指标向量进行性能看护,都应采用一些基础的统计学方法来使评估和看护更客观。

首先,需要对采集到的指标样本进行正态性检验,如果指标样本不符合正态分布,则需要对样本进行数据矫正,或是调研采样过程是否存在偏斜。符合正态分布的样本是进一步统计学对比的前提。

其次,由于指标众多,加之优化或劣化可能仅体现在某些指标上,因此在性能测试样本与性能基线的对比过程中,可通过诸如 t 检验的一类方法,计算每个指标变化的显著性水平,来客观的评价指标值是否发生了显著的变化。

最后,考虑到优化成本和实际的收效,系统略微的劣化,可能不值得进行大刀阔斧的优化活动,因此除了显著性水平的判断,还可通过计算效应量来判断实际发生的劣化/优化是否明显对系统产生了影响,进而帮助工程师进行决策。

持续性能改进

在发现性能问题后,如何改进且持续的改进性能就变成了第一要务。

TopDown 分析与问题建模

一般情况下,性能问题都是由业务现象或是黑盒指标异常所产生的,这类问题的特点就在于表象之下深层次的原因往往被各种纷繁复杂的噪声所掩盖。而遇到这类问题最先冒出来的想法都是随机试错,这时我们会极度相信大脑所冒出的第一个可能原因,并有强烈的试一试看看的冲动。

然而随机试错法不仅是片面的,也是低效的。更科学的分析方法是对问题建模,从负载和资源的角度更准确的定义问题,之后基于被测系统的架构进行自顶向下的分析,作出假设后采用客观的测试方法进行验证。

这里举一个问题建模的简单例子。系统被测试用户认为使用流畅度不佳。在分析该问题之前,首先需要定义清楚问题:系统发生不流畅时,负载是怎样的?帧率是一种能够描述系统渲染负载的黑盒指标,如果低于正常值表明渲染过程存在高负载,否则就需要进一步调查各业务阶段的完成时间。此外,系统发生不流畅时,资源是怎样的?对硬件资源(CPU、内存、磁盘)以及软件资源(锁,线程,连接)的争用情况进行分析,能够对系统所处状态做出进一步描述。

构建微基准测试

对性能问题进行建模之后,可能的优化路径也许已经逐渐清晰,但在着手尝试实施优化之前,设计相关的微基准测试也是十分必要的。相比于浮现出性能问题的业务现象或黑盒指标,微基准测试能从更细粒度的方向对系统进行测试,它排除了不相干的噪声干扰,可以专注于对性能优化点所影响的指标进行测试。

例如在对前台应用卡顿问题进行优化的时候,经过建模和分析,我们假设卡顿的原因可能是由于在系统负载较高时,渲染线程难以及时被调度到 CPU 上,导致渲染不及时。那么对于这种假设,我们就需要构建一组基准测试,包括一个负载生成器,能够为系统施加一定程度的负载,使之达到测试条件。也包含一个能够探测并记录应用调度延迟的工具。之后通过一个测试脚本,一边生成负载,一边运行被测应用,测试完成后能够打印过程中的调度延迟变化。基于这样一组微基准测试,就能够相对独立的测试对前台应用调度延迟的优化程度。

优化驱动模型迭代

在性能优化工作中,必须认识到软件的迭代性,随着软件的不断迭代更新,原本可用的优化手段其效果可能会慢慢变差甚至失效。因此对优化本身的看护也很关键。

举例说明,IO 预读是一种缩短系统启动时间的方法,通过将启动过程中少量多次的 IO 操作进行合并以减少总体开销,从而达到缩短时间的目的。但预读优化要求能提前获悉启动过程中所有代码实际读写的文件,这种信息势必会跟随软件迭代而变化,那么预读的内容也需要一起更新才能确保有效。

为了能及时发现优化效果减弱的情况,基于优化本身可以提取出与之相关的检测项,可作为白盒指标纳入评估模型,最好能通过相应的适应度函数来自动化评估。仍旧回到预读的例子,为了能让预读的内容跟得上软件本身的变化,可以构建一个自动化的适应度函数:

在每个新版本发布后,自动执行一次,获取启动过程的读写文件列表,与实施优化的文件列表(这就是基线)进行对比,当发现差异度大于 30% 时报警。

通过这样的方式,就能持续确保优化的有效性,且一旦建立后就不再需要人工干预。

性能工程团队

对于前文提到的性能工程方法,如果没有一个专业化团队来负责推进,是难以最终在组织中落地生根的。就像在工程化五大实践中提到的,成熟的技术支持必不可少。对于构建性能工程,需要组建一个分别包含了领域专家、性能专家和工程专家的专业化团队。

在 Matthew Skelton 和 Manuel Pais 的《团队拓扑》中,描述了四种基本的团队类型:

图源:Organizing Agile Teams and ARTs: Team Topologies at Scale

  • 业务流团队:匹配业务领域和组织能力的端到端交付团队。
  • 赋能团队:特定技术领域或产品领域的专家,为业务流团队赋能。
  • 复杂子系统团队:构建和维护系统中严重依赖专业领域知识的子系统。
  • 平台团队:为产品导向团队构建能提供自服务的各项基础能力。

有趣的是,我们在性能工程的实践过程中,发现性能工程团队是一个融合了包括“赋能”、“复杂子系统”和“平台”三种类型的团队。当负责协助业务流团队对具体的产品或组件进行性能诊断和优化时,性能工程团队是赋能团队;当对系统层面实施性能优化时,性能工程团队变为复杂子系统团队;而当构建性能建模、性能观测等平台化能力时,性能工程团队又成为了平台团队。

能有效承担上述工作职责,与团队本身的成员构成密不可分。

在 SDV 的语境下,领域专家需要熟悉车载系统在不同场景下的业务构成及其性能要求,性能评估模型中的业务指标,也大都是由领域专家基于业务经验给出的。领域专家不一定长期在性能工程团队工作,TA 可能是技术架构师,业务分析师或产品经理,但结合业务和性能的跨领域能力十分关键。

性能专家深谙性能观测和性能优化的各种原理,方法和实践,同时也需要熟悉整个系统架构。在整车软件架构中,因不同功能域对实时性要求的不同,通常会采用虚拟化技术在同一硬件平台上运行多套系统。虚拟化产生的资源抽象和隔离会对性能优化产生很大的影响。例如,若性能专家不了解虚拟化层对计算资源的抽象,在 Guest 系统中盲目进行大小核、调频等优化,不仅不一定有效,还可能导致出现未知的行为。

工程专家则主要参与优化的落地,平台的搭建以及对业务团队赋能等任务。工程专家是经验丰富的工程师,排查业务团队的性能故障要求 TA 熟悉 Android、Linux 或 AUTOSAR 的开发;搭建观测系统以及平台能力要求 TA 熟悉数据工程、网络通信、云原生服务等;而包括编译工具链、DevOps、测试工具开发等研发相关的能力也不可或缺。

当然一步到位的组建出这样的“六边形”团队不是件容易的事,但组织只要尝试开始构建性能工程,相信最初不胜任的团队,其能力也会随着性能工程成熟度的不断提升,而最终成为胜任的团队。

总结

最后总结一下,由于智能网联汽车与传统汽车在功能上的巨大差异,为了灵活性和迭代速度,软件定义汽车的理念势在必行。然而软件的两种本质复杂性,晦涩性和依赖性,叠加性能本身的跨领域特性,导致车企不容易做好软件性能。

我们尝试通过工程化的手段持续提升汽车软件的性能,其中包含了一些实践:

  • 构建系统观测能力,了解系统现状,为性能看护和优化提供评估依据。
  • 通过分析建模、测试验证、迭代优化的方式持续地优化软件系统的性能。
  • 组建性能工程团队,专业化解决性能问题、赋能业务团队并搭建平台。

对软件性能工程这件事,我们仍在持续不断地探索和实践,希望本文能对您产生帮助。