コンパイルのターゲット
CompileのCompilationTargetオプションはコンパイルされた関数のターゲットのランタイムシステムを指定する.デフォルト設定は"MVM"で,これは従来のWolfram言語仮想マシンのためのコードを作成する.この仮想マシンについてはコンパイルされた関数の操作のセクションで詳述してある.
CompilationTargetを使って次のようなCコードを生成することもできる.
cFun = Compile[{{x}}, x ^ 2 + Sin[x ^ 2], CompilationTarget -> "C"]この関数はWolfram言語の仮想マシンで実行されているコンパイルされた関数と同じように働く.
cFun[10]しかし,InputFormはコンパイルされた関数が実際にはLibraryFunctionを含んでいることを示している.
cFun//InputFormLibraryFunctionを直接呼び出すこともできる.
dFun = Last[cFun];
dFun[10]生成されたコードに外部呼出しの必要がある場合も期待通りの動作をする.
fFun[x_] := x ^ 2;
cFun = Compile[{{x}}, fFun[x], CompilationTarget -> "C"]cFun[10]適切なCコンパイラがない場合はCompilationTargetをCに設定することができないので注意のこと.設定しようとすると警告メッセージが表示される.
計算の高速化
CompilationTargetをCに設定する最大の理由は計算の高速化である.これは多くの場合非常にうまくいく.
次の例はCコードが従来のWolfram言語仮想マシンよりもいかに高速であるかを示している.
cFun = Compile[ {{x, _Real}, {n, _Integer}},
Module[ {sum, inc}, sum = 1.0;inc = 1.0;Do[inc = inc * x / i;sum = sum + inc, {i, n}];sum], CompilationTarget -> "C"];
cFun[1.5, 10000000]//AbsoluteTimingcNormal = Compile[ {{x, _Real}, {n, _Integer}},
Module[ {sum, inc}, sum = 1.0;inc = 1.0;Do[inc = inc * x / i;sum = sum + inc, {i, n}];sum]];
cNormal[1.5, 10000000]//AbsoluteTiming常にかなりの高速化がはかれる訳ではない.行列かける行列のように費用がかかる内部関数が呼ばれた場合は,CでもWolfram言語仮想マシンでもかかる時間はあまり変わらないであろうから,このような場合は高速化による恩恵はないことになる.
従来のコンパイルされた関数の実行の際のように,Wolframシステムコンパイラを使用している際の外部呼出しもまた効率を下げることがある.特に,未定義の外部呼出しは避けるべきである.
上記以外で影響がある事柄にCatchMachineOverflow,CatchMachineIntegerOverflow等のRuntimeOptionsの使用が挙げられる.先に説明したように,これらは皆コンパイルされた関数の効率に影響する.
ListabilityとParallelization
Cの実行に併せてCompileにListabilityとParallelizationをセットで設定することができる.
cUL1 = Compile[{{x}},
Module[{sum = 1.0, inc = 1.0}, Do[inc = inc * x / i;sum = sum + inc, {i, 10000}];sum],
RuntimeAttributes -> {Listable}];
arg = Range[ -50., 50, 0.02];
cUL1[arg];//AbsoluteTiming同じ関数でCをターゲットとするなら,かなりな程度の高速化になる.
cCL1 = Compile[{{x}},
Module[{sum = 1.0, inc = 1.0}, Do[inc = inc * x / i;sum = sum + inc, {i, 10000}];sum],
RuntimeAttributes -> {Listable}, CompilationTarget -> "C"];
arg = Range[ -50., 50, 0.02];
cCL1[arg];//AbsoluteTimingcCP1 = Compile[{{x}},
Module[{sum = 1.0, inc = 1.0}, Do[inc = inc * x / i;sum = sum + inc, {i, 10000}];sum],
RuntimeAttributes -> {Listable}, Parallelization -> True, CompilationTarget -> "C"];
arg = Range[ -50., 50, 0.02];
cCP1[arg];//AbsoluteTiming最後はWolfram言語関数を使った計算で最速の方法の1つの例である.
ライフサイクル
CompilationTargetがCに設定されると, LibraryFunctionが作られ,これがコンパイルされた関数に埋め込まれる.InputFormを使ってLibraryFunctionを見ることができる.
cFun = Compile[{{x}}, x ^ 2, CompilationTarget -> "C"];
cFun//InputFormこの変換は,CCodeGeneratorパッケージを使ってWolframライブラリのためのCコードを生成し,次に(CreateLibraryを使って) CCompilerDriverパッケージを使いコードを実際のライブラリにコンパイルする.ライブラリはすべて各Wolframシステムセッションで一意的な一つのフォルダに置かれる.
デフォルト設定は,コンパイルが終了したときに一時的なファイルすべてを削除する設定になっている.さらに,カーネルセッションが終了すると,生成されたライブラリはすべて削除される.
CreateLibraryへの呼出しのオプション設定を変更したい場合は,Compile`$CCompilerOptionsを使ってこれを行うことができる.これは,生成されたコードを検査したりデバッグしたりする等のさまざまな理由のために役立つ.
生成されたコードの検査
生成されたコードを検査するためには,CreateLibraryのデフォルト動作を変更する必要がある.これによって生成された中間ファイルはすべて削除され,"CleanIntermediate"オプションによって制御される.変更は以下下のようになる.
Compiler`$CCompilerOptions = {"CleanIntermediate" -> False};これでCompilationTargetをCに設定することによってコンパイルされた関数を生成できるようになる.
cFun = Compile[{{x}}, x ^ 2, CompilationTarget -> "C"];
cFun//InputFormFileNames["*.c", FileNameJoin[{FileNameDrop[Part[cFun, -1, 1], -1], "Working"}]]Cコードを表示する.これらの項目の意味はCCodeGeneratorのドキュメントに記載されている.
FilePrint /@ %中間ファイルが削除されないようにすると,Wolframシステムセッションが終了したときに,生成されたコードのフォルダが整理されることを妨げる.この時点で,ファイルを自分で削除した方がよいこともある.
コードを生成する際の出力
コードを生成しているときに,Cコンパイラからの出力を見るには, CreateLibraryにオプションを加えなければならない.これは,"ShellOutputFunction"をPrintに設定することで行うことができ,以下にその例を示す.
Compiler`$CCompilerOptions = {"ShellOutputFunction" -> Print};これでCコンパイラが実行されるときに出力が見えるようになった.
cFun = Compile[{{x}}, x ^ 2, CompilationTarget -> "C"];コードを生成する際のCコンパイラのコマンド
コードを生成しているときにCコンパイラに与えられるコマンドを見るためには,CreateLibraryにオプションを加える必要がある.これは,"ShellCommandFunction"をPrintに設定することで行うことができ,以下にその例を示す.
Compiler`$CCompilerOptions = {"ShellCommandFunction" -> Print};これでCコンパイラを実行するために与えられるコマンドを見ることができるようになった.
cFun = Compile[{{x}}, x ^ 2, CompilationTarget -> "C"];生成されたコードのデバッグ
生成されたコードをデバッグするためには,デバックのオプションをCreateLibraryに加える必要がある.これらは,Cコンパイラの種類によって異なる.Visual Studioについては,以下のように設定することができる.
Compiler`$CCompilerOptions = {"CleanIntermediate" -> False, "CompileOptions" -> "/Zi"};中間ファイルが保存されるように,"CleanIntermediate"をFalseに設定しなければならない.またデバッグの情報が結果のライブラリに挿入されるように"CompileOptions"を設定する必要がある.
これでデバッグ環境を起動し,Wolframシステムプロセスに接続できるようになったはずである.その後Cコードを開き,ブレイクポイントを設定することができる.