0

我正在尝试利用 knc (Xeon Phi) 提供的 SIMD 512 来使用 intel 内在函数来提高以下 C 代码的性能。但是,我的内在嵌入式代码运行速度比自动矢量化代码慢

C代码

int64_t match=0;
int *myArray __attribute__((align(64)));
myArray = (int*) malloc (sizeof(int)*SIZE); //SIZE is array size taken from user
radomize(myArray); //to fill some random data
int searchVal=24;
#pragma vector always
for(int i=0;i<SIZE;i++) {
   if (myArray[i]==searchVal) match++;
return match;

内在嵌入代码:在下面的代码中,我首先加载数组并将其与搜索键进行比较。内在函数返回使用 _mm512_mask_reduce_add_epi32() 减少的 16 位掩码值。

register int64_t match=0;
int *myArray __attribute__((align(64)));
myArray = (int*) malloc (sizeof(int)*SIZE); //SIZE is array size taken from user
const int values[16]=\
                {   1,1,1,1,\
                    1,1,1,1,\
                    1,1,1,1,\
                    1,1,1,1,\
                };
__m512i const flag = _mm512_load_epi32((void*) values);
__mmask16 countMask;

__m512i searchVal = _mm512_set1_epi32(16);
__m512i kV = _mm512_setzero_epi32();


for (int i=0;i<SIZE;i+=16)
{
   // kV = _mm512_setzero_epi32();
    kV = _mm512_loadunpacklo_epi32(kV,(void* )(&myArray[i]));
    kV = _mm512_loadunpackhi_epi32(kV,(void* )(&myArray[i + 16]));

    countMask = _mm512_cmpeq_epi32_mask(kV, searchVal);
    match += _mm512_mask_reduce_add_epi32(countMask,flag);
}
return match;

我相信我有一些如何在此代码中引入额外的循环,因此与自动矢量化代码相比它运行缓慢。与直接返回 128 位寄存器中比较值的 SIMD128 不同,SIMD512 返回掩码寄存器中的值,这增加了我的代码的复杂性。我在这里遗漏了什么吗,必须有一种方法可以直接比较和记录成功搜索的数量,而不是使用 XOR 操作等掩码。

最后,请建议我使用内在函数提高此代码性能的方法。我相信我可以使用内在函数来提高性能。至少对于 SIMD128 来说是这样,在使用内部函数时,我可以获得 25% 的性能。

4

1 回答 1

1

我建议以下优化:

  • 使用预取。您的代码执行的计算量很少,而且几乎肯定会受到带宽限制。Xeon Phi 仅对 L2 缓存进行硬件预取,因此为了获得最佳性能,您需要手动插入预取指令。
  • 使用_mm512_load_epi32@PaulR 提示的对齐读取。使用memalignfunction 而不是malloc来保证数组确实在 64 字节上对齐。如果您需要未对齐的指令,_mm512_undefined_epi32()请用作第一个未对齐加载的源,因为它打破了对kV(在您当前的代码中)的依赖并让编译器进行额外的优化。
  • 将数组展开 2 或使用至少两个线程来隐藏指令延迟。
  • 避免使用int变量作为索引。unsigned intsize_t或者ssize_t是更好的选择。
于 2014-02-15T06:01:16.963 回答