我有以下的工作程序,它能正确地产生结果,但我对一些统计数字感到困惑。设置是这样的。
代码是。
void MatrixMultiply(img_in1, img_in2, img_out, myRank, nRanks)
{
for (int i=startingRow ; i<endingRow ; i++) //no of rows of first matrix divided on per process basis
{
for (int j=0 ; j<M1Cdim ; j++) //no of cols of first matrix
{
int temp = 0;
for(int k=0 ; k<M2Rdim ; k++) //no of rows of second matrix
{
temp += in1[i*M1Rdim+k] * in2[k*M2Rdim+j]; //out(i,j) += in1(i,k) * in2(k,j)
}
out[i*M1Rdim+j] = temp;
}
}
}
main()
{
for (int i = 1; i <= 10; i++)
{
MPI_Barrier(MPI_COMM_WORLD);
const double t0 = omp_get_wtime();
MatrixMultiply(img_in1, img_in2, img_out, myRank, nRanks);
MPI_Barrier(MPI_COMM_WORLD);
const double t1 = omp_get_wtime();
const double ts = t1-t0; // time in seconds
const double tms = ts*1.0e3; // time in milliseconds
const double gbps = double(sizeof(P)*2*img_in1.height*img_in1.width*img_in2.height)*1e-9/ts; // bandwidth in GB/s
const double fpps = double(2*img_in1.height*img_in1.width*img_in2.height)*1e-9/ts; // performance in GFLOP/s
if (myRank == 0)
{
printf("%5d %15.3f %15.3f %15.3f %s\n", i, tms, gbps, fpps);
}
}
}
The statistics I am getting are:
Step Time, ms GB/s GFLOP/s
1 2.306 116.408 116.408
2 2.334 115.017 115.017
3 2.297 116.855 116.855
4 2.295 116.964 116.964
5 16.692 16.082 16.082
6 11.468 23.407 23.407
7 2.299 116.758 116.758
8 2.291 117.171 117.171
9 2.295 116.964 116.964
10 10.792 24.874 24.874
所以我的问题是:
为什么第5、6、10次迭代的结果比其他迭代的差?
我的怀疑是,即使数据被放置在高带宽内存(mcdram)中,但代码本身是从缓存中执行的,所以可能会受到影响。虽然整个程序非常小,如54KB,但如果运行在共享服务器上,那么一些迭代可能会从指令缓存中被驱逐,导致性能下降。
这个矩阵乘法代码是 效率低下!
的确,这条线 in2[k*M2Rdim+j]
有可能导致 高速缓存 于是 计算时间的高不稳定性 如果需要经常从MCD-RAM中重新加载线路。虽然MCD-RAM有很高的带宽,但它也有很高的延迟(类似于DDR-RAM的延迟)。在这种情况下,延迟可能是一个很大的问题。
具体来说,在矩阵的一列中跨下一列,对于空间定位来说是很糟糕的。 而当矩阵维度是2的幂数时,情况就更糟糕了:你很可能在缓存上出现冲突失误,因为所有这些缓存行都会在集关联缓存中别名到同一个集。 这可能会导致缓存打乱,即使工作集很小。
因此,请使用 BLAS 函数(来自MKL、OpenBLAS、ATLAS等)! 它们的优化程度远高于此。如果你不能,请考虑改进这个代码。你可以找到一个相当不错的解释,你可以这样做。此处. 我想,提速10以上是很容易实现的。
我还建议你 概况 使用 perf 或 VTune 等工具对您的代码进行分析。硬件事件 (如L1L2缓存操作),并确认拒绝现金粉碎假说,以及帮助你改进这段代码。