MATLAB Coder(3)

MATLAB Coder(2)からの続きです。今回は、MEX化にチャレンジです。

とは言え、本当にコレってうれしいのかなー?という気持ちはあります。

ちょっと高速化したいとか、mファイルの中身を隠したいという方は、まずpcodeコマンドにチャレンジすると幸せになれるかも、です。

pcode  mファイル名.m

とすると、 .p ファイルが出来ます。コレだけ配布しても動作するのと、ほんのちょっぴり高速化される(かも)なので、これで満足できるならこれで終了です。

そうではなくて、

・ものすごく高速化したい!
MATLAB Coder(2)のための中間ステップとして、MEX化したい

というのであれば、MATLAB CoderによるMEX化にチャレンジする価値がありそうです。

MEXの仕組み

そもそもMEXって何だっけ?という方のために、ざっくりと説明させていただきます。すでにご存知の方はスキップしてください。

ここでMEXと呼んでいるものは、MATLABから呼び出せるDLLの事を言っています。拡張子はmexw32, mexw64 などになっていますが、中身は単なるDLLです。(Dependency Walkerなどで見てみると良く分かります。)

MEX関数は単なるDLL

このDLLの中にmexFunctionという関数が存在していて、MATLABはこれを呼び出しに行きます。結果として、MATLABからCコードで書いたロジックを実行する事ができます。

ただし、MATLAB変数とC言語の変数とには厳密な互換性がありません。そこで、「MATLAB変数を取り扱うための特殊なAPI」が用意されていて、これにアクセスします。

MATLAB変数を取り扱うAPIがある

具体的にどんなAPIなのかは、マニュアルのMATLAB>ユーザーガイド>C/C++ and Fortran API Reference>MX Matrix Libraryを見てみてください。

その結果、「Cコードがコンパイルされてそのまま動くんだから、高速動作するんじゃないの?」という期待が生まれます。

余談ですが、S-Functionをコンパイルしたときに生成されるmexw32, mexw64もコレと同じです。やっぱりmexFunction関数がエクスポートされています。S-Functionの場合は、mexFunctionが呼び出された後でmdlOutputs関数などへの呼び出しが行われますが、そのあたりは巧妙に隠してくれているため、ユーザーは気にしなくても良いようになっています。

MEX化の概要

MEX化すると、Mファイルから生成されるCコードと、ラッパー部分とが生成されます。アルゴリズム部分は、基本的に純粋なCコードで出来ています。一方、「MEXとしてのラッパー部分」には、上述の「MATLAB変数の読み書きAPI」が書き込まれていて、MATLABとCコードとの橋渡しをしてくれています。

MEXとしてのラッパー部分についてはMATLAB Coderがうまいこと生成してくれますので、問題はアルゴリズムの部分だけです。ここは、なんとかかんとかM-FileからCコードに変換しないといけません。

MATLAB Coder(2)にて、2つの課題が存在すると書きました。

問題(1)セル配列やTry/Catch構文など、コード生成できないロジックが存在する

問題(2)呼び出しているMATLAB関数が、コード生成に対応していない

このうち、問題(1)については、個別に対応していくしかありません。一方、問題(2)についてはMEXならではの逃げ道があります。

コード生成に対応していないMATLAB関数の呼び出し

m-file中に、こう書くだけでOKです。

coder.extrinsic(‘関数名’);

たとえば、Simulink中のブロックを表示するコードは、次のようになります。

これをMEX化して実行すると、こうなります。(操作方法は、だいたいMATLAB Coderに書いてあるようなかんじです)

こういうSimulinkモデルを開いておくと

codetest_mexコマンドを実行したときに、こう表示される

まぁこれだけの話で、生成されたCコードを見てみると、こういう振る舞いになっています。

disp, find_system, gcs などの関数が自動生成されて呼び出される

自動生成された、disp関数

要するに、「アルゴリズム部分は純粋なCコード」という原則を破って、MATLABコマンドをたたきにいくようなCコードが自動生成されるわけです。

自動生成されたdisp関数から、MATLAB中のdisp関数の実体を呼び出す

そりゃあ、動きますよね。

高速化が目的でMEX化している場合、「呼び出しているMATLABコマンドがパフォーマンス上のボトルネックではない」のであれば、これで十分です。coder.extrinsic って書くだけですからね。

ハードウェア化が最終目的で、その手前のステップとしてMEX化している場合にも便利です。一度に大改造するのは大変ですから、「とりあえずcoder.extrinsicを使って逃げておいて、1つ1つCコードに置き換えていく」というステップを踏むだけで、随分と作業がラクになるはずです。(私が仕事としてやるなら、間違いなくこうやって安全なステップを踏んで進めていきます)

まとめ

とりあえず、MATLAB Coderを使ってコード生成し、動かしていくところの話はこれで終了です。

m-fileからCコードに変換する際、いちばん大変なのは「何でも入れられる変数であるMATLAB変数」から、「厳密に型が決まっているC変数」への変換です。この作業は、MATLAB Coderが本当にうまくやってくれています。

あとは、m-file → Cコード という変換作業によって、どんなユーザーメリットが生まれるのか?という点ですが、アルゴリズムのハードウェア化や、MEX高速化に対して、どれほどの需要があるのかイマイチ分かりません。Simulinkをガリガリ使ってらっしゃる部署よりも、MATLABを主に使ってらっしゃる所のほうが需要がありそうな気がしますが、どうなんでしょうねぇ。