MATLAB Answers

MEXファイルを利用​した関数のオーバーヘ​ッドを減らす方法につ​いて

10 views (last 30 days)
hotaka yagi
hotaka yagi on 3 Jan 2018
Commented: hotaka yagi on 6 Jan 2018
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 Comments

Sign in to comment.

Accepted Answer

michio
michio on 4 Jan 2018
Edited: michio on 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さんの方でも試して頂けますか?
今回のプログラムはあくまでサンプルで、実際に実行されたい計算は他にあるとは思いますが、まずは本当にオーバーヘッドが速度差の主要因なのかどうかを確認したく、回答させて頂きました。

  1 Comment

hotaka yagi
hotaka yagi on 6 Jan 2018
ご返信ありがとうございます。 おっしゃる通り、1純Cプログラムをdouble型に合わせ、2のように転置に気をつけ、メモリ純に参照するように変更して検証した結果ですが、
n=2^15;
a=rand(n);
b=rand(n,1);
tic;
a=a';
c=matVec(a,b);
toc;
  • Matlab版のMexファイル版が 2.7202 秒
  • Macでcプログラムを用いて計算した場合は 5.4986 秒
という結果になりました。

Sign in to comment.

More Answers (1)

mizuki
mizuki on 4 Jan 2018
MatPro.m が何を行っているファイルか分かりませんが、ビルトインの MATLAB 関数をコールしていると時間がかかるようです。
生成されたコードを見る限り、Cコード向けに書かれているようなのでこの点は当てはまらないと思いますが、ベクトル化など MATLAB 向けに最適化したコードの場合、遅くなることがあります。

  1 Comment

hotaka yagi
hotaka yagi on 4 Jan 2018
MatPro.cはmファイルではなくcファイルで、行列ベクトル積を行うc関数MatProを呼び出すMEXファイルを作成しているファイルです。
また、そのページでも書いてある通り、このようにc関数をMatlabで呼び出す際、オーバーヘッドに時間がかかってしまいます。その時間を減らす方法を教えていただけますか?

Sign in to comment.

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!