ARM:stm​​ia指令比ldmia快得多?

时间:2011-09-06 13:51:50

标签: assembly arm

我正在观察一些不正确的事情。

我发现我可以使用

写入ARM上的主内存
 stmia r0!, {r3,r4,r5,r6,r7,r8,r9,r10}

比使用

从主存储器(SDRAM)读取的速度快约6倍
 ldmia r0!, {r3,r4,r5,r6,r7,r8,r9,r10}

所以,如果我将血红蛋白替换为stmia并将r0指向分配的记忆,那么如果我计时,那么血症会快6倍。

ARM的stmia指令有什么特别之处可能导致假阳性吗?也许stmia与缓存交互奇怪?

总的来说,我已经看到ARM的写入速度比从主内存中读取的速度快,但从硬件的角度来看,速度提高6倍是没有意义的。


更新: 这种情况发生在大块内存中,可能比L2缓存大。

因此,缓存说明没有充分的意义。即使ARM有一个写回L2缓存需要永远回写,它也不会比我分配的内存区域大。

感谢。

4 个答案:

答案 0 :(得分:3)

您没有指定您的平台和环境,但我怀疑您正在看到缓存的影响。执行加载时,首先检查缓存,如果数据不存在(缓存未命中),则CPU必须等到实际从主内存中取出,这比缓存慢很多。另一方面,商店可以将数据转储到缓存中并继续前进,依靠缓存控制器来执行实际的内存写入而无需CPU的参与。

要确定是否属于这种情况,您可以尝试各种测试模式,例如:

  1. 禁用缓存,这应该使时间反映实际的内存访问时间。
  2. 连续多次从同一地址执行加载。重复加载应该更快,因为它们将会访问缓存。
  3. 在商店之后立即执行加载到同一地址 - 这应该使用缓存中的值并加快速度。
  4. 在每次操作之前刷新缓存以减少其对时间的影响
  5. 在存储之后添加一个DSB,以确保在执行之前完成实际写入。
  6. 等等。要阅读有关ARM处理器中缓存的更多信息,我建议您阅读Cortex-A Series Programmer's Guide。即使您的处理器不是Cortex-A,它也会很有用,因为大多数概念也适用于老一代。

答案 1 :(得分:1)

以下是一些示例代码:

.globl _start
_start:


    ldr r11,=0xD6800600
    mov r1,#0
    str r1,[r11,#0x08] ;@ stop timer
    mvn r1,#0
    str r1,[r11,#0x00] ;@ timer load register
    mov r1,#3
    str r1,[r11,#0x08] ;@ start timer, 1 x prescaler

    mov r3,#3
    mov r4,#4
    mov r5,#5
    mov r6,#6
    mov r7,#7
    mov r8,#8
    mov r9,#9
    mov r10,#10

    ldr r0,=0xD6001000
    mov r12,#0x400

    ldr r13,[r11,#0x04]
write_loop:
    stmia r0!, {r3,r4,r5,r6,r7,r8,r9,r10}
    subs r12,#1
    bne write_loop
    ldr r1,[r11,#0x04]

    ldr r0,=0xD6001000
    mov r12,#0x400

    ldr r2,[r11,#0x04]
read_loop:
    ldmia r0!, {r3,r4,r5,r6,r7,r8,r9,r10}
    subs r12,#1
    bne read_loop
    ldr r14,[r11,#0x04]

    mov r0,r13
    mov r3,r14

    ldr sp,=0xD600E000
    bl notmain
hang: b hang

.globl PUT32
PUT32:
    str r1,[r0]
    bx lr

.globl GET32
GET32:
    ldr r0,[r0]
    bx lr

外设基数为0xD6800000。使用on-core计时器。这是一个带有64位AXI总线的mpcore r2p0(rev 2.0)。您可能会发现写入比读取慢3倍。打印出时间并减去写入是0x191F5刻度并读取0x81F7。

但我知道原因。这个存储器控制器可以/确实将stm转换成4个双字写周期(你在AXI总线上看到的)。我认为读取是单个8字(4个双字)传输,因此写入的总线开销是4倍。每次写入的开销加一个时钟,每次读取都是开销加8个时钟来突发数据。

我添加了代码以验证缓存是否已关闭。并添加了nops,一次一个nop来调整内存中指令的对齐(仍然可以影响提取和片上内存的实现)。例如,在每个循环之前,在读取计时器之前放置nops。通过操纵内存中循环的位置,读取循环最敏感,我可以将结果改为50%。它不是0x8xxx范围,而是在一个敏感点发送到0xAxxx,在另一个敏感点发送到0x6xxx时钟。我不打算深入研究这个问题,ram本身可能会产生一些影响,以及作为一个ARM11的影响,其中有一些平滑来自获取,以及可能未对齐的读取被平滑为更少的对齐读取等。

我建议你这样做,关闭缓存,关闭mmu,关闭奇偶校验或ecc生成/检查。拧紧循环,循环外部的时间。在测试代​​码前面一次放置一个nops,一次一个,可能多达8或16或32,如果有变化,模式应该在一些逻辑边界上重复,如4,8或16个字。此外,如果你的计时器给你一个不同的数字(没有重新编译)运行后运行,你有中断或类似的事情会弄乱你的数字。像我想象的那样的处理器核心时钟甚至会改变一个时钟,当然取决于你的内存系统。嗯,因为你正在做8个字的指令,试着把起始地址改为0,4,8和12.还试着打开指令缓存(不需要mmu)。我怀疑你也会看到性能数字跳跃。

还有其他一些ARM我可以试试......不是芯片我有尽可能多的内部知识......

你在跑什么家庭/核心?你可以发布测试代码吗?你的测试循环是否与我上面的相似?

答案 2 :(得分:0)

@dwelch 我认为你对NOP提出了一个有趣的观点,但是已经证明代码在读取时可以非常快地运行---只要它访问缓存而不是主内存。速率约为5000MB / s。而写作速度为6000MB / s。所以NOP并没有真正解释为什么写入主内存比从主内存中读取要快得多。

答案 3 :(得分:0)

您观察到的是ARM写入缓冲区的影响。写缓冲区位于CPU和高速缓存或RAM之间。它旨在防止CPU在执行少量写操作时等待内存。典型的写缓冲区可以处理4个唯一的地址,每个地址有2个字,用于存放您在上面的示例中编写的寄存器。如果您创建一个带有8个寄存器的stmia循环,您将开始看到它可以写入的真实速度。没有合并的地址,所以如果你写4个字节,那也将填充写缓冲区。