打印
[信息]

【实战经验】浮点 DSP 运算效率不高

[复制链接]
2943|14
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 香水城 于 2017-8-17 10:08 编辑

浮点 DSP 运算效率不高

问题:
该问题由某客户提出,发生在 STM32F407IGT6 器件上。据其工程师讲述:由于在其产品中,需要使用STM32进行大量的浮点数以及浮点DSP运算,所以针对STM32的浮点数运算能力及 DSP 运算能力做了相关的测试,但测试结果不理想。STM32F407 在144MHz 主频下,对于表(一)程序的运算耗时为:9105uS。没有体现出硬件浮点运算应有的运算能力。
调研:
使用 Keil MDK4.21 创建工程对表(一)的程序进行测试。在工程设置中,选择支持浮点运算指令。将编译器的优化等级设置为 LEVEL1,然后编译运行。通过示波器测量主程序在调用该函数之前和在该函数返回之后在 I/O 管脚上所发出的脉冲之间的时间差,来判断 STM32 运行该函数所花费的时间。
1. 当 STM32 的主频为 168MHz,使用 SRAM2 存贮变量的条件下,测得时间消耗为:7840uS。修改工程设置,将内存的使用由 SRAM2 转成 CCM,重新编译、下载、运行,测得时间消耗为:7840uS。
2. 修改工程设置,将优化等级由 LEVEL1 换成 LEVEL3。为了避免编译器把整个测试函数优化掉,修改该函数如表(二)。重新编译、下载、运行,测得时间消耗为:7660uS。
3. 修改程序代码,将序函数 sin()和 cos()分别替换成 ARM DSP library 中的arm_sin_f32()和 arm_cos_f32(),如表(三)所示。重新编译、下载、运行,测得时间消耗为:748uS。
4. 修改代码,将计算中所用到的小数常量,表示成单精度,如表(四)所示。重新编译、下载、运行,测得时间消耗为:130uS。
结论:
三个方面的原因导致了计算效率降低:
1. 编译器的优化等级不够,以至生成的代码本身的效率低下;
2. 表达式上的漏洞,造成部分计使用了双精度浮点运算;
3. 三角函数库的选取不当,导致在计算正弦、余弦过程中引入了大量的双精度浮点运算;

处理:
1. 合理选用编译器的优化等级,提高代码的执行效率;
2. 在计算表达式中,强制常量为单精度浮点数,以避免引入双精度浮点数动算;
3. 选用 ARM 公司提供的,采用单精度浮点数优化的三角函数库,以避免由普通的数学函数库引入的双精度浮点数运算;

建议:
从应用角度看,Cortex-M4 可以认为是 Cortex-M3 的加强版。相对 Cortex-M3,Cortex-M4主要从两个方面进行了改进:
1. 增加了 DSP、SIMD 指令;
2. 增加了单精度浮点运算单元;
第 1 点使得 Cortex-M4 拥有高速的定点 DSP 处理能力,第 2 点则使得 Cortex-M4 拥有强大的数**算能力。受益于 Cortex-M4 的优异的处理性能,以及高效的总线与存贮器接口,STM32F4 系列 MCU 在数据处理方面有着非凡的表现。不过,要使硬件上的性能得以充分的发挥,除了对算法本身进行优化以外,对一些相关因素也要仔细斟酌:
1. 恰当的设置 Flash 缓冲区的参数。在 STM32F4 中,为了匹配 Flash 存贮器与CPU 之间的对数据、指令的吞吐速率,设有指令缓冲区和数据缓冲区。复位后缓冲区是不工作的,需要软件予以开启,并设置恰当的等待周期数。没有缓冲区的参与,运行在 Flash 中的程序,在运效率上会大幅度的降低。
2. 选择高效的存贮器来存放数据。快速的数据存取是保证 CPU 不间断的执行指令的前提。这一点上,不仅要考查存贮器本身的速率,还要看是否有其它的处理单元与 CPU 分享该存贮器。比如,在 STM32F4 中,将数据放在 CCM 存贮器中,要比放在 SRAM1 中更能保证 CPU 对数据的存取速率,因为 CCM 存贮器是 CPU独享的,而 SRAM1 还可能被 DMA 访问。
3. 根据 CPU 指令集的特点,合理的选取计算的数据类型。比如,要计算 16 位的DSP 运算,最好把变量和常量定义成 16位数据,这样有利于编译器使用 SIMD指令对代码进行优化。在单精度浮点数能够满足要求的情况下,将变量或常量定义成单精度类型,有利于编译器使用单精度浮点运算指令,对代码优化。
4. 选择针对 Cortex-M4 进行优化的数学函数库。ARM 公司为 Cortex_M4 的提供了一整套的 DSP、浮点数运算库,其效率远高于编译器自带的函数库。
5. 编译器的优化等级是一个重要的设置选项,不同的优化等级下,所生成的代码的效率是有很大差别的。
6. 对于高频次使用的数据,要考虑放在寄存器类型的变量中。通常,CPU 存取操作数的最快捷的方式是寄存器寻址,可以做到零时钟花费。
7. 合理安排计算次序,考虑是否可以以乘法代替除法。在数学中,乘法和除法是一对逆运算,除以一个数与乘于这个数的倒数可以等同起来。然而在 CPU 的指令实现中,乘法和除法的计算速度上是有很大差别的,通常乘法的计算速度远高于除法的计算速度。所以,有必要在运算中,使用乘法来代替除法。比如: a÷b÷c可以使用a÷(b×c)来代替。
8. 找出算法中的重复计算,将其合并,只计算一次。对这样的计算,完全可以在第一次计算之后,将结果放在中间变量中,而在后面的计算中直接引用。
9. 对于复杂的计算,考虑是否能用查表来代替。查表是一种快速得出结果的好方法,它以牺牲存贮器空间来换取速度。在存贮器空间不是很紧张的情况下,用查表代替计算还是很划算的。

