最近期的处理器支持AVX
技术。它提供了一个包含4个双精度(256位寄存器)的向量。因此,这种优化的解决方案可能会使用AVX。为此,我使用x86intrin.h
库实现它,它是GCC
编译器的一部分。我还使用OpenMP
使解决方案成为多线程。
//gcc -Wall -fopenmp -O2 -march=native -o "MatrixVectorMultiplication" "MatrixVectorMultiplication.c"
//gcc 7.2, Skylake Corei7-6700 HQ
//The performance improvement is significant (5232 Cycle in my machine) but MKL is not available to test
#include <stdio.h>
#include <x86intrin.h>
double A[20][1024] __attribute__((aligned(32))) = {{1.0, 2.0, 3.0, 3.5, 1.0, 2.0, 3.0, 3.5}, {4.0, 5.0, 6.0, 6.5,4.0, 5.0, 6.0, 6.5},{7.0, 8.0, 9.0, 9.5, 4.0, 5.0, 6.0, 6.5 }};//The 32 is for 256-bit registers of AVX
double B[1024] __attribute__((aligned(32))) = {2.0, 2.0, 2.0, 2.0, 3.0, 3.0, 3.0, 3.0 }; //the vector
double C[20][1024] __attribute__((aligned(32)));//the results are stored here
int main()
{
int i,j;
__m256d vec_C1, vec_C2, vec_C3, vec_C4;
//begin_rdtsc
//get the start time here
#pragma omp parallel for
for(i=0; i<20;i++){
for(j=0; j<1024; j+=16){
vec_C1 = _mm256_mul_pd(_mm256_load_pd(&A[i][j]), _mm256_load_pd(&B[j]));
_mm256_store_pd(&C[i][j], vec_C1);
vec_C2 = _mm256_mul_pd(_mm256_load_pd(&A[i][j+4]), _mm256_load_pd(&B[j+4]));
_mm256_store_pd(&C[i][j+4], vec_C2);
vec_C3 = _mm256_mul_pd(_mm256_load_pd(&A[i][j+8]), _mm256_load_pd(&B[j+8]));
_mm256_store_pd(&C[i][j+8], vec_C3);
vec_C4 = _mm256_mul_pd(_mm256_load_pd(&A[i][j+12]), _mm256_load_pd(&B[j+12]));
_mm256_store_pd(&C[i][j+12], vec_C4);
}
}
//end_rdtsc
//calculate the elapsead time
//print the results
for(i=0; i<20;i++){
for(j=0; j<1024; j++){
//printf(" %lf", C[i][j]);
}
//printf("\n");
}
return 0;
}
我假设你的意思是1024行和20列?是固定的20(或在编译时已知并保证是4的倍数)?你的矩阵存储rowmajor或columnmajor? – chtz
@chtz 1024列 - 即功能。在另一种情况下是52列。两者都是固定的,是4的倍数。而20是批量大小。我选择了它,但它不可能很大。并且有许多这样的乘法迭代。 –
我可能误解了你想要做的事情。如果你想为每一行逐个元素地进行乘法运算,那么你的矩阵应该有与矢量元素一样多的列,不是吗? (如果这不是你想要的,请写一些伪代码,或者你正在使用的代码) – chtz