Main Content

fiaccel を使用したコードの高速化

fiaccel による固定小数点実行の高速化

fiaccel を使用すると、固定小数点 MATLAB® コードを MEX 関数に変換できます。生成される MEX 関数には、MATLAB で固定小数点アルゴリズムをコンパイル済み C/C++ コードのスピードに自動的に高速化するための最適化機能が含まれています。関数 fiaccel によって、アルゴリズムの実行速度が大幅に向上されます。

fiaccel の実行

以下に基本のコマンドを示します。

fiaccel M_fcn

既定では、fiaccel は次のアクションを実行します。

  • コンパイル パスの検索順序に指定されているように、ファイル M_fcn.m に保存されている関数 M_fcn を検索します。

  • M_fcn を MEX コードにコンパイルします。

  • エラーや警告がない場合は、ファイル命名規則に説明されている命名規則を使用して、現在のフォルダーにプラットフォーム固有の MEX ファイルを生成します。

  • エラーがある場合は MEX ファイルは生成しませんが、生成ファイルと場所に説明されているように、エラー レポートを既定の出力フォルダーに生成します。

  • 警告がある場合でエラーがない場合は、現在のフォルダーにプラットフォーム固有の MEX ファイルを生成し、警告をレポートします。

この既定の動作は、fiaccel で 1 つ以上のコンパイラ オプションを指定して変更できます (複数のオプションはコマンド ライン上で空白で区切ります)。

生成ファイルと場所

fiaccel では次の場所にファイルが生成されます。

生成物In:

プラットフォーム固有の MEX ファイル

現在のフォルダー

コード生成レポート

(コンパイル中にエラーや警告が発生した場合)

既定の出力フォルダー:

fiaccel/mex/M_fcn_name/html

生成ファイルの名前と場所を変更するには、fiaccel を実行する際にオプション -o-d を使用します。

この例では、関数 fiaccel を使用し、簡単なアルゴリズムの異なる部分をコンパイルします。この 2 つのケースの実行時間を比較すれば、関数 fiaccel の利点と最適な使用方法を理解できます。

アルゴリズムの異なる部分を高速化する場合の実行時間の比較

この例では、関数 fiaccel を使用して簡単なアルゴリズムの異なる部分をコンパイルする方法を示します。

この例で使用するアルゴリズムは MATLAB 関数 sum の機能を複製したもので、行列の列の和を計算します。

type fi_matrix_column_sum.m
function B = fi_matrix_column_sum(A)
% Sum the columns of matrix A.

% Copyright 2008-2023 The MathWorks, Inc.
%#codegen
    [m,n] = size(A);
    w = get(A,'WordLength') + ceil(log2(m));
    f = get(A,'FractionLength');
    B = fi(zeros(1,n),true,w,f,fimath(A));
    for j = 1:n
        for i = 1:m
            B(j) = B(j) + A(i,j);
        end
    end

試行 1: 最良のパフォーマンス

アルゴリズムの実行速度を上げる最良の方法は、関数 fiaccel を使用してアルゴリズム全体をコンパイルすることです。アルゴリズム全体をコンパイルする場合に、関数 fiaccel によって実現されるパフォーマンスの向上を評価するには、次のコードを実行します。

コードの最初の部分は、MATLAB 関数だけを使用してアルゴリズムを実行します。

fipref('NumericTypeDisplay','short');
A = fi(randn(1000,10));
tic
B = fi_matrix_column_sum(A);
t_matrix_column_sum_m = toc
t_matrix_column_sum_m = 3.8430

コードの 2 番目の部分は、関数 fiaccel を使用してアルゴリズム全体をコンパイルします。MATLAB 関数 tictoc は、それぞれの方法による実行時間を記録します。

fiaccel fi_matrix_column_sum -args {A}
tic
B = fi_matrix_column_sum_mex(A);
t_matrix_column_sum_mex = toc
t_matrix_column_sum_mex = 0.1714

試行 2: 最悪のパフォーマンス

関数 fiaccel を使用して計算の最小ユニットだけをコンパイルすると、実行速度が大幅に低下します。入れ子になっているループ内で関数 mex を呼び出すことで生じるオーバーヘッドのため、MATLAB 関数のみを使用する場合よりも実行速度が低下することもあります。計算の最小ユニットだけをコンパイルする場合の mex 関数のパフォーマンスを評価するには、次のコードを実行します。

