Mono C#/C++ Interop,优化矩阵乘法 - 开销导致的最小收益?
Mono C#/C++ Interop, optimizing matrix multiplications - minimal gain due to overhead?
我在 C# 上有一个矩阵结构,在不使用 SSE 内在函数的情况下实现了乘法运算。由于此时我无法访问代码,因此我将尝试尽可能多地指定详细信息,而不是 copy/pasting 定义。如果需要,我可以在早上编辑 post 以包含相关定义。
该结构有 16 个 float
定义为 M11, M12, M13, ..., M43, M44'
,并指定了顺序布局:[StructLayout(LayoutKind.Sequential)]
C++ 函数是用属性规范声明的
[DllImport("cppCode.dll", EntryPoint = "MatrixMultiply", CallingConvention = CallingConvention::Cdecl]
我正在尝试使用 P/Invoke 调用 C++ 函数来优化乘法。我的问题是关于传递参数。正如在 MSDN 上提到的,如果传递的类型不可 blittable,成本是 CPU + 编组的 10 到 30 个周期。
C# 上的函数调用看起来像
MatrixMultiply(ref matrix1, ref matrix2, out matrix_out);
并且 C++ 对应方使用 mat*
接收它们,其中 mat
是具有 4x vec4
s.
的匹配 C++ 结构
static extern void MatrixMultiply(mat* m1, mat* m2, mat* out) { *out = *m1 * *m2; }
分析计算时,增益非常小——一般情况下只有一两微秒。然而,最坏的情况变得更糟,从使用 C# 乘法的 150us 到使用 C++ 乘法的 400us,这让我认为从导出的 dll 调用函数的开销几乎抵消了 SSE 指令的增益。
由于我对 C# 的了解有限,我不能确定发生了什么。难道我做错了什么?在这种特殊情况下,是否有更快的 C#/C++ 通信方法?
如果 Numerics 无法提供足够好的解决方案,您最好的选择是尽量减少 p/Invoke 调用。不要为每个乘法调用 Multiply(m1, m2, m_out)
,而是尽可能在 C++ 端尝试在一次调用中连接矩阵,如下所示:
void MatrixConcat3(m1, m2, m3, m_out);
void MatrixConcat4(m1, m2, m3, m4, m_out);
void MatrixConcat5(m1, m2, m3, m4, m5, m_out);
...
这将减少进行多次调用的开销。
我在 C# 上有一个矩阵结构,在不使用 SSE 内在函数的情况下实现了乘法运算。由于此时我无法访问代码,因此我将尝试尽可能多地指定详细信息,而不是 copy/pasting 定义。如果需要,我可以在早上编辑 post 以包含相关定义。
该结构有 16 个 float
定义为 M11, M12, M13, ..., M43, M44'
,并指定了顺序布局:[StructLayout(LayoutKind.Sequential)]
C++ 函数是用属性规范声明的
[DllImport("cppCode.dll", EntryPoint = "MatrixMultiply", CallingConvention = CallingConvention::Cdecl]
我正在尝试使用 P/Invoke 调用 C++ 函数来优化乘法。我的问题是关于传递参数。正如在 MSDN 上提到的,如果传递的类型不可 blittable,成本是 CPU + 编组的 10 到 30 个周期。
C# 上的函数调用看起来像
MatrixMultiply(ref matrix1, ref matrix2, out matrix_out);
并且 C++ 对应方使用 mat*
接收它们,其中 mat
是具有 4x vec4
s.
static extern void MatrixMultiply(mat* m1, mat* m2, mat* out) { *out = *m1 * *m2; }
分析计算时,增益非常小——一般情况下只有一两微秒。然而,最坏的情况变得更糟,从使用 C# 乘法的 150us 到使用 C++ 乘法的 400us,这让我认为从导出的 dll 调用函数的开销几乎抵消了 SSE 指令的增益。
由于我对 C# 的了解有限,我不能确定发生了什么。难道我做错了什么?在这种特殊情况下,是否有更快的 C#/C++ 通信方法?
如果 Numerics 无法提供足够好的解决方案,您最好的选择是尽量减少 p/Invoke 调用。不要为每个乘法调用 Multiply(m1, m2, m_out)
,而是尽可能在 C++ 端尝试在一次调用中连接矩阵,如下所示:
void MatrixConcat3(m1, m2, m3, m_out);
void MatrixConcat4(m1, m2, m3, m4, m_out);
void MatrixConcat5(m1, m2, m3, m4, m5, m_out);
...
这将减少进行多次调用的开销。