【STM32F0实验】FLASH 等待周期对性能影响的测试
做了个程序, 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 的预取指缓冲管理应该还有改进的地方.