高能效软件编码
Posted
技术标签:
【中文标题】高能效软件编码【英文标题】:Power Efficient Software Coding 【发布时间】:2010-09-08 21:06:46 【问题描述】:在典型的手持/便携式嵌入式系统设备中,电池寿命是硬件、软件和设备可以支持的功能设计中的主要考虑因素。从软件编程的角度来看,人们知道 MIPS、内存(数据和程序)优化代码。 我知道 H/W 深度睡眠模式、待机模式,它们用于以较低的周期为硬件提供时钟,或者将时钟完全转到一些未使用的 circutis 以节省电力,但我正在从这个角度寻找一些想法:
我的代码在哪里运行并且需要继续执行,鉴于此,我如何才能有效地编写代码“功率”以消耗最少的功率?
是否有任何特殊的编程结构、数据结构、控制结构,我应该查看它们以实现给定功能的最低功耗。
在代码结构设计时或在低级设计期间是否应牢记任何软件高级设计注意事项,以使代码尽可能高效(最低功耗)?
【问题讨论】:
同意,这对我没用,但这是一个非常好的问题:) 何必麻烦 :-) 据我所知,手持设备中的大多数应用不再关注电池寿命 :-( 幸运的是,操作系统仍然如此 【参考方案1】:不要投票。使用事件和其他操作系统原语来等待可通知的事件。轮询可确保 CPU 保持活动状态并延长电池寿命。
【讨论】:
【参考方案2】:考虑尽可能少地使用网络接口。您可能希望收集信息并以突发方式发送出去,而不是不断发送。
【讨论】:
【参考方案3】:Zeroith,使用可以在空闲时停止的完全静态机器。你不能超过零赫兹。
首先,切换到无滴答操作系统调度程序。每毫秒左右醒来都会浪费电力。如果不能,请考虑减慢调度程序中断。
其次,确保你的空闲线程是省电的,等待下一个中断指令。 您可以在大多数小型设备所拥有的那种监管不足的“用户空间”中执行此操作。
第三,如果您必须投票或执行用户信任活动,例如更新 UI, 睡觉,做,然后继续睡觉。
不要相信你没有检查过“睡眠和旋转”类型代码的 GUI 框架。 尤其是您可能很想将事件计时器用于#2。
在读取时阻塞线程,而不是使用 select()/epoll()/WaitForMultipleObjects() 进行轮询。 给线程调度器(和你的大脑)带来压力,但这些设备通常都可以。 这最终会稍微改变您的高级设计;它变得更整洁! 一个轮询你可能做的所有事情的主循环最终会在 CPU 上变得缓慢和浪费,但确实保证了性能。 (保证很慢)
缓存结果,懒惰地创建东西。用户希望设备运行缓慢,所以不要让他们失望。少跑步更好。尽可能少地逃跑。 当您不再需要单独的线程时,可以将它们杀死。
尝试获得比您需要的更多的内存,然后您可以插入多个哈希表并节省搜索。如果内存是 DRAM,这是一个直接的权衡。
查看比您认为可能需要的更实时的系统。以后可以节省时间(原文如此)。 它们也能更好地处理线程。
【讨论】:
【参考方案4】: 如1800 INFORMATION
所说,避免轮询;订阅事件并等待它们发生
仅在必要时更新窗口内容 - 让系统决定何时重绘它
更新窗口内容时,确保您的代码尽可能少地重新创建无效区域
使用快速代码,CPU 可以更快地返回深度睡眠模式,并且此类代码更有可能保留在 L1 缓存中
一次性处理小数据,以便数据也保留在缓存中
确保您的应用程序在后台不执行任何不必要的操作
让您的软件不仅能省电,而且能感知电源 - 减少使用电池时更新图形的频率、禁用动画、减少硬盘抖动
并阅读其他一些guidelines。 ;)
最近一系列名为"Optimizing Software Applications for Power" 的帖子开始出现在英特尔软件博客上。可能对 x86 开发人员有用。
【讨论】:
【参考方案5】:根据我使用智能手机的工作,我发现保持电池寿命的最佳方法是确保禁用程序在特定时间点运行所需的一切。
例如,仅在需要时打开蓝牙,类似手机功能,在不需要时调低屏幕亮度,调低音量等。
这些函数使用的功能通常会远远超过您的代码使用的功能。
【讨论】:
我支持这个。如果您使用的是 PIC 等嵌入式微控制器,请禁用您不使用的外围设备,例如 A/D 转换器或串行端口。【参考方案6】:看看你的编译器生成了什么,特别是代码的热点区域。
【讨论】:
【参考方案7】:如果你有低优先级的间歇性操作,不要使用特定的定时器唤醒来处理它们,而是在处理其他事件时处理。
使用逻辑来避免您的应用可能会进入睡眠状态 10 毫秒然后必须再次唤醒以等待下一个事件的愚蠢情况。对于提到的那种平台,是否同时处理两个事件都无关紧要。 拥有自己的计时器和回调机制可能适合这种决策。权衡是代码复杂性和维护与可能的节能。
【讨论】:
【参考方案8】:简单地说,尽可能少做。
【讨论】:
【参考方案9】:还有一些重要的事情是降低数学运算的精度,选择可用的最小数据集,如果您的开发环境可用,则打包数据和聚合操作。
knuth 书籍可以为您提供节省内存或 CPU 所需的特定算法的所有变体,或者降低精度以最大限度地减少舍入误差
另外,花一些时间检查所有嵌入式设备 api - 例如,大多数 symbian 手机可以通过专门的硬件进行音频编码
【讨论】:
【参考方案10】:好吧,如果您的代码可以完全在处理器缓存中执行,那么您将有更少的总线活动并节省电力。如果您的程序足够小以将代码+数据完全放入缓存中,那么您将“免费”获得这种好处。 OTOH,如果您的程序太大,并且您可以将程序划分为或多或少独立于另一个的模块,则可以通过将其划分为单独的程序来节省电力。 (我想也可以制作一个工具链,将相关的代码和数据包分散到缓存大小的块中......)
我想,从理论上讲,您可以通过减少指针取消引用的次数以及重构您的跳转以便首先执行最有可能的跳转来节省一些不必要的工作——但这对于程序员来说是不现实的.
Transmeta 的想法是让机器在运行中进行一些指令优化以节省电力...但这似乎没有足够的帮助...And look where that got them.
【讨论】:
【参考方案11】:避免轮询是个好建议。
微处理器的功耗大致与其时钟频率和电源电压的平方成正比。如果您有可能通过软件调整这些,则可以节省一些电量。此外,关闭不需要的处理器部分(例如浮点单元)可能会有所帮助,但这在很大程度上取决于您的平台。在任何情况下,您都需要一种方法来测量处理器的实际功耗,以便找出哪些有效,哪些无效。就像速度优化一样,功耗优化也需要仔细分析。
【讨论】:
【参考方案12】:将未使用的内存或闪存设置为 0xFF 而不是 0x00。对于闪存和 eeprom 来说当然是这样,对于 s 或 d ram 不确定。对于舞会,存在反转,因此 0 存储为 1 并消耗更多能量,而 1 存储为零并消耗更少。这就是你在擦除一个块后读取 0xFFs 的原因。
【讨论】:
这好像是微优化中的微优化。【参考方案13】:尽快完成工作,然后进入空闲状态等待中断(或事件)发生。尝试用尽可能少的外部内存流量使代码用尽缓存。
【讨论】:
【参考方案14】:在 Linux 上,安装 powertop 以查看哪个软件唤醒 CPU 的频率。并遵循 powertop 站点链接的各种提示,其中一些可能也适用于非 Linux。
http://www.lesswatts.org/projects/powertop/
【讨论】:
你知道announced version 2.0 of PowerTop发生了什么吗?该链接不再可用。 回复很晚,google 很容易解决,但是 v2.0 已经发布了。 01.org/powertop【参考方案15】:选择快速且具有小基本块和最少内存访问的高效算法。
了解您的处理器的缓存大小和功能单元。
不要访问内存。如果它们将您的工作代码或数据集扩展到可用缓存之外,请不要使用对象或垃圾收集或任何其他高级构造。如果您知道缓存大小和关联性,请在低功耗模式下布置您需要的整个工作数据集并将其全部放入 dcache(忘记一些将数据分散在单独对象或数据中的“正确”编码实践)结构,如果这会导致缓存垃圾)。与所有子程序相同。如有必要,将您的工作代码集全部放在一个模块中,以便在 icache 中将其全部条带化。如果处理器具有多级高速缓存,请尽量适应最低级别的指令或数据高速缓存。不要使用浮点单元或任何其他可能会启动任何其他可选功能单元的指令,除非您可以很好地证明使用这些指令会显着缩短 CPU 退出睡眠模式的时间。
等等
【讨论】:
【参考方案16】:这个比较及时,今天Hackaday上关于测量各种命令功耗的文章: Hackaday: the-effect-of-code-on-power-consumption
除此之外: - 中断是你的朋友 - Polling / wait() 不是你的朋友 - 尽量少做 - 使您的代码尽可能小/高效 - 在 micro 中关闭尽可能多的模块、引脚、外设 - 尽可能慢地运行 - 如果 micro 具有引脚驱动强度、转换速率等设置。请检查并配置它们,默认值通常是全功率/最大速度。 - 回到上面的文章,回去测量一下功率,看看你是否可以通过改变一些东西来降低它。
【讨论】:
【参考方案17】:不要投票,睡觉
尽可能避免使用芯片的耗电区域。例如,乘数很耗电,如果你可以移位和加法,你可以节省一些焦耳(只要你不做太多移位和加法,实际上乘数就是赢了!)
如果你真的很认真,我会得到一个功耗感知调试器,它可以将功耗与你的源代码相关联。 Like this
【讨论】:
以上是关于高能效软件编码的主要内容,如果未能解决你的问题,请参考以下文章