打印

【STM32F0实验】FLASH 等待周期对性能影响的测试

[复制链接]
6880|15
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
airwill|  楼主 | 2012-8-9 20:06 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
做了个程序, Systick 和 main() 的while 循环. 完成简单的处理. 并测量使用的 CPU 时间(每秒).
设定不同的频率和FLASH 等待周期, 对比这个使用的 CPU 时间. 得到下面的数据.
测试条件: STM32F0-Discovery, Keil MDK 4.54, 优化级别3.
24MHz 条件下, FLASH 零个等待周期 0x1AD, 一个等待周期 0x1F1,  两个等待周期 0x275.
32MHz 条件下, FLASH 零个等待周期 0x141, 一个等待周期 0x175,  两个等待周期 0x1D8.
36MHz 条件下, FLASH 零个等待周期 0x11E, 一个等待周期 0x14B,  两个等待周期 0x1A3.
48MHz 条件下, FLASH 一个等待周期 0xF9, 两个等待周期 0x13B.
52MHz 条件下, FLASH 一个等待周期 0xE5, 两个等待周期 0x122.
56MHz 条件下, FLASH 一个等待周期 0xD5, 两个等待周期 0x10D.
60MHz 条件下, FLASH 一个等待周期 0xC7, 两个等待周期 0xFC.
64MHz 条件下, FLASH 一个等待周期 0xBA, 两个等待周期 0xEB.
    由于是每秒的CPU 占用时间. 可以直接对比数据来评判性能. 数字越小性能越高. 数字间的比例关系也等同于性能间的比例关系.
可见等待周期对 CPU 的性能影响很大.
24MHz 零等待的性能超过 36Mhz 两个等待周期的性能.
36MHz 零等待的性能超过 52Mhz 两个等待周期的性能.
通常这样的测试跟执行的指令有很大关系, 为此增加特别的指令再来测试
1. 增加 delay() 类延时.
;;;28      do ; while (--x);
000004  1e40              SUBS     r0,r0,#1
000006  d1fd              BNE      |L3.4|
48MHz 条件下, FLASH 一个等待周期 0xB3F7, 两个等待周期 0xB43F.
36MHz 条件下, FLASH 零个等待周期 0xEFD2, 一个等待周期 0xF005,  两个等待周期 0xEF7E.
等待周期对这样操作没有影响. 因为 FLASH 指令在缓冲中, 执行中没有读 FLASH  的操作.
2. 增加 strsum() 类数据读.
                  |L3.8|
000008  5c53              LDRB     r3,[r2,r1]
00000a  1818              ADDS     r0,r3,r0
;;;33      while (--x);
00000c  1e49              SUBS     r1,r1,#1
00000e  d1fb              BNE      |L3.8|
48MHz 条件下, FLASH 一个等待周期 0x7DCE, 两个等待周期 0xA1BD. (0X9F29)
36MHz 条件下, FLASH 零个等待周期 0xA79C, 一个等待周期 0xA7CB,  两个等待周期 0xD7BB.
有大量的 SRAM 读指令. 两个等待周期对性能的影响比较大.
3. 增加 strset() 类数据初始化.
000004  4a02              LDR      r2,|L3.16|
000006  21ff              MOVS     r1,#0xff
;;;32      do abdat[x] = 0xFF;
                  |L3.8|
000008  5411              STRB     r1,[r2,r0]
;;;33      while (x--);
00000a  1e40              SUBS     r0,r0,#1
00000c  d2fc              BCS      |L3.8|
48MHz 条件下, FLASH 一个等待周期 0x7DCF, 两个等待周期 0x6C47.
36MHz 条件下, FLASH 零个等待周期 0x17F4, 一个等待周期 0x1BF3,  两个等待周期 0x188F.
36MHz 条件下, FLASH 零个等待周期 0x8FD8, 一个等待周期 0xA7D2,  两个等待周期 0x9073.
有大量写 SRAM 的指令. 很奇怪, 两等待周期的性能会快与一个等待, 并接近零等待?!
4. 增加 strget() 类数据移动.
;;;37      do abdat[0] = abdat[x];
000002  4903              LDR      r1,|L3.16|
000004  01c0              LSLS     r0,r0,#7              ;36
                  |L3.6|
