Performance 为什么在thumb2中更改为低寄存器会增加循环计数?
我已将thumb2汇编代码中的所有r10都更改为r4。 正如所料,尺寸确实缩小了一点。Performance 为什么在thumb2中更改为低寄存器会增加循环计数?,performance,assembly,arm,cortex-m,thumb,Performance,Assembly,Arm,Cortex M,Thumb,我已将thumb2汇编代码中的所有r10都更改为r4。 正如所料,尺寸确实缩小了一点。 但执行的周期增加了。虽然仍然有相同的说明,但现在只有一些是窄的而不是宽的 为什么会这样 根本不使用中断,只访问闪存和ram(在定时例程中) 我已经在Cortex-M4(STM32F411)上运行了我的代码,有0个等待状态,有或没有预取和/或icache。我已经用DWT:CYCCNT测量过了。 它从1902619次增加到1908268次,约为0.2%。(循环会谨慎地进行一些操作,不执行icache/预取。)测试
但执行的周期增加了。虽然仍然有相同的说明,但现在只有一些是窄的而不是宽的 为什么会这样 根本不使用中断,只访问闪存和ram(在定时例程中) 我已经在Cortex-M4(STM32F411)上运行了我的代码,有0个等待状态,有或没有预取和/或icache。我已经用DWT:CYCCNT测量过了。 它从1902619次增加到1908268次,约为0.2%。(循环会谨慎地进行一些操作,不执行icache/预取。)测试代码:
ldr r2,[r0]
---- code under test ----
loop:
subs r1,#1
bne loop
---- code under test ----
ldr r3,[r0]
subs r0,r2,r3
bx lr
R0包含systick计数寄存器上的点,被测代码基本上是尽可能紧密和可重复地测量的。Systick同样优秀,可能比DWT更容易
我是从ram运行的,因为这是一个mcu,但更重要的是,它是一个STM32,它在闪存前面有一个预取缓存,除了极少数例外,你不能禁用它,也不能轻易击败它,这使得基准测试成为一个PITA
在低位寄存器和高位寄存器之间切换
add r3,r10,r11
add r3,r3,r4
c: eb0a 030b add.w r3, sl, fp
c: 4423 add r3, r4
基本上是两个半字对一个半字。通过更改某些指令中的某些寄存器,可能会导致指令大小更改,此指令大小更改会影响后续代码的对齐
测试代码
10: 6802 ldr r2, [r0, #0]
00000012 <loop>:
12: 3901 subs r1, #1
14: d1fd bne.n 12 <loop>
16: 6803 ldr r3, [r0, #0]
18: 1ad0 subs r0, r2, r3
1a: 4770 bx lr
所以现在是相同的机器代码,在单词边界上对齐
00000010 <loop>:
10: 3901 subs r1, #1
12: d1fd bne.n 10 <loop>
00040001
00040001
00080001
000C0001
00000010:
10:3901潜艇r1#1
12:d1fd bne.n 10
00040001
00040001
00080001
000C0001
机器代码在每种情况下都匹配
12: 3901 subs r1, #1
14: d1fd bne.n 12 <loop>
10: 3901 subs r1, #1
12: d1fd bne.n 10 <loop>
12:3901潜艇r1,#1
14:d1fd bne.n 12
10:3901潜艇r1#1
12:d1fd bne.n 10
通过半字更改对齐方式,性能将发生显著变化
当然,无论何时进行任何ARM汇编语言编程,您都应该随时准备好ARM文档:
“所有回迁都是字范围的。每个字回迁的指令数取决于运行的代码和内存中代码的对齐方式。” 注意,不同的Cortex-M内核可能有不同的获取选项。不要假设,因为Cortex-M4说的是一件事,其他的没有做不同的事情 为了记录在案,上面的简单示例并未说明flash中存在问题。STM32产品有一个闪存缓存(有一些别致的营销名称和商标,可能还有专利),您无法关闭它(通常) 这在瞬间奏效了
08000032 <loop>:
8000032: f3af 8000 nop.w
8000036: f3af 8000 nop.w
800003a: f3af 8000 nop.w
800003e: f3af 8000 nop.w
8000042: f3af 8000 nop.w
8000046: 3901 subs r1, #1
8000048: d1f3 bne.n 8000032 <loop>
00090000
00090000
00120000
001B0000
0800032:
800032:f3af 8000不含西
800036:f3af 8000不含西
80003A:f3af 8000不含西
8000003E:f3af 8000不含西
800042:f3af 8000不含西
800046:3901个接头r1,#1
800048:d1f3英国国家公园800032
00090000
00090000
00120000
001B0000
vs
0800030:
800030:f3af 8000不含西
800034:f3af 8000不含西
800038:f3af 8000不含西
800003c:f3af 8000不含西
800040:f3af 8000不含西
8000044:3901个接头r1,#1
800046:d1f3英国国家公园800030
00080000
00080000
00100000
00180000
相同的机器代码,半字对齐更改。快12.5%
一些非STM32的此类工作(在闪存中)要容易得多,因为它们没有奇特的缓存功能和/或依赖ARM的缓存,您可以启用/禁用它。测试中的代码:
ldr r2,[r0]
---- code under test ----
loop:
subs r1,#1
bne loop
---- code under test ----
ldr r3,[r0]
subs r0,r2,r3
bx lr
R0包含systick计数寄存器上的点,被测代码基本上是尽可能紧密和可重复地测量的。Systick同样优秀,可能比DWT更容易
我是从ram运行的,因为这是一个mcu,但更重要的是,它是一个STM32,它在闪存前面有一个预取缓存,除了极少数例外,你不能禁用它,也不能轻易击败它,这使得基准测试成为一个PITA
在低位寄存器和高位寄存器之间切换
add r3,r10,r11
add r3,r3,r4
c: eb0a 030b add.w r3, sl, fp
c: 4423 add r3, r4
基本上是两个半字对一个半字。通过更改某些指令中的某些寄存器,可能会导致指令大小更改,此指令大小更改会影响后续代码的对齐
测试代码
10: 6802 ldr r2, [r0, #0]
00000012 <loop>:
12: 3901 subs r1, #1
14: d1fd bne.n 12 <loop>
16: 6803 ldr r3, [r0, #0]
18: 1ad0 subs r0, r2, r3
1a: 4770 bx lr
所以现在是相同的机器代码,在单词边界上对齐
00000010 <loop>:
10: 3901 subs r1, #1
12: d1fd bne.n 10 <loop>
00040001
00040001
00080001
000C0001
00000010:
10:3901潜艇r1#1
12:d1fd bne.n 10
00040001
00040001
00080001
000C0001
机器代码在每种情况下都匹配
12: 3901 subs r1, #1
14: d1fd bne.n 12 <loop>
10: 3901 subs r1, #1
12: d1fd bne.n 10 <loop>
12:3901潜艇r1,#1
14:d1fd bne.n 12
10:3901潜艇r1#1
12:d1fd bne.n 10
通过半字更改对齐方式,性能将发生显著变化
当然,无论何时进行任何ARM汇编语言编程,您都应该随时准备好ARM文档:
“所有回迁都是字范围的。每个字回迁的指令数取决于运行的代码和内存中代码的对齐方式。” 注意,不同的Cortex-M内核可能有不同的获取选项。不要假设,因为Cortex-M4说的是一件事,其他的没有做不同的事情 为了记录在案,上面的简单示例并未说明flash中存在问题。STM32产品有一个闪存缓存(有一些别致的营销名称和商标,可能还有专利),您无法关闭它(通常) 这在瞬间奏效了
08000032 <loop>:
8000032: f3af 8000 nop.w
8000036: f3af 8000 nop.w
800003a: f3af 8000 nop.w
800003e: f3af 8000 nop.w
8000042: f3af 8000 nop.w
8000046: 3901 subs r1, #1
8000048: d1f3 bne.n 8000032 <loop>
00090000
00090000
00120000
001B0000
0800032:
800032:f3af 8000不含西
800036:f3af 8000不含西
80003A:f3af 8000不含西
8000003E:f3af 8000不含西
800042:f3af 8000不含西
800046:3901个接头r1,#1
800048:d1f3英国国家公园800032
00090000
00090000
00120000
001B0000
vs
0800030:
800030:f3af 8000不含西
800034:f3af 8000不含西
800038:f3af 8000不含西
800003c:f3af 8000不含西
800040:f3af 8000不含西
8000044:3901个接头r1,#1
800046:d1f3英国国家公园800030
00080000
00080000
00100000
00180000
相同的机器代码,半字对齐