
浮点 DSP 运算效率不高 1 A" i( z. }" w2 x M2 @, s3 h问题:3 F% n1 N! A: G) ~! K+ Y 该问题由某客户提出,发生在 STM32F407IGT6 器件上。据其工程师讲述:由于在其产品中,需要使用STM32进行大量的浮点数以及浮点DSP运算,所以针对STM32的浮点数运算能力及 DSP 运算能力做了相关的测试,但测试结果不理想。STM32F407 在144MHz 主频下,对于表(一)程序的运算耗时为:9105uS。没有体现出硬件浮点运算应有的运算能力。$ a) ^; z4 b7 J# V6 E2 z S ![]() 使用 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。6 Q5 I7 h: B/ h% U 4. 修改代码,将计算中所用到的小数常量,表示成单精度,如表(四)所示。重新编译、下载、运行,测得时间消耗为:130uS。/ ?+ L- `0 _8 w$ k ![]() ![]() 三个方面的原因导致了计算效率降低: 1. 编译器的优化等级不够,以至生成的代码本身的效率低下; 2. 表达式上的漏洞,造成部分计使用了双精度浮点运算; 3. 三角函数库的选取不当,导致在计算正弦、余弦过程中引入了大量的双精度浮点运算; 处理:$ r: h) v( M! p% ^- Q 1. 合理选用编译器的优化等级,提高代码的执行效率; 2. 在计算表达式中,强制常量为单精度浮点数,以避免引入双精度浮点数动算; 3. 选用 ARM 公司提供的,采用单精度浮点数优化的三角函数库,以避免由普通的数学函数库引入的双精度浮点数运算;3 a2 i0 l+ I# Y; o8 W+ X 建议: 从应用角度看,Cortex-M4 可以认为是 Cortex-M3 的加强版。相对 Cortex-M3,Cortex-M4主要从两个方面进行了改进: 1. 增加了 DSP、SIMD 指令;, [+ O; P1 g# x! q; n$ \ 2. 增加了单精度浮点运算单元;( Z* W* ]4 _% z) r: B1 g P 第 1 点使得 Cortex-M4 拥有高速的定点 DSP 处理能力,第 2 点则使得 Cortex-M4 拥有强大的数**算能力。受益于 Cortex-M4 的优异的处理性能,以及高效的总线与存贮器接口,STM32F4 系列 MCU 在数据处理方面有着非凡的表现。不过,要使硬件上的性能得以充分的发挥,除了对算法本身进行优化以外,对一些相关因素也要仔细斟酌: 1. 恰当的设置 Flash 缓冲区的参数。在 STM32F4 中,为了匹配 Flash 存贮器与CPU 之间的对数据、指令的吞吐速率,设有指令缓冲区和数据缓冲区。复位后缓冲区是不工作的,需要软件予以开启,并设置恰当的等待周期数。没有缓冲区的参与,运行在 Flash 中的程序,在运效率上会大幅度的降低。2 Y$ G$ w8 e, K' B& k) l# W 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. 对于复杂的计算,考虑是否能用查表来代替。查表是一种快速得出结果的好方法,它以牺牲存贮器空间来换取速度。在存贮器空间不是很紧张的情况下,用查表代替计算还是很划算的。- K2 }1 x% I3 Q! g, B' f 转载自21ic:http://bbs.21ic.com/icview-1070644-1-1.html) f) L& s% h+ a5 n" k7 w# k1 Q |
F7也不是都是双精度的FPU,低端的还是搭载单精度FPU,但是比M4核的效率是高了40%,如果换做双精度的F7,估计效率会更高。
$ V# Y( D; V* F+ ]; ~8 R; O% a; X( x
原贴总体思路是对的,部分分析可能不太准确;依照原贴的思考方向,自己也重新进行了测试
一、上靓照0 J9 @+ s; W- P$ Q/ |9 ~; ~0 n) [9 h
脱光了
: Q- [& e1 a: d
' I8 w! ^7 G# s2 e
二、对比F407浮点运算
运行于168M,三种模式运行时间对比% K6 C( K! y$ c
主循环 ~) m3 a5 M$ K) [( T
函数后面的时间标注是通过串口打印出来的时间测试值,测试方法是1us定时器累加,函数执行前后时间差就是执行时间。此处可看出DSP库函数的强大这里要注意!小数点后面不加f的编译器会自动转为双精度浮点数,而M4核和DSP库函数都是只支持单精度浮点数,就会导致运算速度降低,切记!!!/ }- g6 X3 J, _6 m
什么情况嘛,还不如M4,肯定哪里设置错了...4 X4 \+ o) Q" d
+ y9 Z8 ^9 f$ Y1 {, M9 R* U
这个选项M1和M4可没有,点开看看
紧耦合内存技术(TCM),该功能打开,实测在这种应用中作用不大8 A( q4 e7 d/ `1 I
打开CPU的ICache8 P. k) S3 k' h/ j+ s! @9 _( V' H
再次测试
再打开CPU的DCache
测试结果
看来TCM接口要配合Cache的使用才有作用下面还有内存管理器MPU的配置,这里没用到,大型应用(比如linux移植应用)更如鱼得水了, @$ c% z/ A5 i/ ?
对比M4的测试是不是有什么问题?# X1 _& m3 |- U# y( V
最后把频率提升到216M也没见结果有什么影响......不应该呀; L. T' b/ x5 p+ F5 H* b
原来自己犯了个错误,时钟改了,定时器的1us没改,导致结果错误,重新修改编译,结果是
先到240M试试
; b+ c! k' Z: C+ I' ]
280M7 F1 m6 i, H; O. V
) ~* t; U' q% T& p6 Q3 l
300M
310M. y& e9 S$ o+ J. H) H, {2 W/ z, z
几分钟后死机4 p9 e5 E2 m0 U; e8 Q) w% p# I/ O
320M直接都没反应了。。。。。。5 I) w- a- X0 s. I1 X7 }
看来也就300M左右可以发挥一下了
补充一下CUBEMX针对F7特有的配置MPU6 B$ t, G+ P5 h q+ U* s- q
MPU管理模式有四种- A3 a Z, u1 S/ I5 x
MPU管理单元有8个2 C; C- p: Y% P( F; Z" d/ n
每个MPU管理单元可配置内存地址范围和管理方式
重新回到二楼的flash 接口选择,分别为AXI和ITCM总线,看总线图" L' F" w' p7 }: d- z; j& _; e
AXI总线是通过转接AHB总线与flash相连,大家知道flash是低速存取设备,因此使用该总线会在调取指令时插入空指令来弥补flash读取指令时候的空白指令周期,因此也拖慢了系统执行指令的速度. {2 g x2 V( B" c8 u
而使用ITCM总线是三种模式,第一种是不开ART直接读取flash,与AXI总线差不多,优点是不占用AHB总线
第二种是开ART,ART(Adaptive Real-Time Memory Accelerator 即 自适应实时存储器加速器),主要功能是弥补高速cpu与相对低速flash指令读取之间的矛盾。当指令flash读取速度足够快,cpu就可以相应提速。这句话载自网络,没太理解,大概意思就是发挥flash的读取极限,但是仍然跟不上CPU的速度。
第三种是使用ITCM内存的情况下开ART,这种模式就牛逼了,ART存取和预取的指令都存放到一片SRAM内存中,大部分指令(比如循环体和重载函数)都可以从这片RAM中取指令,就不用到flash读取了,因此执行指令就可以0等待了,这时才发挥CPU的全部能力5 [+ Q" w; `9 |) ]2 L
看看我的测试,在168M下开ITCM能提升将近一倍的速度。
! {, o, n' y R# X
看看ITCM和DTCM在存储空间的映射,他们不再一个区域。DTCM和SRAM在一起,功能也相近;ITCM映射到了和flash一个区,根据功能确定的。但是具体使用地址是在映射接口区0x00200000----0x0027ffff) K3 }) i' h: c) ^
/*用默认math.h和单精度浮点数测试*/3 V2 f2 z: W# n- {5 l6 F0 }$ |
{. g, T, a; `# ?
uint16_t i=0;2 R6 {. g- z* G* s0 z0 J
float Tr=0.0f;/ S2 l s* J3 b( J6 _/ g6 |5 j$ D% g
float Ti=0.0f;) l* Y' L% x* q S; ?
float Temp=0.0f;
for(i=0;i<1000;i++); L- e" U1 Y$ N7 i/ @
{
Tr+=1.0f;
Ti+=10.0f;
Temp=Ti-Tr*cos(2.0f*PI*i/N)+Ti*sin(2.0f*PI*i/N);. q' { l0 g" B4 u0 B
}' T% q" w( M! a. d% ~
}
void Test2(void)) A0 W: @# p) H P' J; ?6 z' B `
/*用默认math.h和双精度浮点数测试*/9 Q i# ?, a+ k% D
{
uint16_t i=0;6 @4 r& Q( r! H' P1 O! R( n7 s
float Tr=0.0;$ ^$ r. L! f% [- f. J9 W
float Ti=0.0;4 E+ J5 I1 A9 i1 P3 L
float Temp=0.0;; E' k: ]; f1 O+ r# X% h [
for(i=0;i<1000;i++)4 F6 J4 `) {/ b
{
Tr+=1.0;
Ti+=10.0;
Temp=Ti-Tr*cos(2.0*PI*i/N)+Ti*sin(2.0*PI*i/N);6 p7 B/ B7 g9 ~6 V% i0 C- y
}
}7 t( \: ]6 a3 p6 W- {
void Test3(void)
/*用DSP库和单精度浮点数测试*/
{
uint16_t i=0;2 j7 a, |/ d/ N
float Tr=0.0f;3 r' a7 `6 n4 o
float Ti=0.0f;3 Q' ]+ A$ Y3 T% e) Y
float Temp=0.0f;
for(i=0;i<1000;i++)7 L ], h3 T& x5 \
{+ K$ f+ D _8 g& @/ H. g
Tr+=1.0f;$ r% e; c* D9 q- Z1 s) R9 `
Ti+=10.0f;
Temp=Ti-Tr*arm_cos_f32(2.0f*PI*i/N)+Ti*arm_sin_f32(2.0f*PI*i/N);
}. q3 u3 a" D" m b( w
}
void Test4(void): ?9 S+ t; L2 b/ B3 c% |) U; f
/*用DSP库和双精度浮点数测试*/
{) V8 U# m& g4 M) ?
uint16_t i=0;
float Tr=0.0;+ D% h4 s* I% f2 d5 N5 m
float Ti=0.0;
float Temp=0.0;
for(i=0;i<1000;i++)
{6 L4 R- r2 u3 N' a2 c' q
Tr+=1.0;/ e8 \5 C$ N% ?1 a
Ti+=10.0;% _! k" E( e; w. f
Temp=Ti-Tr*arm_cos_f32(2.0*PI*i/N)+Ti*arm_sin_f32(2.0*PI*i/N);
} Q& J6 i8 g/ N+ A1 d
}, c0 j/ C3 l1 [. i& {" G
6 o! N$ q3 N: A7 }- |+ a
是不是可以这样,综述一下:
虽然STM32F4的DSP单位时间内的处理能力有些吃力,但STM32F7的DSP处理能力已经能满足基本需求了。
望大师指点
因为我用的F722,是不带双浮点FPU单元的;而你用的F767是带双浮点FPU单元的;所以767在处理双浮点数上面是有优势的。
通过你的实验也反应出双浮点单元在处理数据上面,如果数据精度要求不高的话,单精度比双精度数据处理速度上还是有一点点优势的; _1 A, a( Q. ~+ {