コードの最初の部分は、MATLAB 関数だけを使用してアルゴリズムを実行します。

tic
[m,n] = size(A);
w = get(A,'WordLength') + ceil(log2(m));
f = get(A,'FractionLength');
B = fi(zeros(1,n),true,w,f);
for j = 1:n
    for i = 1:m
        B(j) = fi_scalar_sum(B(j),A(i,j));
        % B(j) = B(j) + A(i,j);
    end
end
t_scalar_sum_m = toc
t_scalar_sum_m = 11.0941

コードの 2 番目の部分は関数 fiaccel で計算の最小ユニットをコンパイルし、計算の残りの部分は MATLAB で行います。

fiaccel fi_scalar_sum -args {B(1),A(1,1)}
tic
[m,n] = size(A);
w = get(A,'WordLength') + ceil(log2(m));
f = get(A,'FractionLength');
B = fi(zeros(1,n),true,w,f);
for j = 1:n
    for i = 1:m
        B(j) = fi_scalar_sum_mex(B(j),A(i,j));
        % B(j) = B(j) + A(i,j);
    end
end
t_scalar_sum_mex = toc
t_scalar_sum_mex = 5.4848

実行時間の比率

試行 1 と試行 2 の結果を比較します。使用するコンピューターにより異なる実行時間が記録される場合もありますが、比率はほぼ同じになります。fiaccel を使用してアルゴリズム全体をコンパイルした試行 (t_matrix_column_sum_mex.m) と、スカラーの加算だけをコンパイルした試行 (t_scalar_sum_mex.m) との間では比率に有意差があります。fiaccel でコンパイルしていないファイル (t_matrix_column_sum_m) の方が、fiaccel を使用して計算の最小ユニットだけをコンパイルした場合 (t_scalar_sum_mex) よりもまだ良い結果になっています。

t_scalar_sum_mex/t_matrix_column_sum_mex
ans = 32.0024
t_scalar_sum_mex/t_matrix_column_sum_m
ans = 1.4272
t_matrix_column_sum_m/t_matrix_column_sum_mex
ans = 22.4230
t_scalar_sum_m/t_scalar_sum_mex
ans = 2.0227

試行 1: 最良のパフォーマンス

アルゴリズムの実行速度を上げる最良の方法は、関数 fiaccel を使用してアルゴリズム全体をコンパイルすることです。アルゴリズム全体をコンパイルする場合に、関数 fiaccel によって実現されるパフォーマンスの向上を評価するには、次のコードを実行します。

コードの最初の部分は、MATLAB 関数だけを使用してアルゴリズムを実行します。コードの 2 番目の部分は、関数 fiaccel を使用してアルゴリズム全体をコンパイルします。MATLAB の関数 tictoc は、それぞれの方法による実行時間を記録します。

% MATLAB
fipref('NumericTypeDisplay','short');
A = fi(randn(1000,10));
tic
B = fi_matrix_column_sum(A)
t_matrix_column_sum_m = toc

% fiaccel
fiaccel fi_matrix_column_sum -args {A}
tic
B = fi_matrix_column_sum_mex(A);
t_matrix_column_sum_mex = toc

試行 2: 最悪のパフォーマンス

関数 fiaccel を使用して計算の最小ユニットだけをコンパイルすると、実行速度が大幅に低下します。入れ子になっているループ内で関数 mex を呼び出すことで生じるオーバーヘッドのため、MATLAB 関数のみを使用する場合よりも実行速度が低下することもあります。計算の最小ユニットだけをコンパイルする場合の mex 関数のパフォーマンスを評価するには、次のコードを実行します。

コードの最初の部分は、MATLAB 関数だけを使用してアルゴリズムを実行します。コードの 2 番目の部分は関数 fiaccel で計算の最小ユニットをコンパイルし、計算の残りの部分は MATLAB 関数で行います。

% MATLAB
tic
[m,n] = size(A);
w = get(A,'WordLength') + ceil(log2(m));
f = get(A,'FractionLength');
B = fi(zeros(1,n),true,w,f);
for j = 1:n
    for i = 1:m
        B(j) = fi_scalar_sum(B(j),A(i,j));
        % B(j) = B(j) + A(i,j);
    end
