hehung 发表于 2024-7-24 09:24

《嵌入式软件的时间分析》读书活动:8 第八章读书笔记-软件运行时间优化

<p id="ua3449b7d">本章主要讲解了软件运行时间的优化相关知识。运行时间优化应严格遵循&ldquo;自上而下&rdquo;的原则。首先要在调度层级进行分析和优化,然后才在代码层级进行优化。</p>

<p id="udb7bfa48">目录如下:</p>

<pre>
<code>第8章 软件运行时间优化 174
8.1 调度层级的运行时间优化 174
- 8.1.1 防止跨核心通信 174
- 8.1.2 避免使用 ECC 任务 174
- 8.1.3 合理使用异构多核处理器 175
- 8.1.4 避免需要确保数据一致性的机制 175
- 8.1.5 通过优化偏移实现周期性任务的负载均衡 175
- 8.1.6 拆分任务 177
- 8.1.7 将功能迁移到执行频率较低的任务 177
8.2 针对存储器使用的运行时间优化 178
- 8.2.1 快速存储器的利用 178
- 8.2.2 数据对齐 180
- 8.2.3 代码对齐和缓存优化 181
8.3 代码层级的运行时间优化 182
- 8.3.1 优化频繁调用的小函数 184
- 8.3.2 优化根函数sqrt 184
- 8.3.3 AURIX的线性内核 ID 187
- 8.3.4 计算至达到饱和 190
- 8.3.5 处理器特定的通用指令 191
- 8.3.6 编译器优化 192
8.4 运行时间优化总结与指南 199</code></pre>

<h1 data-lake-index-type="2" id="jIZB8">1. 调度层级的时间优化</h1>

<p id="uc92435a0">在调度层级进行优化的最重要在于项目特定的参数,包括应用程序在多核处理器不同核心之间的基本分布、操作系统的配置以及任务函数和Runnable的分发等。换言之,整个项目特定的运行时间设计肯定会对调度效率产生最大的影响。</p>

<p id="u902b7dd3">防止跨核心通信:在多核处理器的不同核心之间分配功能时,应尽量减少跨越核的通信。应诊将尽可能多的中断(甚至所有中断)交由一个核心集中处理,而将计算密集型代码节部署到另一核心。</p>

<p id="uf8ab5e74">遐免使用 ECC 任务:只和OSEK/AUTOSAR CP项目相关。</p>

<p id="uf25e26e5">合理使用异构多核处理器:在异构多核处理器中,采用前述拆分方式时,应将软件的计算密集型代码节分配给最强大的核心。</p>

<p id="ucd3a8635">避免需要确保数据一致性的机制:随着系统变得越来越复杂,确保数据一致性的成本不断提高,因此,最好消除对显式数据一致性机制的需求。数据一致性机制会消耗额外的RAM、闪存和运行时间。避免方式:</p>

<ul>
        <li data-lake-index-type="0" id="uc99d83ff">使用相同的优先级或优先级组来尽可能避免抢占式中断;</li>
        <li data-lake-index-type="0" id="uee549fd3">使用协作式多任务处理来避免抢占式中断;</li>
        <li data-lake-index-type="0" id="ue47f34b4">如果无法避免抢占式中断,可以将抢占式任务或(抢占式)中断划分为包含强制性抢占部分的节段和可以以非抢占方式实现且包含所有其他部分的节段。</li>
</ul>

<p id="uea0f5ccf">通过优化偏移实现周期性任务的负载均衡:当配置了多个周期性任务时,会带来各任务彼此之间时间关系的问题。可以通过偏移(offsets)来设置,偏移是指与调度开始时的基准或假想的基准之间的时间差。(书中有具体的示例,page 176)目的是让任务切换的中断次数最少。</p>

<p id="u92531bc1">拆分任务:如果后台需要做很多工作,同时任务中也有大量工作,可能导致后台不会执行,所以将任务拆分成两个或者多个,让后台可能有时间执行。但同时更多的任务也意味着更多的资源消耗,需要根据项目具体情况评估。</p>

<p id="u26337abc">将功能迁移到执行频率较低的任务:这种优化方法比较烦琐;而且它在实践中可能具有很大的针对性。</p>

<h1 data-lake-index-type="2" id="tjlk7">2. 针对存储器使用的运行时间优化</h1>

<p id="u8ed99e29">微处理器有多种不同的存储器和寻址模式,有些访问速度快,有些则比较慢。快速存储器的容量一般非常有限,因此没有足够的空间容纳所有符号。因此就有问题:应该将符号放置在何处才能实现软件的最高性能?</p>

<p id="u904fbe16">下图表示了一个放置规则(经常访问的小符号应该放置在快速存储器中):</p>

<div style="text-align: center;"></div>

<p id="u3a09d5eb">符号的大小可以通过编译后生成的map文件查看。</p>

