【发布时间】:2015-07-19 15:28:46
【问题描述】:
作为一项学习练习,我正在尝试在各种架构上使用 SIMD 加速矩阵乘法代码。我的 SSE2 3D 矩阵乘法代码有一个奇怪的问题,它的性能在两个极端之间跳跃,大约 5 毫秒(预期)或大约 100 毫秒(100 万次操作)。
这段代码唯一“坏”的事情是未对齐的存储/加载以及最后将向量存储到内存中而没有第 4 个元素践踏内存的 hack。这可以解释一些性能差异,但性能差异如此之大的事实让我怀疑我错过了一些重要的东西。
我已经尝试了几件事,但我会在睡一觉之后再试一次。
见下面的代码。 m_matrix 变量在 16 字节边界上对齐。
void Matrix3x3::MultiplySSE2(Matrix3x3 &other, Matrix3x3 &output)
{
__m128 a_row, r_row;
__m128 a1_row, r1_row;
__m128 a2_row, r2_row;
const __m128 b_row0 = _mm_load_ps(&other.m_matrix[0]);
const __m128 b_row1 = _mm_loadu_ps(&other.m_matrix[3]);
const __m128 b_row2 = _mm_loadu_ps(&other.m_matrix[6]);
// Perform dot products with first row
a_row = _mm_set1_ps(m_matrix[0]);
r_row = _mm_mul_ps(a_row, b_row0);
a_row = _mm_set1_ps(m_matrix[1]);
r_row = _mm_add_ps(_mm_mul_ps(a_row, b_row1), r_row);
a_row = _mm_set1_ps(m_matrix[2]);
r_row = _mm_add_ps(_mm_mul_ps(a_row, b_row2), r_row);
_mm_store_ps(&output.m_matrix[0], r_row);
// Perform dot products with second row
a1_row = _mm_set1_ps(m_matrix[3]);
r1_row = _mm_mul_ps(a1_row, b_row0);
a1_row = _mm_set1_ps(m_matrix[4]);
r1_row = _mm_add_ps(_mm_mul_ps(a1_row, b_row1), r1_row);
a1_row = _mm_set1_ps(m_matrix[5]);
r1_row = _mm_add_ps(_mm_mul_ps(a1_row, b_row2), r1_row);
_mm_storeu_ps(&output.m_matrix[3], r1_row);
// Perform dot products with third row
a2_row = _mm_set1_ps(m_matrix[6]);
r2_row = _mm_mul_ps(a2_row, b_row0);
a2_row = _mm_set1_ps(m_matrix[7]);
r2_row = _mm_add_ps(_mm_mul_ps(a2_row, b_row1), r2_row);
a2_row = _mm_set1_ps(m_matrix[8]);
r2_row = _mm_add_ps(_mm_mul_ps(a2_row, b_row2), r2_row);
// Store only the first 3 elements in a vector so we dont trample memory
_mm_store_ss(&output.m_matrix[6], _mm_shuffle_ps(r2_row, r2_row, _MM_SHUFFLE(0, 0, 0, 0)));
_mm_store_ss(&output.m_matrix[7], _mm_shuffle_ps(r2_row, r2_row, _MM_SHUFFLE(1, 1, 1, 1)));
_mm_store_ss(&output.m_matrix[8], _mm_shuffle_ps(r2_row, r2_row, _MM_SHUFFLE(2, 2, 2, 2)));
}
【问题讨论】:
-
做100万次测试几次,得到平均时间。只做一次测试会得到不可靠的结果。
-
@CoffeeandCode 我已经将平均值作为测试台的一部分。与具有 SSE2 的 2D 和 4D 矩阵相比,平均时间仍然是异常的。踩踏行为无法用统计数据解释,代码有问题。
-
Idk,伙计。如果它有效,我不会说它有问题。顺便说一句,你怎么会做一个未对齐的商店?
-
@CoffeeandCode 3x3 矩阵的行的步长为 12 字节,但 SSE 中的对齐指令要求地址在 16 字节边界上对齐。所以在第一行之后,我们不能使用对齐的加载/存储。
-
这就是为什么我建议只使用 4x4 或 3x4 矩阵的原因,除非您真的受限于空间。在另一个领域:您是否在其他线程接触相同数据的情况下运行这些测试?当然,这会引发许多其他问题,例如什么架构等……为了缩小范围,请尝试对适当大小的数据进行操作的仅对齐变体。
标签: c++ sse intrinsics icc