【发布时间】:2019-06-21 21:41:57
【问题描述】:
为什么我通过使用__m256 数据类型获得了如此巨大的加速(x16 倍)?
一次处理 8 个浮点数,所以我希望只能看到 x8 加速?
我的 CPU 是 4 核 Devil Canyon i7(具有超线程) 在发布模式下使用 Visual Studio 2017 进行编译 - O2 优化已打开。
快速版本在 400x400 矩阵上消耗 0.000151 秒:
//make this matrix only keep the signs of its entries
inline void to_signs() {
__m256 *i = reinterpret_cast<__m256*>(_arrays);
__m256 *end = reinterpret_cast<__m256*>(_arrays + arraysSize());
__m256 maskPlus = _mm256_set1_ps(1.f);
__m256 maskMin = _mm256_set1_ps(-1.f);
//process the main portion of the array. NOTICE: size might not be divisible by 8:
while(true){
++i;
if(i > end){ break; }
__m256 *prev_i = i-1;
*prev_i = _mm256_min_ps(*prev_i, maskPlus);
*prev_i = _mm256_max_ps(*prev_i, maskMin);
}
//process the few remaining numbers, at the end of the array:
i--;
for(float *j=(float*)i; j<_arrays+arraysSize(); ++j){
//taken from here:http://www.musicdsp.org/showone.php?id=249
// mask sign bit in f, set it in r if necessary:
float r = 1.0f;
(int&)r |= ((int&)(*j) & 0x80000000);//according to author, can end up either -1 or 1 if zero.
*j = r;
}
}
旧版本,运行时间为 0.002416 秒:
inline void to_signs_slow() {
size_t size = arraysSize();
for (size_t i = 0; i<size; ++i) {
//taken from here:http://www.musicdsp.org/showone.php?id=249
// mask sign bit in f, set it in r if necessary:
float r = 1.0f;
(int&)r |= ((int&)_arrays[i] & 0x80000000);//according to author, can end up either -1 or 1 if zero.
_arrays[i] = r;
}
}
是不是偷偷用了2核,所以一旦我开始使用多线程这个好处就消失了?
编辑:
在较大的矩阵上,大小为 (10e6)x(4e4) 我平均得到 3 秒和 14 秒。所以只是 x4 加速,甚至不是 x8 This is probably due to memory bandwidth, and things not fitting in cache
不过,我的问题是关于令人愉快的 x16 加速惊喜 :)
【问题讨论】:
-
恶魔峡谷处理器? Perhaps the answer is SATAN?
-
(int&)r |= [...]真的有效吗?它会将float&转换为int&吗?至少它看起来像严格的别名违规。 -
如果
end是一个过去的数组指针(似乎是),那么if(i > end){ break; }是真的i需要是过去的两个- 不存在的末端指针(试图得到一个是UB)。所以i > end可以安全地优化为false,循环可能没有中断条件。如果_mm256_and_ps是noexcept,整个循环就是UB,意味着整个函数就是UB。上面的例子可以简单地优化出来。你看过生成的程序集吗? -
你能测试更大的矩阵(达到大约 1 秒的时间)吗?这样的微基准根本不可靠。或者一次运行至少运行 1000 次。
标签: c++ visual-c++ compiler-optimization sse intrinsics