关于嵌入式:高效软件编码

关于嵌入式:高效软件编码

Power Efficient Software Coding

在典型的手持/便携式嵌入式系统设备中,电池寿命是H / W,S / W和设备可以支持的功能设计中的主要问题。从软件编程的角度来看,人们知道MIPS,内存(数据和程序)优化的代码。
我知道H / W深度睡眠模式,即待机模式,可用于以较低的周期为硬件计时或将时钟整体转向一些未使用的电路以节省功耗,但是我正在从这一角度寻找一些想法:

在我的代码正在运行且需要继续执行的地方,鉴于此,我如何才能有效地编写代码"电源"以消耗最小的瓦特?

我是否应该查看任何特殊的编程结构,数据结构,控制结构,以实现给定功能的最低功耗。

在进行代码结构设计时或在进行低级设计时,是否应牢记一些软件高级设计注意事项,以使代码尽可能高效(省电)?


  • 就像1800 INFORMATION所说的那样,避免轮询;订阅事件并等待事件发生
  • 仅在必要时更新窗口内容-让系统决定何时重绘窗口内容
  • 更新窗口内容时,请确保您的代码重新创建尽可能少的无效区域
  • 使用快速代码,CPU可以更快地返回深度睡眠模式,并且这样的代码更有可能保留在L1缓存中
  • 一次处理小数据,因此数据也保留在缓存中
  • 确保您的应用程序在后台运行时不执行任何不必要的操作
  • 使您的软件不仅高效节能,而且还具有节能意识-电池供电时更新图形的频率降低,禁用动画,减少硬盘抖动

并阅读其他指南。 ;)

最近,一系列名为"为电源优化软件应用程序"的文章开始出现在英特尔软件博客上。可能对x86开发人员有用。


Zeroith,请使用可以在空闲时停止的全静态计算机。您不能击败零赫兹。

首先,切换到无滴答的操作系统调度程序。唤醒每一毫秒都会浪费能量。如果不能,请考虑减慢调度程序中断的速度。

其次,确保您的空闲线程是节能的,等待下一个中断指令。
您可以通过大多数小型设备所拥有的,被监管不足的"用户区"来执行此操作。

第三,如果您必须轮询或执行用户信心活动(例如更新用户界面),
睡觉,去做,然后重新入睡。

不要信任尚未检查"睡眠和旋转"类代码的GUI框架。
特别是事件计时器,您可能很想在#2中使用。

在读取时阻止线程,而不是使用select()/ epoll()/ WaitForMultipleObjects()进行轮询。
给线形scheuler(和您的大脑)施加压力,但是设备通常还可以。
最终会稍微改变您的高级设计;它变得更整洁!
轮询您可能做的所有事情的主循环最终会在CPU上缓慢而浪费,但可以保证性能。 (保证慢)

缓存结果,懒惰地创建事物。用户希望设备运行缓慢,因此不要让他们失望。跑步越少越好。尽可能少地奔跑。
当您不再需要单独的线程时,可以将它们杀死。

尝试获取比您需要的更多的内存,然后可以将其插入多个哈希表中并保存以前的搜索。如果内存是DRAM,则这是直接的权衡。

查看您认为可能需要的实时系统。这样可以节省时间(原文如此)。
他们也更好地处理线程。


从我使用智能手机的工作来看,我发现保留电池寿命的最佳方法是确保禁用程序在特定时间点所需的所有功能。

例如,仅在需要时打开蓝牙,类似手机的功能,在不需要时降低屏幕亮度,调低音量等。

这些功能使用的功能通常将远远超过代码使用的功能。


不要轮询。使用事件和其他操作系统原语等待可报告的事件。轮询可确保CPU保持活动状态并使用更长的电池寿命。


避免轮询是一个很好的建议。

微处理器的功耗与时钟频率和电源电压的平方大致成比例。如果您可以通过软件调整这些设置,则可以节省一些电量。另外,关闭不需要的处理器部分(例如浮点单元)可能会有所帮助,但这在很大程度上取决于您的平台。无论如何,您都需要一种方法来测量处理器的实际功耗,以便找出有效的方法和无效的方法。就像速度优化一样,功率优化也需要仔细分析。


