Performance 为什么在thumb2中更改为低寄存器会增加循环计数?

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/预取。)测试

我已将thumb2汇编代码中的所有r10都更改为r4。 正如所料,尺寸确实缩小了一点。
但执行的周期增加了。虽然仍然有相同的说明,但现在只有一些是窄的而不是宽的

为什么会这样

根本不使用中断,只访问闪存和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
相同的机器代码,半字对齐