我无法解释(并避免)Matlab mex程序与没有Matlab接口的相应C程序之间的速度差异.我一直在分析数值分析程序:
int main(){
Well_optimized_code();
}
Run Code Online (Sandbox Code Playgroud)
使用gcc 4.4针对Matlab-Mex等效编译(指向使用gcc44,这不是Matlab当前支持的版本,但出于其他原因需要):
void mexFunction(int nlhs,mxArray* plhs[], int nrhs, const mxArray* prhs[]){
Well_optimized_code(); //literally the exact same code
}
Run Code Online (Sandbox Code Playgroud)
我执行的时间如下:
$ time ./C_version
Run Code Online (Sandbox Code Playgroud)
与
>> tic; mex_version(); toc
Run Code Online (Sandbox Code Playgroud)
时间上的差异是惊人的.从命令行运行的版本平均需要5.8秒.Matlab中的版本在21秒内运行.对于上下文,mex文件替换了SimBiology工具箱中的算法,该算法大约需要26秒才能运行.
与Matlab的算法相比,C和mex版本都使用对openMP的调用线性扩展到27个线程,但为了进行性能分析,这些调用已被禁用并注释掉.
这两个版本以相同的方式编译,除了作为mex文件编译的必要标志:-fPIC --shared -lmex -DMATLAB_MEX_FILE应用于mex编译/链接.我删除了对mex文件的左右参数的所有引用.也就是说它不需要输入也没有输出,它仅用于分析.
伟大而光荣的谷歌告诉我,与位置无关的代码不应该是经济放缓的源头,除此之外我不知所措.
任何帮助将不胜感激,
安德鲁
我有一个密钥算法,其中大部分运行时用于计算密集矩阵产品:
A*A'*Y, where: A is an m-by-n matrix,
A' is its conjugate transpose,
Y is an m-by-k matrix
Typical characteristics:
- k is much smaller than both m or n (k is typically < 10)
- m in the range [500, 2000]
- n in the range [100, 1000]
Run Code Online (Sandbox Code Playgroud)
基于这些维度,根据矩阵链乘法问题的教训,很明显,在运算数意义上将计算结构化为最优A*(A'*Y).我当前的实现就是这样做的,而只是强迫关联性到表达式的性能提升是显而易见的.
我的应用程序是用C++编写的,用于x86_64平台.我正在使用Eigen线性代数库,英特尔的数学核心库作为后端.Eigen能够使用IMKL的BLAS接口来执行乘法,并且从我的Sandy Bridge机器上移动到Eigen的原生SSE2实现到Intel优化的基于AVX的实现的提升也很重要.
然而,表达式A * (A.adjoint() * Y)(用Eigen的说法)被分解为两个通用的矩阵 - 矩阵乘积(调用xGEMMBLAS例程),在它们之间创建一个临时矩阵.我想知道,通过一次专门的实现来一次评估整个表达式,我可以得到一个比我现在的通用更快的实现.一些让我相信这一点的观察结果是:
使用上述典型尺寸,输入矩阵A通常不适合缓存.因此,用于计算三矩阵乘积的特定存储器访问模式将是关键.显然,避免为部分产品创建临时矩阵也是有利的.
A 并且它的共轭转置显然具有非常相关的结构,可以利用它来改善整体表达的存储器访问模式.
是否有任何标准技术以缓存友好的方式实现这种表达式?我发现的矩阵乘法的大多数优化技术都是针对标准A*B情况而不是更大的表达式.我对这个问题的微优化方面很满意,例如转换成适当的SIMD指令集,但是我正在寻找任何可以用尽可能最友好的方式打破这个结构的引用.
编辑: …