好吧,就您的代码可以完全在处理器缓存中执行的程度而言,您的总线活动将减少,并可以节省功耗。如果您的程序足够小,可以完全将代码和数据容纳在缓存中,那么您将获得"免费"的好处。 OTOH,如果您的程序太大,并且可以将程序划分为彼此独立的模块,则可以通过将其划分为单独的程序来节省一些电能。 (我想也可以制作一个工具链,将相关的代码和数据束扩展为缓存大小的块...)

我认为,从理论上讲,您可以通过减少指针取消引用的次数以及重构跳转以使最可能的跳转首先执行而节省一些不必要的工作,但这对于程序员来说是不现实的。

Transmeta的想法是让机器即时执行一些指令优化以节省功耗。但是,这似乎并没有提供足够的帮助。


考虑最少使用网络接口。您可能希望收集信息并突发发送,而不是不断发送。


查看您的编译器生成的内容,尤其是对于代码的热门区域。


如果您具有低优先级的间歇操作,请不要使用特定的计时器唤醒以处理它们,而要在处理其他事件时进行处理。

使用逻辑避免愚蠢的情况,您的应用可能会休眠10毫秒,然后必须为下一个事件再次唤醒。对于所提到的那种平台,两个事件是否同时处理并不重要。
具有自己的计时器和回调机制可能适合于此类决策。需要权衡的是代码复杂性和维护与可能的节能。


简而言之,要做的越少越好。


将未使用的内存或闪存设置为0xFF,而不是0x00。对于flash和eeprom,当然确实如此,不确定s或dram。对于舞会,存在一个反转,因此0被存储为1并消耗更多的能量,而1被存储为零而消耗较少的能量。这就是为什么在擦除一个块后读取0xFFs的原因。


不要轮询,睡觉

尽可能避免使用芯片上需要大量电的地方。例如,乘数器非常耗电,如果您可以移位和加数,则可以节省一些焦耳(只要您不做太多移位,并且加倍数实际上是一个胜利!)

如果您真的很认真,请使用电源意识的调试器,该调试器可以将电源使用情况与源代码相关联。像这样


尽快完成工作,然后进入一些空闲状态等待中断(或事件)发生。尝试使代码用尽缓存,并尽可能减少外部存储器流量。


在Linux上,安装powertop以查看哪个软件唤醒CPU的频率。并遵循powertop站点链接到的各种技巧,其中一些技巧也可能适用于非Linux。

http://www.lesswatts.org/projects/powertop/


选择快速的高效算法,这些算法具有较小的基本块和最少的内存访问。

了解处理器的缓存大小和功能单元。

不要访问内存。如果对象,垃圾收集或任何其他高级构造将您的工作代码或数据集扩展到可用缓存之外,请不要使用它们。如果您知道缓存的大小和关联性,请在低功耗模式下布局所需的全部工作数据集,然后将其全部放入dcache中(忘记一些将数据分散在单独的对象或数据中的"适当"编码做法结构(如果这会导致缓存垃圾)。与所有子例程相同。如有必要,将所有工作代码集放在一个模块中,以将其全部分拆到icache中。如果处理器具有多个高速缓存级别,请尝试使用最低级别的指令或数据高速缓存。除非可以很好地证明使用这些指令会大大缩短CPU进入睡眠模式的时间,否则不要使用浮点单元或任何其他可能打开其他可选功能单元电源的指令。

等等


相当及时的是,今天在Hackaday上有关测量各种命令的功耗的文章:
Hackaday:代码对功耗的影响

除此之外:
-打扰是你的朋友
-轮询/ wait()不是您的朋友
-尽量少做
-使您的代码尽可能小/高效
-在微型计算机中关闭尽可能多的模块,引脚,外围设备
-尽可能缓慢地运行
-如果微控制器具有引脚驱动强度,压摆率等设置,请检查并配置它们,则默认设置通常为全功率/最大速度。
-返回上面的文章,返回并测量功率,看看是否可以通过改动来降低功率。


同样不容易的事情是降低数学运算的精度,选择可用的最小数据集,如果开发环境打包数据和聚合运算可用,则使用最小的数据集。

knuth书籍可能会为您提供节省内存或cpu所需的特定算法的所有变体,或降低精度以最大程度地减少舍入误差

此外,还花了一些时间检查所有嵌入式设备api-例如,大多数symbian手机可以通过专用硬件进行音频编码


推荐阅读