Main Content

MATLAB プロファイラーを使用した MEX 関数のプロファイリング

MATLAB® Coder™ によって生成された MEX 関数の実行時間を MATLAB プロファイラーを使用してプロファイリングできます。生成コードのプロファイルには、呼び出し回数および対応する MATLAB 関数の各行に要した時間が表示されます。最も時間がかかる生成コードを生み出した MATLAB コードの行を特定するには、プロファイラーを使用します。この情報は、開発サイクルの初期段階でパフォーマンスの問題を特定して修正するのに役立ちます。MATLAB プロファイラーの詳細については、profileパフォーマンス向上のためのコードのプロファイリングを参照してください。

プロファイラーへのグラフィカルなインターフェイスは MATLAB Online™ ではサポートされていません。

MEX プロファイルの生成

生成された MEX 関数で MATLAB プロファイラーを使用することができます。あるいは、MATLAB 関数を呼び出すテスト ファイルがある場合は、MEX 関数の生成とプロファイリングを 1 ステップで実行できます。これらの操作は、コマンド ラインまたは MATLAB Coder アプリで実行できます。

生成された MEX 関数でプロファイラーを使用するには、以下を実行します。

  1. 構成オブジェクト プロパティ EnableMexProfilingtrue に設定することで、MEX プロファイリングを有効にします。

    代わりに、-profile オプションを指定して codegen を使用することもできます。

    MATLAB Coder アプリでの同等の設定は、[生成] ステップの [実行プロファイリングを有効にする] です。

  2. MEX ファイル MyFunction_mex を生成します。

  3. MATLAB プロファイラーを実行し、別のウィンドウで開くプロファイル概要レポートを表示します。

    profile on;
    MyFunction_mex;
    profile viewer;

    元の MATLAB ファイル MyFunction.m を変更または移動させていないことを確認します。変更または移動させていた場合、プロファイラーはプロファイリングで MyFunction_mex を考慮しません。

MATLAB 関数を呼び出すテスト ファイル MyFunctionTest.m がある場合は、以下を実行できます。

  • -test オプションと -profile オプションを指定した codegen を使用して、MEX 関数の生成とプロファイリングを 1 ステップで実行できます。以前に MATLAB プロファイラーをオンにしていた場合は、これら 2 つのオプションを一緒に使用する前にオフにします。

    codegen MyFunction -test MyFunctionTest -profile
  • アプリの [検証] ステップの [実行プロファイリングを有効にする] を選択することで、MEX 関数をプロファイリングします。以前に MATLAB プロファイラーをオンにしていた場合は、この操作を実行する前にオフにします。

プロファイラーを使用して、最も時間がかかる生成コードを生み出す関数または MATLAB コードの行を特定します。入力行列 A および B の表現を行優先から列優先のレイアウトに 1 行で変換する MATLAB 関数の例を以下に示します。大規模な行列の場合は、こうした変換の実行に長い時間を要します。特定の行を変更して変換を回避することで、関数の効率性が向上します。

以下の MATLAB 関数について考えます。

function [y] = MyFunction(A,B) %#codegen

% Generated code uses row-major representation of matrices A and B
coder.rowMajor; 
length = size(A,1);

% Summing absolute values of all elements of A and B by traversing over the
% matrices row by row
sum_abs = 0;  
for row = 1:length 
   for col = 1:length  
       sum_abs = sum_abs + abs(A(row,col)) + abs(B(row,col));
   end
end

% Calling external C function 'foo.c' that returns the sum of all elements
% of A and B
sum = 0;
sum = coder.ceval('foo',coder.ref(A),coder.ref(B),length);

% Returning the difference of sum_abs and sum
y = sum_abs - sum;
end

この関数の生成コードでは、正方行列 A および B の行優先の表現を使用します。コードでは最初に、行列を行ごとに移動することで sum_abs (AB のすべての要素の絶対値の合計) を計算します。このアルゴリズムは、行優先のレイアウトで表現される行列向けに最適化されています。次に、コードでは coder.ceval を使用して外部の C 関数 foo.c を呼び出します。

#include <stdio.h>
#include <stdlib.h>
#include "foo.h"