对应的PDF:浮点DSP运算效率不高
更多实战经验请看:【ST MCU实战经验汇总贴】


沙发
55854234| | 2015-8-24 09:50 | 只看该作者
顶版主 学习了

使用特权

评论回复
板凳
kseeker| | 2015-8-24 10:37 | 只看该作者
我觉得lz的分析没到点子上。整个过程里面提升最大的一步是专用库函数的使用,其次是双精度到单精度的替换。只有在汇编等级优化才能充分利用DPS能力,编译器自动优化能做的通常非常有限。然后DSP模块应该是针对单精度优化的,所以双精度和单精度差异巨大。lz的分析主要是针对普通程序的,什么flash,sram的影响有,但没有质变。看见问题描述,第一反映应该是DPS模块没有被充分利用,之后再说其它的。

使用特权

评论回复
地板
kseeker| | 2015-8-24 10:43 | 只看该作者
DSP能力的充分利用需要了解cpu的架构,针对性的设计算法。这就是为什么厂商的库函数效率出奇的高的原因。

使用特权

评论回复
5
mmuuss586| | 2015-8-24 12:28 | 只看该作者

学习了,以后都改成单精度;

使用特权

评论回复
6
米尔豪斯| | 2015-8-24 15:17 | 只看该作者
只有在汇编等级优化才能充分利用DPS能力,编译器自动优化能做的通常非常有限。
都是大神,学习了

使用特权

评论回复
7
lefeng| | 2015-8-28 20:30 | 只看该作者
整个过程里面提升最大的一步是专用库函数的使用,其次是双精度到单精度的替换

使用特权

评论回复
8
598330983| | 2015-8-28 20:33 | 只看该作者
。查表是一种快速得出结果的好方法,它以牺牲存贮器空间来换取速度

使用特权

评论回复
9
734774645| | 2015-8-28 21:04 | 只看该作者
学习了,以后都改成单精度

使用特权

评论回复
10
玛尼玛尼哄| | 2015-8-28 21:06 | 只看该作者
最好少用浮点运算比较好。

使用特权

评论回复
11
冰河w| | 2015-8-28 21:31 | 只看该作者
只有在汇编等级优化才能充分利用DPS能力,编译器自动优化能做的通常非常有限

使用特权

评论回复
评论
zhslcd 2015-8-28 21:43 回复TA
用专门优化的函数库是可以的。不用自己写,人家的函数库就是最好的了,人家函数是汇编专家写的 
12
zh113214| | 2015-8-29 08:43 | 只看该作者
不错啊,楼主总结的很好,学习了(^_^)

使用特权

评论回复
13
冰河w| | 2015-9-9 22:17 | 只看该作者
DSP处理算法还是可以的

使用特权

评论回复
14
z994051| | 2017-3-2 13:46 | 只看该作者
谢谢版主,解决了我困扰的问题

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:意法半导体(中国)投资有限公司
简介:STM32技术专家

596

主题

17106

帖子

287

粉丝