gpt4 book ai didi

c++ - 通过 ARM NEON 汇编最大优化元素乘法

转载 作者:可可西里 更新时间:2023-11-01 17:59:40 26 4
gpt4 key购买 nike

我正在为双 Cortex-A9 处理器优化两个一维数组的逐元素乘法。主板上运行的是 Linux,我使用的是 GCC 4.5.2 编译器。

所以下面是我的 C++ 内联汇编函数。 src1、src2 和 dst 是 16 字节对齐的。

更新:可测试代码:

void Multiply(
const float* __restrict__ src1,
const float* __restrict__ src2,
float* __restrict__ dst,
const unsigned int width,
const unsigned int height)
{
int loopBound = (width * height) / 4;
asm volatile(
".loop: \n\t"
"vld1.32 {q1}, [%[src1]:128]! \n\t"
"vld1.32 {q2}, [%[src2]:128]! \n\t"
"vmul.f32 q0, q1, q2 \n\t"
"vst1.32 {q0}, [%[dst]:128]! \n\t"
"subs %[lBound], %[lBound], $1 \n\t"
"bge .loop \n\t"
:
:[dst] "r" (dst), [src1] "r" (src1), [src2] "r" (src2),
[lBound] "r" (loopBound)
:"memory", "d0", "d1", "d2", "d3", "d4", "d5
);
}

//The following function describes how to test the element wise multiplication
void Test()
{
const unsigned int width = 1024, height = 1024;
float* src1 __attribute__((aligned(16))) = new float[width * height];
float* src2 __attribute__((aligned(16))) = new float[width * height];
float* dst __attribute__((aligned(16))) = new float[width * height];
for(unsigned int i = 0; i < (width * height); i++)
{
src1[i] = (float)rand();
src2[i] = (float)rand();
}
Multiply(src1, src2, dst, width, height);

std::cout << dst[0] << std::endl;
}

计算 1024*1024 个值大约需要 0.016 秒。 (两个线程——每个线程计算数组的一半)。天真地解释,一次迭代的计算需要122个周期。这似乎有点慢。但是瓶颈在哪里呢?

我什至尝试使用 pld 命令在 L2 缓存中预加载元素,通过每次迭代最多计算 20 个值来“展开”循环,并对指令重新排序以确保处理器不会等待内存。我没有得到那么多的加速(最多快 0.001 秒)。

您对加快计算有什么建议吗?

最佳答案

我对 NEON 了解不多。但是,我认为您有导致性能问题的数据依赖性。我建议您为循环准备一些负载,然后将它们放在乘法存储 之间。我认为 store 可能会阻塞,直到 multiply 完成。

    asm volatile(
"vld1.32 {q1}, [%[src1]:128]! \n\t"
"vld1.32 {q2}, [%[src2]:128]! \n\t"
".loop: \n\t"
"vmul.f32 q0, q1, q2 \n\t"
"vld1.32 {q1}, [%[src1]:128]! \n\t"
"vld1.32 {q2}, [%[src2]:128]! \n\t"
"vst1.32 {q0}, [%[dst]:128]! \n\t"
"subs %[lBound], %[lBound], $1 \n\t"
"bge .loop \n\t"
:
:[dst] "r" (dst), [src1] "r" (src1), [src2] "r" (src2),
[lBound] "r" (loopBound)
:"memory", "d0", "d1", "d2", "d3", "d4", "d5
);

通过这种方式,您应该能够并联负载与乘法。您将需要过度分配源数组或更改循环索引并进行最终的乘法和存储。如果 NEON 操作不影响条件代码,您也可以重新排序 subs 并将其放置在更早的位置。

编辑:事实上,Cortex A-9 媒体处理引擎文档建议交错使用 ARM 和 NEON 指令,因为它们可以并行执行。此外,NEON 指令似乎设置了 FPSCR 而不是 ARM CPSR,因此重新排序 subs 会减少执行时间。您还可以缓存对齐循环。

关于c++ - 通过 ARM NEON 汇编最大优化元素乘法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12777483/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com