MEXファイルを利用した関数のオーバーヘッドを減らす方法について
6 Ansichten (letzte 30 Tage)
Ältere Kommentare anzeigen
Matlab上のMexファイルを用いた関数のオーバーヘッドを少なくする方法について
同じ内容の行列ベクトル積のcプログラムを用いて数値実験を行い、その際の時間計測を行いました。
Mexファイルは以下です。
#include "mex.h"
#include "math.h"
/* The computational routine */
void MatPro(double *x, double *y, double *z, mwSize m, mwSize n)
{
int i;
int j;
/* main program */
for(i=0;i<m;i++){
z[i]=0;
for(j=0;j<m;j++){
z[i]=z[i]+x[m*j+i]*y[j];
}
}
}
/* The gateway function */
void mexFunction( int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[])
{
double *in1; /* input scalar */
mwSize n; /* size of matrix */
mwSize m;
double *in2;
double *out; /* output matrix */
/* get the value of the input */
in1 =mxGetPr(prhs[0]);
/* create a pointer to the real data in the input matrix */
in2 =mxGetPr(prhs[1]);
/* get dimensions of the input matrix */
m = (mwSize)mxGetM(prhs[1]); //GYO
n = (mwSize)mxGetN(prhs[1]); //RETU
/* create the output matrix */
plhs[0] = mxCreateDoubleMatrix(m,n,mxREAL);
/* get a pointer to the real data in the output matrix */
out = mxGetPr(plhs[0]);
/* call the computational routine */
MatPro(in1,in2,out,m,n);
}
このプログラムを用いて、以下のように実験しました。
M=rand(32768);
x=rand(32768,1);
for i=1:100
tic;
y=MatPro(M,x);
tim=tim+toc;
end
tim=tim/100;
さらに、行列ベクトル積のcファイルは以下です。
#include "stdio.h"
#include "time.h"
#include "math.h"
#include "stdlib.h"
#include "omp.h"
void matVec(long *ans1, long *ans2)
{
// set variables
int m=32768;
int n=1;
int* x;
int* y;
int* z;
struct timespec startTime, endTime;
// set matrix
x=(int *)malloc(sizeof(int) * m*m);
y=(int *)malloc(sizeof(int) * m*n);
z=(int *)malloc(sizeof(int) * m*n);
// set value
for (i=0;i<m*n;i++) {
x[i]=rand();
y[i]=rand();
}
// check start time
clock_gettime(CLOCK_REALTIME, &startTime);
// calculation
for(i=0;i<m;i++){
z[i]=0;
for(j=0;j<m;j++){
z[i]=z[i]+x[m*i+j]*y[j];
}
}
// check end time
clock_gettime(CLOCK_REALTIME, &endTime);
// output
if (endTime.tv_nsec < startTime.tv_nsec) {
*ans1=endTime.tv_sec - startTime.tv_sec - 1;
*ans2=endTime.tv_nsec + (long int)1.0e+9 - startTime.tv_nsec;
} else {
*ans1=endTime.tv_sec - startTime.tv_sec;
*ans2=endTime.tv_nsec - startTime.tv_nsec;
}
}
int main(void){
long *ans1;
long *ans2;
printf("次数 = %09d, 計測時間 = ",m);
matVec(&ans1,&ans2);
printf("%5ld.%09ld",ans1,ans2);
printf(" (sec)\n");
return 0;
}
このプログラムを用いて先ほどと同様に100回計算した時の計算時間の平均値を求めました。
用いたマシンはMacbook Pro (intel core i7, 2.5GHz, 16GBmemory, macOS High sierra ver 10.13.1)で、コンパイラはclang 5.0.0です。また、コンパイラオプションは利用していません。Matlabは2017Rを利用しました。
これらの環境で同じプログラムを動かした結果、
MatlabのMexファイル版が 44.0157 秒、
Macでcプログラムを用いて計算した場合は 3.927542 秒
という結果でした。
どうすればMatlabのMexファイル版のオーバーヘッドを減らすことができるでしょうか。
0 Kommentare
Akzeptierte Antwort
michio
am 4 Jan. 2018
Bearbeitet: michio
am 4 Jan. 2018
再現ステップを詳細にまとめてくださりありがとうございます。Windowsマシンではありますが、同じような傾向がこちらでもR2017bで確認できました。
MEX関数を実行する際のオーバーヘッドがどこで発生しているのかを検討していたのですが、その過程で純C言語で実行されるプログラムとMEXファイルのソースコードの間で2つ大きな実装面での違いが気になりました。
1: 純Cプログラムは整数型、MEX関数はdouble型。整数型の積の方が低負荷。
2: 純Cプログラムは値の参照がメモリ順、MEX関数は飛び飛び。
z[i]=z[i]+x[m*j+i]*y[j];
部分を
z[i]=z[i]+x[m*i+j]*y[j];
と x の要素をメモリ順に参照するよう実装した方が負荷が低くなります。もちろん、転置などの作業が別に発生してしまいますが・・。
上記の2点を変更した上で同じように実行速度を検証した結果、速度差は随分小さく(少なくとも NxN行列とNx1ベクトル(N=10,000)の積ではMEX関数の方が速い)結果になりましたので、yagiさんの方でも試して頂けますか?
今回のプログラムはあくまでサンプルで、実際に実行されたい計算は他にあるとは思いますが、まずは本当にオーバーヘッドが速度差の主要因なのかどうかを確認したく、回答させて頂きました。
Weitere Antworten (1)
mizuki
am 4 Jan. 2018
MatPro.m が何を行っているファイルか分かりませんが、ビルトインの MATLAB 関数をコールしていると時間がかかるようです。
- Why is m-function overhead 100 times more than built-in overhead. https://jp.mathworks.com/matlabcentral/answers/155490
生成されたコードを見る限り、Cコード向けに書かれているようなのでこの点は当てはまらないと思いますが、ベクトル化など MATLAB 向けに最適化したコードの場合、遅くなることがあります。
Siehe auch
Kategorien
Mehr zu C MEX ファイル アプリケーション finden Sie in Help Center und File Exchange
Produkte
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!