使用SSE进行矢量初始化

Ale*_*ros 2 c++ sse vector

我是C++的新手(从Java转移到我的科学应用程序的性能),我对SSE一无所知.不过,我需要改进以下非常简单的代码:

    int myMax=INT_MAX;
    int size=18000003;
    vector<int> nodeCost(size);

    /* init part */
    for (int k=0;k<size;k++){
     nodeCost[k]=myMax;
    }
Run Code Online (Sandbox Code Playgroud)

我已经测量了初始化部分的时间,它需要13ms,这对于我的科学应用来说太大了(整个算法在22ms运行,这意味着初始化占总时间的1/2).请记住,初始化部分将针对同一向量重复多次.

如您所见,向量的大小不会除以4.有没有办法加速SSE的初始化?你能建议怎么样?我是否需要使用数组或SSE也可以与向量一起使用?

请,因为我需要你的帮助,所以我们都避免a)"你是如何衡量时间"或b)"过早优化是所有邪恶的根源",这对你来说是合理的,但a)测量的时间是正确的b我同意,但我别无选择.我不想将代码与OpenMP并行化,因此SSE是唯一的后备.

谢谢你的帮助

Ker*_* SB 7

使用vector的构造函数:

std::vector<int> nodeCost(size, myMax);
Run Code Online (Sandbox Code Playgroud)

这很可能会使用优化的"memset"类型的实现来填充向量.

还要告诉编译器生成特定于体系结构的代码(例如,-march=native -O3在GCC上).在我的x86_64机器上,这会生成以下用于填充向量的代码:

L5:
    add     r8, 1                    ;; increment counter
    vmovdqa YMMWORD PTR [rax], ymm0  ;; magic, ymm contains the data, and eax...
    add     rax, 32                  ;; ... the "end" pointer for the vector
    cmp     r8, rdi                  ;; loop condition, rdi holds the total size
    jb      .L5
Run Code Online (Sandbox Code Playgroud)

movdqa指令的大小以256位操作为前缀,一次将32个字节复制到内存中; 它是AVX指令集的一部分.

  • @AlexandrosE:稍后你可以使用`std :: fill`. (3认同)

Pau*_*l R 5

std::fill首先按照已经建议尝试,然后如果仍然不够快,你可以去SIMD,如果你真的需要.请注意,根据您的CPU和内存子系统,对于这样的大型向量,您可能会达到DRAM的最大带宽,这可能是限制因素.无论如何,这是一个相当简单的SSE实现:

#include <emmintrin.h>

const __m128i vMyMax = _mm_set1_epi32(myMax);
int * const pNodeCost = &nodeCost[0];
for (k = 0; k < size - 3; k += 4)
{
    _mm_storeu_si128((__m128i *)&pNodeCost[k], vMyMax);
}
for ( ; k < size; ++k)
{
    pNodeCost[k] = myMax;
}
Run Code Online (Sandbox Code Playgroud)

这应该适用于现代CPU - 对于较旧的CPU,您可能需要更好地处理潜在的数据错位,即使用_mm_store_si128而不是_mm_storeu_si128.例如

#include <emmintrin.h>

const __m128i vMyMax = _mm_set1_epi32(myMax);
int * const pNodeCost = &nodeCost[0];
for (k = 0; k < size && (((intptr_t)&pNodeCost[k] & 15ULL) != 0); ++k)
{                                              // initial scalar loop until we
    pNodeCost[k] = myMax;                      // hit 16 byte alignment
}
for ( ; k < size - 3; k += 4)                  // 16 byte aligned SIMD loop
{
    _mm_store_si128((__m128i *)&pNodeCost[k], vMyMax);
}
for ( ; k < size; ++k)                         // scalar loop to take care of any
{                                              // remaining elements at end of vector
    pNodeCost[k] = myMax;
}
Run Code Online (Sandbox Code Playgroud)