SSE的性能是相同的
Performance with SSE is the same
我对我正在开发的应用程序中出现的以下循环进行了矢量化:
void vecScl(Node** A, Node* B, long val){
int fact = round( dot / const);
for(i=0; i<SIZE ;i++)
(*A)->vector[i] -= fact * B->vector[i];
}
这是SSE代码
void vecSclSSE(Node** A, Node* B, long val){
int fact = round( dot / const);
__m128i vecPi, vecQi, vecCi, vecQCi, vecResi;
int sseBound = SIZE/4;
for(i=0,j=0; j<sseBound ; i+=4,j++){
vecPi = _mm_loadu_si128((__m128i *)&((*A)->vector)[i] );
vecQi = _mm_set_epi32(fact,fact,fact,fact);
vecCi = _mm_loadu_si128((__m128i *)&((B)->vector)[i] );
vecQCi = _mm_mullo_epi32(vecQi,vecCi);
vecResi = _mm_sub_epi32(vecPi,vecQCi);
_mm_storeu_si128((__m128i *) (((*A)->vector) + i), vecResi );
}
//Compute remaining positions if SIZE % 4 != 0
for(; i<SIZE ;i++)
(*A)->vector[i] -= q * B->vector[i];
}
虽然这在正确性方面是有效的,但使用SSE和不使用SSE的性能完全相同。我正在编译代码:
g++ *.cpp *.h -msse4.1 -march=corei7-avx -mtune=corei7-avx -mno-avx -mno-aes -Warray-bounds -O2
这是因为我没有分配(并使用相应的SSE函数)对齐内存吗?代码修改起来非常复杂,所以我现在尽量避免这样做。
顺便说一句,就进一步的改进而言,考虑到我被限制在Sandy Bridge架构中,我能做的最好的是什么?
EDIT: 编译器还没有向量化代码。首先,我将向量的数据类型更改为short
s,这不会改变性能。然后,我用-fno-tree-vectorize
编译,性能是一样的。
Thanks to lot
如果你的数据很大,那么你可能只是内存受限,因为你每次加载/存储只做很少的ALU操作。
然而,你可以尝试一些小的改进:
inline void vecSclSSE(Node** A, Node* B, long val){
// make function inline, for cases where `val` is small
const int fact = (dot + const / 2 - 1) / const;
// use integer arithmetic here if possible
const __m128i vecQi = _mm_set1_epi32(fact);
// hoist constant initialisation out of loop
int32_t * const pA = (*A)->vector; // hoist invariant de-references out of loop
int32_t * const pB = B->vector;
__m128i vecPi, vecCi, vecQCi, vecResi;
for(int i = 0; i < SIZE - 3; i += 4) { // use one loop variable
vecPi = _mm_loadu_si128((__m128i *)&(pA[i]));
vecCi = _mm_loadu_si128((__m128i *)&(pB[i]));
vecQCi = _mm_mullo_epi32(vecQi,vecCi);
vecResi = _mm_sub_epi32(vecPi,vecQCi);
_mm_storeu_si128((__m128i *)&(pA[i]), vecResi);
}
//Compute remaining positions if SIZE % 4 != 0
for(; i<SIZE ;i++)
pA[i] -= q * pB[i];
}
正如Paul所说,每次数据访问的计算量相对较少,并且代码可能受IO限制。因为未对齐的存储/加载比对齐的慢,所以你真的应该对齐你的数据。
你应该与SSE对齐16字节,这也是一条缓存线,(我认为)与AVX对齐32字节。如果您自己分配数据,只需使用_aligned_alloc
。如果您使用std::vector
,最简单的对齐方法是使用自定义分配器而不是std::allocator
。这个分配器将调用_aligned_alloc
或类似的东西,而不是malloc
/new
。参见这个问题
然后你可以切换到load/stores的对齐指令。
另外,我不确定&((*A)->vector)[i]
生成的代码是什么,最好使用本地指针来存储数据,但一定要注释它__restrict
但是在进行所有这些之前,请确保它值得您花费时间和承担维护负担。您可以使用linux的oprofile
或windows的AMD的code analyst
配置文件。
我想说的是,对于相同的SIZE,我能够向量化一个内核,它发生在第一篇文章中的内核之前。这一次,我有了很大的加速(我不会说这个因素,因为它是不相关的,除非我量化整个应用程序中花在内核上的时间)。内核计算两个向量的点积,即:
for(i=0;i<SIZE;i++)
dot += A->vector[i] * B->vector[i];
由此我可以得出结论,尺寸小不是问题。这反过来表明,我可能在第一个内核中做错了。有人能给第一个内核提供一套不同的SSE操作吗?我认为值得一试。下一步是分配对齐内存,但如前所述,这在Sandy Bridge和其他新架构中并不重要。
这再次证明编译器没有对代码进行向量化。
谢谢
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- OpenMP阵列性能较差
- 递归列出所有目录中的C++与Python与Ruby的性能
- 大小相等但成员数量不同的结构之间的性能差异
- 为什么constexpr的性能比正常表达式差
- 在类中使用随机生成器时出现性能问题
- 在main()之外初始化std::vector会导致性能下降(多线程)
- 海湾合作委员会 ARM 性能下降
- GCC 和 Clang 代码性能的巨大差异
- 在容量内调整矢量大小时的性能影响
- 了解算法的性能差异(如果以不同的编程语言实现)
- 未达到的情况会影响开关外壳性能
- QStringList vs list<shared_ptr<QString>> 性能比较C++
- 是否总是可以将使用递归编写的程序重写为不使用递归的程序C++,性能观点是什么?
- C++ SSE 内部函数:将结果存储在变量中
- 单精度矩阵运算的特征性能 AVX 与 SSE 没有区别?
- 性能 AVX/SSE 程序集与内部函数
- SSE拷贝、AVX拷贝和std::拷贝性能
- SSE,主要行vs主要列的性能问题
- SSE的性能是相同的