【发布时间】:2013-12-24 11:54:35
【问题描述】:
我想使用直接算法将两个矩阵相乘一次:
template <typename T>
void multiplicate_straight(T ** A, T ** B, T ** C, int sizeX)
{
T ** D = AllocateDynamicArray2D<T>(sizeX, sizeX);
transpose_matrix(B, D,sizeX);
for(int i = 0; i < sizeX; i++)
{
for(int j = 0; j < sizeX; j++)
{
for(int g = 0; g < sizeX; g++)
{
C[i][j] += A[i][g]*D[j][g];
}
}
}
FreeDynamicArray2D<T>(D);
}
一次通过使用 SSE 函数。为此,我创建了两个函数:
template <typename T>
void SSE_vectormult(T * A, T * B, int size)
{
__m128d a;
__m128d b;
__m128d c;
#ifdef linux
double A2[2], B2[2], C[2] __attribute__ ((aligned(16)));
#endif
#ifdef _WIN32
__declspec(align(16)) double A2[2], B2[2], C[2];
#endif
for(int i = 0; i < size; i+=2)
{
//std::cout << "In SSE_vectormult: i is: " << i << '\n';
A2[0] = A[i];
B2[0] = B[i];
A2[1] = A[i+1];
B2[1] = B[i+1];
//std::cout << "Values from A and B written to A2 and B2\n";
a = _mm_load_pd(A2);
b = _mm_load_pd(B2);
//std::cout << "Values converted to a and b\n";
c = _mm_mul_pd(a,b);
_mm_store_pd(C, c);
A[i] = C[0];
A[i+1] = C[1];
};
}
和
template <typename T>
void multiplicate_SSE(T ** A, T ** B, T ** C, int sizeX)
{
// std::cout << "Entered SSE-Function\n";
T ** D = AllocateDynamicArray2D<T>(sizeX, sizeX);
T * tmp = AllocateDynamicArray1D<T>(sizeX);
T * tmp2 = AllocateDynamicArray1D<T>(sizeX);
//std::cout << "Matrices allocated\n";
transpose_matrix<T>(B, D,sizeX);
//std::cout << "Matrix B transposed\n";
for(int i = 0; i < sizeX; i++)
{
for(int j = 0; j < sizeX; j++)
{
extract_row<T>(A,tmp, i, sizeX);
// std::cout << "Row from A extracted\n";
//print_vector(tmp, sizeX);
extract_row<T>(D, tmp2, j, sizeX);
// std::cout << "Row from D extracted\n";
//print_vector(tmp2, sizeX);
SSE_vectormult<T>(tmp, tmp2, sizeX);
// std::cout << "Vectors multiplicated\n";
//print_vector(tmp, sizeX);
C[i][j] = add_vector(tmp, sizeX);
// std::cout << "Written value to C\n";
// std::cout << "j is " << j << " and i is " << i << '\n';
}
}
// std::cout << "Loop finished\n";
FreeDynamicArray2D<T>(D);
//std::cout << "Freed D\n";
//FreeDynamicArray1D<T>(tmp);????
// std::cout << "Freed tmp\n";
FreeDynamicArray1D<T>(tmp2);
// std::cout << "Everything freed, returning\n";
}
但是我遇到了几个问题:一方面,当我想释放 multiplicate_SSE() 中标有几个问号的 tmp 数组时,我收到错误“_BLOCK_TYPE_IS_VALID”。我考虑过两次释放相同空间的可能性,所以我取消了注释(但我想我会通过这个得到内存泄漏?)。现在,当我将两个函数的性能与相同的矩阵进行比较时,两个 1024x1024 矩阵的 SSE 函数所需的时间大约是直接方法的四倍。
如何重写我的 SSE-Function 以获得更好的性能(我以前从未使用过 SSE),以及如何修复我的内存泄漏?
谢谢!
【问题讨论】:
-
看起来您陷入了数据移动过多而计算量过少的常见陷阱。您有一个实际的算术指令用于 9 次以上的内存访问。这是1/9的比率。如果您想要任何形式的体面加速,则该比率至少需要达到 2/1。
-
@Mysticial:那么有没有可能重写函数来加快速度,还是我的问题不适合这个?
-
矩阵乘法可以以具有高计算/内存访问率的方式完成。但这并不容易。
-
适用于这两种方法的一个小建议是跳过转置,并在第二个矩阵的第一个(而不是第二个)维度上求和。即:
C[i][j] += A[i][g]*D[g][j]; -
@Matt:但这不会减少我的数据移动开销...