为什么根据时钟周期数和核心频率测得的NEON内联汇编代码运行时间与预期时间不一致?

问题描述 投票:-3回答:1
  image width  = 4000
  image height = 2000
  number of iterations = width * height / 64 = 125 000  

  asm volatile(
  "1:                                                    \n\t"
  "prfm     pldl1keep, [%[src], #128]                    \n\t"

  "LD4   {v0.16B, v1.16B, v2.16B,v3.16B},  [%[src]], #64 \n\t" //5 cycles

  "MOVI v10.16B, #12                                     \n\t" //1 cycle

  "AND v4.16B, v0.16B, v10.16B                           \n\t" //1 cycle
  "AND v5.16B, v1.16B, v10.16B                           \n\t" //1 cycle
  "AND v6.16B, v2.16B, v10.16B                           \n\t" //1 cycle
  "AND v7.16B, v3.16B, v10.16B                           \n\t" //1 cycle

  "MOVI v11.16B, #20                                     \n\t" //1 cycle

  "SUB v8.16B, v4.16B, v11.16B                           \n\t" //1 cycle
  "SUB v9.16B, v5.16B, v11.16B                           \n\t" //1 cycle
  "SUB v10.16B, v6.16B, v11.16B                          \n\t" //1 cycle
  "SUB v11.16B, v7.16B, v11.16B                          \n\t" //1 cycle

  "ST4   {v8.16B, v9.16B, v10.16B,v11.16B}, [%[dst]], #64 \n\t" //5 cycles

  "subs  %[simd_it], %[simd_it], #1                      \n\t" //1 cycle
  "bne   1b                                              \n\t" //4 cycles

每次迭代约25个时钟周期 125 000 * 25 = 3 125 000个周期/图像。

我在ARM NEON内联汇编中实现了示例代码(代码没有意义).每幅图像有(大约,我使用ARMv7的信息,这是ARMv8,但我不希望这个数字会高得多)3,1M时钟周期。

我使用的是频率为1Ghz的处理器。如果处理器每秒有1G的时钟周期,那么它应该在不到4ms的时间内完成3,1M个周期。但我测量的时间是14ms左右。

为什么不匹配? 同一核心上没有其他进程运行。

有条件分支,每一次迭代(bne),都会导致该管道需要重新填充。如果有条件的跳过将被删除 而取而代之的,将是写好的千行长代码。会不会快3-4倍? 谅谅

assembly arm cpu-architecture neon cpu-cycles
1个回答
1
投票
  • 没有理由使用 ld4st4 的算法。
  • 你应该初始化 v10v11 循环外。
  • 你不应该把 subs 接连 b.ne.
  • 你应该避免使用 v8v15 因为它们必须按照 aapcs.
  • 分支预测器会使条件分支消耗0个周期。

    movi    v4.16b, #12
    movi    v5.16b, #20

.balign 64
1:
    ld1     {v0.16b-v3.16b}, [src], #64
    subs    simd_it, simd_it, #1

    and     v0.16b, v0.16b, v4.16b
    and     v1.16b, v1.16b, v4.16b
    and     v2.16b, v2.16b, v4.16b
    and     v3.16b, v3.16b, v4.16b

    sub     v0.16b, v0.16b, v5.16b
    sub     v1.16b, v1.16b, v5.16b
    sub     v2.16b, v2.16b, v5.16b
    sub     v3.16b, v3.16b, v5.16b

    st1     {v0.16b-v3.16b}, [dst], #64
    b.gt    1b

上面的代码每次迭代消耗16个周期,理论上说

125,000 * 16 = 2,000,000 = 2ms @ 1Ghz。

我想你测量的时间应该是12ms左右,因为我感觉你要么没有启用缓存,要么是在非缓存区读写。

每次迭代大约损失80个周期,对于4个寄存器的缓存漏掉惩罚来说,这看起来很合理。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.