在使用此实现编写了一个表示两个 1D 缓冲区中的整个矩阵的矩阵类之后 ,我已经在我的项目中达到了矩阵多重乘法部分,并且现在倾向于一些缓存友好的优化。偶然发现了两个选项(问题在此页面的下部):
1)仅在乘法时间内选择阻塞/平铺子矩阵。
- 在 c++ DLL 函数中完成,因此没有函数开销。
- 由于代码会更复杂,因此更难应用额外的优化。
2)从子矩阵类(较小的补丁)构建矩阵类,因此通常在子矩阵类上进行乘法。
- 面向对象的方法为子矩阵的额外优化留出了空间。
- C# 的对象标头和填充行为可以帮助克服关键的进步吗?
- 多次调用而不是几次调用后,函数开销可能会成为问题。
矩阵乘法示例:C=AB
A
1 2 3 4 is used as 1 2 3 4
4 3 4 2 4 3 4 2
1 3 1 2
1 1 1 2 1 3 1 2
1 1 1 2
B
1 1 1 1 ---> 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1
Multiplication: 1 2 * 1 1 + 3 4 * 1 1 ==> upper-left tile of result
4 3 1 1 4 2 1 1
same for the upper-right of result
1 3 * 1 1 + 1 2 * 1 1 ==> lower left tile of result
1 1 1 1 1 2 1 1
same for lower-right tile of result
Multiplication is O(n³) but summation is O(n²).
问题:有没有人尝试过(功能和面向对象)并进行性能比较?现在,我的天真乘法没有任何这些缓存目标优化,需要:
Matrix Size Single Threaded Time Multithreaded Time
* 128x128 : 5 ms 1ms-5ms(time sample error is bigger)
* 256x256 : 25 ms 7 ms
* 512x512 : 140 ms 35 ms
* 1024x1024 : 1.3 s 260 ms
* 2048x2048 : 11.3 s 2700 ms
* 4096x4096 : 88.1 s 24 s
* 8192x8192 : 710 s 177 s
Giga-multiplications of variables per second
Single threaded Multithreaded Multi/single ratio
* 128x128 : 0.42 2.0 - 0.4 ?
* 256x256 : 0.67 2.39 3.67x
* 512x512 : 0.96 3.84 4.00x
* 1024x1024 : 0.83 3.47 4.18x
* 2048x2048 : 0.76 3.18 4.18x
* 4096x4096 : 0.78 2.86 3.67x
* 8192x8192 : 0.77 3.09 4.01x
(使用 32 位浮点数的 avx 优化代码的 1.4GHz fx8150 的平均结果)(Visual Studio C# 的 Parallel.For() 中的 dll 函数中的 c++ avx-intrinsics)
上述哪种大小的矩阵可能会受到缓存未命中、临界步长和其他坏事的影响?你知道我怎样才能得到那些使用内在函数的性能计数器吗?
谢谢你的时间。
编辑: DLL 内的内联优化:
Matrix Size Single Threaded Time Multithreaded Time Multi/Single radio
* 128x128 : 1 ms(%400) 390us avrage in 10k iterations(6G mult /s)
* 256x256 : 12 ms(%108 faster) 2 ms (%250 faster) 6.0x
* 512x512 : 73 ms(%92 faster) 15 ms (%133 faster) 4.9x
* 1024x1024 : 1060 ms(%22 faster) 176 ms (%48 faster) 6.0x
* 2048x2048 : 10070 ms(%12 faster) 2350 ms (%15 faster) 4.3x
* 4096x4096 : 82.0 s(%7 faster) 22 s (%9 faster) 3.7x
* 8192x8192 : 676 s(%5 faster) 174 s (%2 faster) 4.1x
在内联之后,较小乘法的阴影性能变得可见。仍然存在 DLL-function-C# 开销。1024x1024 的情况似乎是缓存未命中的起点。虽然工作量只增加了七倍,但执行时间却增加到了十五倍。
编辑: : 本周将使用面向对象的方法尝试 Strassen 的 3 层深度算法。主矩阵将由 4 个子矩阵组成。然后它们将由每个子 4 个子组成。然后它们将分别由 4 个 sub-sub-sub 组成。这应该提供几乎 (8/7) (8/7) (8/7)= +%50 的加速。如果可行,会将 DLL 函数转换为使用更多缓存的补丁优化函数。