double foo(double *A, double *B, double length)
{
 int i,j,s;
 double sum = 0;
 s = (int)length;
 
 /*Summing all the elements of A and B*/
 for(i=0;i<s*s;i++)
 {
         sum += A[i] + B[i];
 }
 return(sum);
}

対応する C ヘッダー ファイル foo.h は以下の通りです。

#include "rtwtypes.h"

double foo(double *A, double *B, double length);

foo.c は変数 sum を返します。この変数は、AB のすべての要素の合計です。関数 foo.c のパフォーマンスは、行列 AB が行優先のレイアウトまたは列優先のレイアウトで表現されるかどうかに影響されません。MyFunctionsum_abssum の差を返します。

大規模な入力行列 ABMyFunction のパフォーマンスを測定してから、それをさらに最適化できます。

  1. MEX プロファイリングを有効にして、MyFunction の MEX コードを生成します。2 つの大規模な乱数行列 AB に対して MyFunction_mex を実行します。プロファイル概要レポートを確認します。

    A = rand(20000);
    B = rand(20000);
    
    codegen MyFunction -args {A,B} foo.c foo.h -profile
    
    profile on; 
    MyFunction_mex(A,B);
    profile viewer;

    別のウィンドウが開き、プロファイル概要レポートが表示されます。

    Profile summary exhibiting a table with field Function Name Calls, Total Time in seconds, Self Time in seconds and total time plot. A flame graph is present, representing the table in a bar graph.

    プロファイル概要レポートには MEX ファイルとその子 (元の MATLAB 関数の生成コード) の合計時間と自己時間が表示されます。

  2. [関数名] で最初のリンクをクリックし、MyFunction の生成コードのプロファイル詳細レポートを表示します。最も時間がかかった行を確認できます。

    Table with fields Line Number, Code, Cells, Total time in seconds, Percentage of time and time plot with relevant data entries from example code. Important to point out that the total time for coder.ceval is relatively high.

  3. coder.ceval を呼び出す行に時間がかかっています (16.914 秒)。この行の実行にかなりの時間を要したのは、外部の C 関数に渡す前に、coder.ceval が行列 AB の表現を行優先のレイアウトから列優先のレイアウトに変換するためです。coder.ceval で追加の引数 -layout:rowMajor を使用することで、この変換を回避することができます。

    sum = coder.ceval('-layout:rowMajor','foo',coder.ref(A),coder.ref(B),length);
  4. 変更した MyFunction を使用して、MEX 関数とプロファイルを再度生成します。

    A = rand(20000);
    B = rand(20000);
    
    codegen MyFunction -args {A,B} foo.c foo.h -profile
    
    profile on; 
    MyFunction_mex(A,B);
    profile viewer;
    MyFunction のプロファイル詳細レポートは、coder.ceval を呼び出す行にかかる時間がわずか 0.653 秒になったことを示しています。

    Same image as mentioned above, here coder.ceval has a reduced total time of 0.653s.

MEX コード カバレッジに対する式の畳み込みの効果

coder.const を使用して式を定数に畳み込むとき、MATLAB 関数と MEX 関数の間のコード カバレッジに差異が生じます。たとえば、以下の関数について考えます。

function y = MyFoldFunction %#codegen
a = 1;
b = 2; 
c = a + b;
y = 5 + coder.const(c);
end

MATLAB 関数 MyFoldFunction をプロファイリングすると、プロファイル詳細レポートにこのコード カバレッジが表示されます。

Profile Detail Report, showing code coverage

しかし、MEX 関数 MyFoldFunction_mex をプロファイリングすると異なるコード カバレッジが表示されます。

Profile Detail Report, showing code coverage

コード生成では式 c = a + b を定数に畳み込んでいるため、行 2、3 および 4 は生成コードでは実行されません。

この例では、ユーザー定義の式の畳み込みを使用します。コード ジェネレーターは、生成コードのパフォーマンスを最適化するために、特定の式を自動的に畳み込む場合があります。こうした最適化も、MEX 関数のカバレッジが MATLAB 関数と異なるものになる要因です。

参考

| | | | |

関連するトピック