电子说
经验丰富的嵌入式系统程序员已经知道将代码优化到目标平台的大部分技巧,但是我们中的许多人相对较晚才接触到嵌入式系统编程,因为我们在限制较少的平台上学习了我们的编码技能。除了算法的一般效率之外,我们不必过多担心硬件细节,但在嵌入式应用程序中,我们需要更加小心,当然是为了性能,还要适应我们想要做的实际限制我们的硬件目标,尤其是可用内存的类型和大小。这些系统中的内存是您必须将所有软件和所有工作数据装入其中的手提箱,而且手提箱通常比您希望的要小得多。
作为一个额外的复杂因素,这些系统中通常有不止一种类型的内存。为了保持编程简单,您只看到一个逻辑内存空间,但某些地址范围可能以不同的方式在硬件中实现。一些空间可以实现为外部主存储器,可以通过一级或多级高速缓存从处理器访问。
一个常见的硬件优化将实现另一个范围作为紧耦合内存 (TCM)。它与处理器位于同一芯片内,通常紧邻该处理器。TCM 为存储在该内存中的任何指令或数据提供有保证的单时钟周期访问,这与标准内存不同,标准内存只有在指令/数据已经在缓存中时才能提供该性能;否则它必须进入主存储器,花费更多的时钟周期。TCM 是(内存映射)快速片上内存的一个例子;还有其他用途,例如用于图像处理中快速访问的图像缓冲区。
另一个考虑因素 - 使用片上存储器可降低功耗,而使用主存储器会消耗更多功率,这要归功于更高的电流来驱动所有这些封装引脚和芯片之间的电路板互连。这是低功耗应用中的一个重要考虑因素。
为什么不只使用大的片上存储器并从片外不频繁地加载/存储?不幸的是,大型片上存储器显着增加了芯片面积,并且随着芯片尺寸的增长,该设备变得更加昂贵且竞争力下降。系统架构师必须非常小心地平衡性能增益与此成本,考虑他们是否可能仅提供 16KB 的 TCM 与可能多达 1MB 的 TCM。这让程序员有很多责任要尽可能节俭和谨慎地使用或规划这些存储器(如果你在早期的芯片架构中有发言权),尤其是在涉及到你想要的功能或数据时使用快速内存。
您需要在这里做的一些事情是相当明显的;我假设您从基于 PC 的实现或为早期产品开发的实现开始。由于您显然对 DSP 感兴趣,因此您可能计划进行大量浮点计算。尽可能将数据类型从双精度减少到单精度;仅此一项就可能将数据大小减半。
临时内存池是一种一次性分配内存块以满足多个较小相关分配需求的方法,它在分配和释放速度方面很受欢迎,但在内存方面可能非常昂贵。尝试将所有这些合并到一个内存池中,只要它们不并行使用或硬着头皮返回堆上的传统malloc;这可能会慢一些,但在内存中效率会高很多。
特别是在 TCM 方面,分析代码以找到消耗最多运行时间的函数。您的策略将是从需求最高的功能开始,决定其中哪些可以适合 TCM。当然,这里必须有一些判断。如果一个高需求函数调用一个低需求函数,你能负担得起从缓存中拉出那个低需求函数吗?只要缓存命中率很高,或者偶尔较长的延迟是可以容忍的,这可能就可以了。
在支持 MP3 和 FLAC 解码器的音乐播放器中,较长的延迟可能是可以的。每首歌曲最多只能使用一个,因此它们不需要都驻留在快速内存中。接受延迟加载所需的任何内容,按需从片外加载到快速存储器中。
您希望将生产代码和数据压缩到尽可能小的大小,因此作为一般良好卫生的一点,请确保所有调试、分析和日志记录代码都包含在编译指示中,这些编译指示可以在生产构建中禁用。在 PC 代码中,您可能不会太担心这一点(特别是如果您想在生产软件上运行调试器),但在这里它是必不可少的。相反,您还应该确保在 禁用该代码的情况下运行所有回归测试。只需要在调试中忽略一个运行时依赖项即可创建下游噩梦。
同样,请确保您的软件中的每一段代码都在被使用。运行覆盖测试。如果您发现未使用的代码,则可能是早期版本的遗留问题,可能需要它。这里不是,所以你应该能够摆脱它,对吧?再次,你必须小心。也许这是对一个不能忽视的非常罕见的情况的错误处理。也许它应该包含在回归测试中,但直接触发太难了。您必须根据与架构师甚至硬件团队的讨论做出决定。
最后,与架构师(如果需要,还有营销人员)争论他们要求包含哪些功能是真正必要的。他们可能没有意识到,在您可能想到的每一次优化之后,手提箱仍然不会关闭。然后他们将不得不决定可能不得不牺牲他们真正想要的真正酷的功能。或者,也许他们必须回到业务团队并要求更大的片上存储器,使用您可以提供的关于这些存储器需要增长多少的信息。无论哪种方式,你都会看起来不错!
审核编辑 黄昊宇
全部0条评论
快来发表一下你的评论吧 !