优化RGBA->RGB arm64组装

Posted

技术标签:

【中文标题】优化RGBA->RGB arm64组装【英文标题】:Optimize RGBA->RGB arm64 assembly 【发布时间】:2013-12-18 16:06:25 【问题描述】:

我编写了这个非常简单的 NEON 实现来从 RGBA 转换为 RGB。它可以工作,但我想知道是否还有其他方法可以进一步提高性能。

我尝试使用预取大小并进一步展开循环,但性能并没有太大变化。顺便说一句,在预取维度方面是否有任何经验法则?我在网上找不到任何有用的东西。此外,在“ARMv8 指令集概述”中,我看到还有一个用于存储的预取,这有什么用?

目前我在 iPhone5s 上转换 1280x720 图像大约需要 1.7 毫秒。

// unsigned int * rgba2rgb_neon(unsigned int * pDst, unsigned int * pSrc, unsigned int count);
_rgba2rgb_neon:
    cmp     w2, #0x7
    b.gt    loop

    mov     w0, #0
    ret

loop:
    prfm    pldl1strm, [w1, #64]

    ld4.8b  v0, v1, v2, v3, [w1], #32
    ld4.8b  v4, v5, v6, v7, [w1], #32

    prfm    pldl1strm, [w1, #64]

    st3.8b  v0, v1, v2, [w0], #24
    st3.8b  v4, v5, v6, [w0], #24

    subs    w2, w2, #16
    b.gt    loop

done:
    ret

【问题讨论】:

【参考方案1】:

首先(因为我假设您的目标是 ios),vImage(Accelerate.framework 的一部分)为您提供这种转换,如vImageConvert_RGBA8888toRGB888。这具有适用于所有 iOS 和 OS X 系统的优势,因此您无需为 arm64、armv7s、armv7、i386、x86_64 编写单独的实现。

现在,可能是您自己编写此转换作为练习,而不是因为您根本不知道已经有一个转换。在这种情况下:

避免使用ld[34]st[34]。它们很方便,但通常比使用 ld1 和置换要慢。 对于像这样完全常规的数据访问模式,不需要手动预取。 用ld1.16b加载四个16b RGBA向量,用三个tbl.16b指令从中提取三个16b RGB向量,用st1.16b存储它们 或者,尝试使用非临时加载和存储 (ldnp/stnp),因为您的图像太大而无法放入缓存中。

最后,回答您的问题:存储的预取提示主要是有用的,因为某些实现可能会因未命中缓存的部分行写入而出现严重停顿。尤其是简单的实现可能会因任何未命中缓存的写入而停滞。

【讨论】:

在 iPad Mini Retina(Apple A7 处理器)上测试,似乎表明存储的非临时提示对性能没有影响。 @BitBank:非临时存储有利于性能的条件很难描述。重要的是要记住,它们最大的好处之一是它们避免分配到内部缓存中,这意味着它们的影响有时仅在围绕被修改以使用它们的循环的代码中可见。我的指导实际上是“尝试它们,衡量整个程序的性能,如果它们有改进,就使用它们”。 我通过测试一个写入大于 L2 缓存的图像缓冲区的函数得出了这个结论。数据只被写入,直到稍后再被引用。这似乎是尝试存储指令的“流式”版本的理想案例。我需要在 Nvidia K1 Denver 上对此进行测试,看看其行为是否与 Apple A7 不同。快更新...【参考方案2】:

如果你想用 alpha 通道做一些有趣的事情,除了把它放在你的肩膀上之外,另请参阅 vImageFlatten_RGBA8888toRGB888。

【讨论】:

以上是关于优化RGBA->RGB arm64组装的主要内容,如果未能解决你的问题,请参考以下文章

英特尔 AVX2 组装开发

如何在QEMU上的GDB中单步ARM组装?

组装在构建之外被优化

在 64 位系统上组装 32 位二进制文​​件(GNU 工具链)

MUL指令将32位组装成64位[重复]

带组装1ROS_1节点_64Chan