C - 交换两个大小相等的内存块的最快方法? (方案可行性)
C - fastest method to swap two memory blocks of equal size? (Solution feasibility)
这个问题是 this one 的延伸。在这里,我提出了两种可能的解决方案,我想知道它们的可行性。我正在使用带有 GCC/ICC 编译器的 Haswell 微体系结构。我还假设内存是对齐的。
选项 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是最快的吗?还有其他我没有提到的更快的实现吗?
如果您确定内存已对齐,最好使用 AVX。请注意,明确地执行此操作可能不可移植 - 最好装饰指针,使其已知对齐(例如,使用 aligned
属性或类似属性。)
最有可能的选项 2(或语义上这样做的东西)可能更快,因为指针不受限制或任何东西。编译器可能不知道重新排序内存或保持 "aux" 不变是安全的。
此外,选项 2 可能更线程安全,具体取决于 aux 的设置方式。
使用本地临时文件和 memcpy to/from 块中的临时文件或什至一次全部使用可能没问题,因为 gcc 可能能够对其进行矢量化。避免使用外部临时对象,并确保所有结构都按对齐方式装饰。
选项 2 的读取次数较少,所以我希望它会更快(当然这完全取决于数据的大小,如果所有内容都适合缓存,性能优势就会小得多)。
您也可以使用 AVX 内在函数 _mm256_stream_si256 而不是存储(然后在再次读取内存之前需要一个栅栏)。
我只会执行以下操作:
unsigned char t;
unsigned char *da = A, *db = B;
while(TO_MOVE--) {
t = *da;
*da++ = *db;
*db++ = t;
}
基于它非常清晰并且优化器将有很好的机会做好工作。
这个问题是 this one 的延伸。在这里,我提出了两种可能的解决方案,我想知道它们的可行性。我正在使用带有 GCC/ICC 编译器的 Haswell 微体系结构。我还假设内存是对齐的。
选项 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是最快的吗?还有其他我没有提到的更快的实现吗?
如果您确定内存已对齐,最好使用 AVX。请注意,明确地执行此操作可能不可移植 - 最好装饰指针,使其已知对齐(例如,使用 aligned
属性或类似属性。)
最有可能的选项 2(或语义上这样做的东西)可能更快,因为指针不受限制或任何东西。编译器可能不知道重新排序内存或保持 "aux" 不变是安全的。
此外,选项 2 可能更线程安全,具体取决于 aux 的设置方式。
使用本地临时文件和 memcpy to/from 块中的临时文件或什至一次全部使用可能没问题,因为 gcc 可能能够对其进行矢量化。避免使用外部临时对象,并确保所有结构都按对齐方式装饰。
选项 2 的读取次数较少,所以我希望它会更快(当然这完全取决于数据的大小,如果所有内容都适合缓存,性能优势就会小得多)。
您也可以使用 AVX 内在函数 _mm256_stream_si256 而不是存储(然后在再次读取内存之前需要一个栅栏)。
我只会执行以下操作:
unsigned char t;
unsigned char *da = A, *db = B;
while(TO_MOVE--) {
t = *da;
*da++ = *db;
*db++ = t;
}
基于它非常清晰并且优化器将有很好的机会做好工作。