C - 交换两个相同大小的内存块的最快方法? (解决方案可行性)

时间:2016-05-19 16:41:12

标签: c memory swap avx2

此问题是this one的扩展。在这里,我提出两种可能的解决方案,我想知道它们的可行性。我正在使用Haswell微体系结构和GCC / ICC编译器。我还假设内存是对齐的。

选项1 - 我已经分配了一个内存位置并进行了3次内存移动。 (我使用memmove而不是memcpy来避免复制构造函数)

void swap_memory(void *A, void* B, size_t TO_MOVE){

    memmove(aux, B, TO_MOVE);
    memmove(B, A, TO_MOVE);
    memmove(A, aux, TO_MOVE);
}

选项2 - 利用对齐的内存,使用AVX或AVX2加载和存储。对于此解决方案,我认为我交换了int数据类型。

void swap_memory(int *A, int* B, int NUM_ELEMS){

    int i, STOP_VEC = NUM_ELEMS - NUM_ELEMS%8;
    __m256i data_A, data_B;

    for (i=0; i<STOP_VEC; i+=8) {
        data_A = _mm256_load_si256((__m256i*)&A[i]);
        data_B = _mm256_load_si256((__m256i*)&B[i]);

        _mm256_store_si256((__m256i*)&A[i], data_B);
        _mm256_store_si256((__m256i*)&B[i], data_A);
    }

    for (; i<NUM_ELEMS; i++) {
        std::swap(A[i], B[i]);
    }
}

选项2是最快的吗?还有其他更快的实现我还没提到吗?

3 个答案:

答案 0 :(得分:2)

如果您确定内存已对齐,则使用AVX可能是最佳选择。请注意,明确地执行此操作可能不是可移植的 - 装饰指针可能更好,以便它们已知对齐(例如,使用aligned属性或类似属性。)

最有可能的选项2(或语义上做的事情)可能更快,因为指针不受限制或任何东西。编译器可能不知道重新排序内存或保持“aux”不变是安全的。

此外,根据辅助设置的方式,选项2可能更加线程安全。

在块中甚至可以同时使用本地临时和memcpy到临时块,甚至可以全部使用,这可能没问题,因为gcc可能能够对其进行矢量化。避免使用外部临时工具,并确保所有结构都按照对齐方式进行装饰。

答案 1 :(得分:0)

选项2读取次数较少,所以我希望它更快(当然这一切都取决于数据的大小,如果所有内容都适合缓存,性能优势会更少)。

你也可以使用AVX内在的_mm256_stream_si256代替商店(那么你在再次阅读内存之前需要一个围栏)。

答案 2 :(得分:0)

我会做以下事情:

unsigned char t; 
unsigned char *da = A, *db = B; 
while(TO_MOVE--) { 
   t = *da; 
   *da++ = *db; 
   *db++ = t; 
}

基于它非常明确,优化者很有可能做得很好。