000006  5c0a              LDRB     r2,[r1,r0]
000008  700a              STRB     r2,[r1,#0]
;;;38      while (--x);
00000a  1e40              SUBS     r0,r0,#1
00000c  d1fb              BNE      |L3.6|
48MHz 条件下, FLASH 一个等待周期 0xA170, 两个等待周期 0xD733(0xCC3A).
36MHz 条件下, FLASH 零个等待周期 0xBF5A, 一个等待周期 0xD754,  两个等待周期 --  溢出.
36MHz 条件下, FLASH 零个等待周期 0x9657, 一个等待周期 0xA930,  两个等待周期 0xE182.
有大量的读写 SRAM 的指令, 两个等待周期的性能明显很差. 比零等待差了 1/3!
5. 增加 strcpy() 类数据移动.
;;;32      do abdat[x] = abdat[x+15];
                  |L3.4|
000004  180a              ADDS     r2,r1,r0
000006  7bd2              LDRB     r2,[r2,#0xf]
000008  540a              STRB     r2,[r1,r0]
;;;33      while (x--);
00000a  1e40              SUBS     r0,r0,#1
00000c  d2fa              BCS      |L3.4|
48MHz 条件下, FLASH 一个等待周期 0x8C71, 两个等待周期 0xA89F. (0xB1AA)
36MHz 条件下, FLASH 零个等待周期 0xA889, 一个等待周期 0xBB55,  两个等待周期 0xE0E6.
关于 FLASH 的 "预取指缓冲区", 数据手册上这么描述:
    预取指缓冲区分3块,每块8个字节,其中的内容与Flash相同,能够完全替代一次同样大小
的读取访问。    当预取缓冲区中存在至少一块可用空间时,预取控制器会发起一次读取请求。
    上面的测试中, 所有的测试循环体都不超过 5 条指令. 理论上讲, 如果预取存在分支预测, 那么执行循环时, 只要读一次 FLASH 指令后, 都不会再读了, 等待周期都不会影响性能测试结果.
    所以, 感觉 FLASH 的预取指缓冲管理应该还有改进的地方.
沙发
hsbjb| | 2012-8-9 20:36 | 只看该作者
论坛里面的高手还真不少

使用特权

评论回复
板凳
火箭球迷| | 2012-8-9 20:52 | 只看该作者
有些问题自己动手测试还是很有必要的

使用特权

评论回复
地板
sinadz| | 2012-8-9 20:58 | 只看该作者
论坛里面的高手还真不少
hsbjb 发表于 2012-8-9 20:36

高手都比较有思想:lol

使用特权

评论回复
5
txcy| | 2012-8-9 21:08 | 只看该作者
我是来向高手学习的

使用特权

评论回复
6
airwill|  楼主 | 2012-8-10 18:48 | 只看该作者
经进一步测试, 发现等待数增加3,4,5 也都能影响性能. 看来更多的等待周期也被支持了.

使用特权

评论回复
7
efen| | 2012-9-20 15:17 | 只看该作者
学习:lol

使用特权

评论回复
8
lut1lut| | 2012-10-24 14:20 | 只看该作者
没看懂,按照STM32F0的数据手册

STM32F0不是最高只跑到48MHz么?

不是24MHz以上,48MHz以下,需要1个等待周期么?

使用特权

评论回复
9
airwill|  楼主 | 2012-10-24 19:44 | 只看该作者
呵呵. 楼上看资料很认真啊.
那只是 STM32 官方的推荐用法. 是稳定可靠运行的保守配置.
我这里只是测试, 测试嘛, 当然可以抛开一些条条框框, 想怎么折腾就怎么折腾.
当然也顺便看看, 芯片还有多少隐藏的潜力哪
当然, 正式产品中, 不建议象我测试的那些设置来设定运行条件.

使用特权

评论回复
10
lut1lut| | 2012-10-25 16:00 | 只看该作者
本帖最后由 lut1lut 于 2012-10-25 16:02 编辑

LZ很有专研精神,佩服佩服。按照你这个话题我也做了一下测试:

首先,F0的预取指令队列是3块*4字节/块;所以说F0的闪存宽度是32位;即prefetch controller读一次闪存,读出32位来,放到一个快中。

第二,我胆小,严格按照手册上的参数做的测试

CASE1,24MHz,闪存无等待
CASE2,28MHz,闪存插入一个等待周期,使能Prefetch
CASE3,28MHz,闪存插入一个等待周期,关闭Prefetch (CASE3这里不做进一步讨论,它总归比CASE2差些)

测试的目标是在固定时间内,执行while(1)里面的test++,自加的次数:那么数字越高,性能越好

在代码速度优化最高的情况下,循环体内有4条指令,那么测试结果 CASE2 > CASE1,这正说明由于3*4字节的预取指队列,使得循环时不再从闪存取指令了,就在prefetch中就有

在代码没有任何优化的情况下,循环体内有6条指令,那么测试结果 CASE1 > CASE2。这和LZ的结论一样,这样看来貌似prefetch没有起到作用?

分析下来,这6条指令不能,除了第一次,就再也不会同时出现在6个半字的Prefetch队列中。因为你在执行第5、第6条指令时,prefetch会把排在第6条指令后的无效数据填到空闲的prefetch块中,那么就覆盖了之前的第1条和第2条指令。那么第6条指令执行完毕发现要跳转了,才发现新被load进来的无效指令是没用的,本来要从第6条指令跳转到第1条指令,但是刚才被覆盖了。。。 所以就要去吭哧吭哧的去读闪存了。

第三,你提到的“预取存在分支预测”。 我只看到说Cortex-M0的内核是“带分支预测(branch speculation)的3级流水线”。是内核的,不是闪存这一块的吧。那个branch speculation是为了避免指令跳转时清空流水线。

使用特权

评论回复
11
airwill|  楼主 | 2012-10-25 21:02 | 只看该作者
预取存在分支预测, 我的理解是预测并prefetch.
按照 Pentium 的分支预测的介绍, 是遇到分支指令时, 将分支转向的地址的代码提前装入指令队列. 避免清空流水线导致的取指延时

使用特权

评论回复
12
dfsa| | 2012-10-25 23:16 | 只看该作者
没太看明白

使用特权

评论回复
13
pkat| | 2012-10-25 23:23 | 只看该作者
很佩服LZ,有时间也做一下类似的测试

使用特权

评论回复
14
lut1lut| | 2012-10-26 10:40 | 只看该作者
LZ,“按照 Pentium 的分支预测的介绍, 是遇到分支指令时, 将分支转向的地址的代码提前装入指令队列. 避免清空流水线导致的取指延时”, 这句话没错。

只是我想请问LZ,哪里看到有说“预取存在分支预测”。“prefetch”是STM32F0的闪存这一块的东西,我没有在它的手册上看到有“分支预测”这个功能啊?

我只在STM32F0的内核介绍时看到说“3-stage pipeline with branch speculation”,这正是你所说的避免清空流水线呀。

使用特权

评论回复
15
yhsy1002| | 2013-12-13 10:19 | 只看该作者
高手!!!!!!!!!!!!!!!!!!!!1

使用特权

评论回复
16
pattywu| | 2013-12-13 13:24 | 只看该作者
实际上,STM32的FLASH的速度在60MHz左右,运行在48MHz时,根本不需要加等待周期。

使用特权

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

本版积分规则

个人签名:欢迎进入 TI 模拟技术论坛!

556

主题

17724

帖子

884

粉丝