开发者社区> 问答> 正文

为什么2048x2048与2047x2047阵列乘法相比会产生巨大的性能影响?

我正在做一些矩阵乘法基准测试,如前面在 MATLAB为什么矩阵乘法中这么快?

现在,我又遇到了另一个问题,当将两个2048x2048矩阵相乘时,C#与其他矩阵有很大的不同。当我尝试仅乘以2047x2047矩阵时,这似乎很正常。也添加了一些其他内容进行比较。

1024x1024-10秒。

1027x1027-10秒。

2047x2047-90秒。

2048x2048-300秒。

2049x2049-91秒。(更新)

2500x2500-166秒

对于2k x 2k的情况,这是三分半钟的差异。

使用2dim数组

//Array init like this int rozmer = 2048; float[,] matice = new float[rozmer, rozmer];

//Main multiply code for(int j = 0; j < rozmer; j++) { for (int k = 0; k < rozmer; k++) { float temp = 0; for (int m = 0; m < rozmer; m++) { temp = temp + matice1[j,m] * matice2[m,k]; } matice3[j, k] = temp; } } 问题来源于stack overflow

展开
收起
保持可爱mmm 2020-02-07 22:48:00 690 0
1 条回答
写回答
取消 提交回答
  • 这可能与L2缓存中的冲突有关。

    matice1上的缓存未命中不是问题,因为它们是按顺序访问的。但是对于matice2,如果一个完整的列适合L2(即,当您访问matice2 [0,0],matice2 [1,0],matice2 [2,0]等时,什么都不会被驱逐),那么这没有问题用matice2缓存未命中。

    现在更深入地了解缓存的工作原理,如果变量的字节地址为X,则其缓存行将为(X >> 6)&(L-1)。其中L是缓存中缓存行的总数。L始终是2的幂。这六个事实来自于2 ^ 6 == 64字节是高速缓存行的标准大小。

    现在这是什么意思?好吧,这意味着如果我有地址X和地址Y并且(X >> 6)-(Y >> 6)可被L整除(即2的大幂),它们将存储在同一高速缓存行中。

    现在回到您的问题,2048和2049有什么区别,

    当您的大小为2048时:

    如果采用&matice2 [x,k]和&matice2 [y,k],则差(&matice2 [x,k] >> 6)-(&matice2 [y,k] >> 6)将被2048 * 4除(大小的浮动)。因此2的大方。

    因此,根据L2的大小,您将有很多缓存行冲突,并且仅利用L2的一小部分来存储列,因此您实际上将无法在缓存中存储完整的列,因此会导致性能下降。

    当size为2049时,差异为2049 * 4(不是2的幂),因此冲突更少,并且列将安全地放入缓存中。

    现在,要检验此理论,您可以做一些事情:

    像matice2 [razmor,4096]这样分配数组matice2数组,并以razmor = 1024、1025或任何大小运行,与以前相比,您会发现性能很差。这是因为您强制对齐所有列以使其相互冲突。

    然后尝试使用matice2 [razmor,4097]并以任意大小运行它,您应该会看到更好的性能。

    2020-02-07 22:48:24
    赞同 展开评论 打赏
问答分类:
问答地址:
问答排行榜
最热
最新

相关电子书

更多
图计算优化技术探索 立即下载
数据带来无限可能 立即下载
混合存储产品 立即下载