<p id="u7c2add6d">确定访问和调用的频率会更加困难。最简单方法就是测量或追踪。</p>

<p id="ufdcf9299">数据对齐:</p>

<p id="u7cc409b7">一般32位的处理器都会要求数据地址是4的整数倍。所有采用32位对齐的地址都以0、4、8或c结尾,这样的数据访问速度会最快。如果不按照4字节对齐,则处理器会使用其他指令访问数据,速度会慢很多。同样,结构体也需要对齐分配才能获得最优的访问效率。</p>

<p id="u8665ef8c">对于代码和数据对齐的运行时间优化是以牺牲存储需求为代价。因此,用户必须&ldquo;最短运行时&rdquo;(速度优化)和&ldquo;最低存储需求&rdquo;(大小优化)这两个优化目标之间做出选择。</p>

<h1 data-lake-index-type="2" id="ckUWX">3. 代码层级时间优化</h1>

<p id="uff438776">一般而言,代码优化的相应候选项(函数)以分为两类:</p>

<ul>
        <li data-lake-index-type="0" id="u299037b1">从很少甚至唯以一一个地方调用但运行时间需求较高的函数(通常为单个大函数中进行的复杂计算);</li>
        <li data-lake-index-type="0" id="u440b13ff">非常频繁地从很多不同的地方调用的函数(通常包含相对较小的函数或用于适配数据类型的函数)。</li>
</ul>

<p id="uc123d5e2">优化频繁调用的小函数:如果源代码可用,则应对源代码进行分析。最好的办法是同时查看源代码和由编译器生成的汇编代码。同时利用编译器的特性,利用内联函数或者其它特性进行优化。</p>

<p id="u54e00e53">根函数sqrt优化:要得到精确的根则会花费较多的时间。一般对于绝大多数的数学函数,有一些精度低但是速度快很多的替代方案。需要开发人员评估精度的缺失是否会带来负面问题,可以网上搜索替代方案。</p>

<p id="u03ac2952">AURIX 的线性内核 ID(page187):英飞凌的第二代AURIX最多有6个CPU,但是内核ID是不连续的,分别为0~4和6,但是一般用户会使用数组,所以需要一个连续的ID,如果为6,则变成5,作者采用的分析方式是通过生成的汇编代码来查看C代码实现的逻辑,并且增加优化等级,查看生成的汇编的变化,然后删除其中不必要的语句,只保留必要的可以实现功能的语句,就可以实现代码效率最高的优化。作者发现内联函数没有真实的被编译器设置为内联函数时,采用了宏的实现方式。</p>

<p id="uf8373125">计算值达到饱和:很多计算中,都要求结果达到饱和而不溢出。需要查看芯片是否有直接的机器指令支持这种饱和操作,AURIX就有sat.hu指令支持。</p>

<p id="u18f6f5e6">编译器优化,有如下方式:</p>

<ul>
        <li data-lake-index-type="0" id="uac348de0">每个编译器都提供了现成的优化组合,因此用户仅需指定粗略的目标(&ldquo;针对大小优化&rdquo;还是&ldquo;针对速度优化&rdquo;)或优化程度即可。-O0用于禁用所有优化措施,-O1至-O3用于依次执行更积极的优化。如果未选择何优化选项,则编译器将使用-O0,不进行任何优化。</li>
        <li data-lake-index-type="0" id="uf6d0d795">对于编译器提供的每种优化,都有一个单独的编译器开关,当从命令行调用该开关时,可以将其传递给编译器。查看编译器手册。</li>
        <li data-lake-index-type="0" id="udd109a34">可以直接在函数层级甚至在函数内的源代码中启用或禁用各个优化选项。这可以通过不同的机制来实现。查看编译器手册,一般通过#pragma语法来实现</li>
</ul>

<p id="u0e6c286e">Page195,作者通过对Memcpy的各种优化说明了优化后的代码的时间消耗,以此说明了优化的方法以及重要性。</p>

<h1 data-lake-index-type="2" id="yW4gO">4. 总结</h1>

<p id="ub636a81e">通过一些流程图来说明了如何解决运行时间问题。</p>

<div style="text-align: center;">
<div style="text-align: center;"></div>

<div style="text-align: center;"></div>

<p>&nbsp;</p>
</div>

<p id="u7e4fae8f">&nbsp;</p>

<p id="u90a6eaa7">本章节的时间优化方案对于嵌入式软件开发人员而言还是很有实际用处的,作者所说的优化方式也在工程中经常用到,但是作者对此进行了系统总结,补充了一些新知识,有助于开发人员对软件做时间优化。</p>

<p id="uf14cecc2">&nbsp;</p>
页: [1]
查看完整版本: 《嵌入式软件的时间分析》读书活动:8 第八章读书笔记-软件运行时间优化