【发布时间】:2012-09-28 10:52:51
【问题描述】:
我正在为双 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 秒)。
您对加快计算有什么建议吗?
【问题讨论】:
-
您是否仅使用单线程分析了代码?
-
您能否提供一个类似代码的测试工具,以便人们可以在本地运行它?
-
新浮动[宽*高]; - 这里操作符“new”不提供对齐的内存。尝试使用静态数组进行测试,或动态分配内存,但必须手动对齐结果指针
-
您还应该通过使用向量指令移动数据来对内存进行基准测试,以查看可以获得的 peek 值。
-
是的——通过'new'是动态分配,它由'malloc'和C++构造函数调用组成,但是你可以使用'memalign'函数进行动态对齐分配,例如:size_t alignment = 16; void* ptr = memalign(对齐,mem_size); - 应该够了。之后,您可以在命令中使用 :128 对齐后缀。但这并不能解决您的问题,因为通常它只会提高大约 5% 的性能(在我的测试中)。
标签: c++ optimization assembly arm neon