end
t_scalar_sum_m = toc

% fiaccel
fiaccel fi_scalar_sum -args {B(1),A(1,1)}
tic
[m,n] = size(A);
w = get(A,'WordLength') + ceil(log2(m));
f = get(A,'FractionLength');
B = fi(zeros(1,n),true,w,f);
for j = 1:n
    for i = 1:m
        B(j) = fi_scalar_sum_mex(B(j),A(i,j));
        % B(j) = B(j) + A(i,j);
    end
end
t_scalar_sum_mex = toc

実行時間の比率

試行 1 と試行 2 の比較を次の表に示します。使用するコンピューターにより実行時間が表の値と異なる場合もありますが、比率はほぼ同じになります。fiaccel を使用してアルゴリズム全体をコンパイルした試行 (t_matrix_column_sum_mex.m) と、スカラーの加算だけをコンパイルした試行 (t_scalar_sum_mex.m) との間では比率に極端な差があります。fiaccel でコンパイルしていないファイル (t_matrix_column_sum_m) の方が、fiaccel を使用して計算の最小ユニットだけをコンパイルした場合 (t_scalar_sum_mex) よりもまだ良い結果になっています。

X (全体のパフォーマンス ランク)時間X/最良X_m/X_mex
試行 1: 最良のパフォーマンス
t_matrix_column_sum_m (2) 1.9975984.4917 84.4917
t_matrix_column_sum_mex (1)0.02364241
試行 2: 最悪のパフォーマンス
t_scalar_sum_m (4)10.2067 431.71 2.08017
t_scalar_sum_mex (3)4.90664 207.536

fiaccel を使用したデータ型オーバーライド

データ型オーバーライドを有効にするには、reset(fipref) コマンドを実行した後、MATLAB プロンプトで次のコマンドを入力します。

fipref('DataTypeOverride','TrueDoubles')

このコマンドは Fixed-Point Designer™ ソフトウェアにすべての fi オブジェクトを fi double 型で作成するよう指示します。fiaccel コマンドを使用してコードをコンパイルすると、その結果作成される MEX 関数は浮動小数点データを使用します。

MEX 関数に対する既定の fimath 値の指定

fiaccel で生成された MEX 関数では、MATLAB の既定のグローバル fimath が使用されます。MATLAB 出荷時の既定のグローバル fimath には以下のプロパティがあります。

RoundingMethod: Nearest
OverflowAction: Saturate
ProductMode: FullPrecision
SumMode: FullPrecision

MATLAB の既定の fimath 値に依存する MEX 関数を実行しているときは、MATLAB セッション中にこの値を変更しないでください。変更すると、コンパイル時と実行時の fimath の値が一致していないという警告が MATLAB によって生成されます。たとえば、次の MATLAB 関数を作成します。

function y = test %#codegen 
y = fi(0); 
関数 test は、fimath オブジェクトを明示的に指定することなく fi オブジェクトを構築します。したがって、test は、実際にはコンパイル時に既定の fimath オブジェクトに依存することになります。

MEX 関数 test_mex を生成し、MATLAB の既定の fimath の出荷時の設定を使用します。

resetglobalfimath;
fiaccel test 
fiaccel は現在のフォルダーに MEX 関数 test_mex を生成します。

test_mex を実行します。

test_mex   
ans =        
  0            
       DataTypeMode: Fixed-point: binary point scaling            
       Signedness: Signed            
       WordLength: 16        
       FractionLength: 15

MATLAB の既定の fimath 値を変更して、コンパイル時に使用される設定と一致しないようにします。

F = fimath('RoundingMethod','Floor');
globalfimath(F); 

メモリから MEX 関数をクリアして、再度実行します。

clear test_mex 
test_mex
不一致が検出され、MATLAB によって警告が生成されます。
testglobalfimath_mex 
Warning: This function was generated with a 
different default fimath than the current default.
ans =        
   0            
      DataTypeMode: Fixed-point: binary point scaling
      Signedness: Signed             
      WordLength: 16         
      FractionLength: 15
この問題を回避するには、型テーブルを使用してアルゴリズムから fimath プロパティを分離します。詳細は、データ型定義のアルゴリズムからの分離を参照してください。