【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 的预取指缓冲管理应该还有改进的地方.

(0)

相关推荐