APIトレーシングへの応用

API記述の重要なユースケースAPIトレーサの生成と言える。API記述というと、BridgesupportやIDLのように言語ブリッジとしての役割が主に注目されるが(ucidも本来はそちらが基本的なユースケースだが)、C/C++しか使用しないようなpure native環境でも価値があるという点で営業的に重要なユースケースとなっている。

APIトレースの実例

APIトレースは、APIの呼び出しパラメタと呼び出し結果を保存することと言える。既に様々な種類のAPIトレーサが作られ、使用されている。
たとえば、apitrace( http://apitrace.github.io/ )は、OpenGL/DirectX呼び出しを保存して後にリプレイすることができる。ゲームロジックと切り離して描画callだけを再生できるので、OpenGL実装のデバッグなどに威力を発揮する。
apitraceの場合は、OpenGLAPI記述からトレーサを生成している:

ただし、最新の.xmlではなく、従来の.specファイルを使用している。API記述は一旦pythonスクリプトに変換され、更にトレース用のコードが生成される。
API Monitor( http://www.rohitab.com/apimonitor )は、強力なWin32 APIモニタで、XMLAPI記述を元にかなりの量のWin32 API呼び出しをトレースすることができる。また、API Monitorはenum等もシンボルにデコードすることが出来る。
apitraceもAPI Monitorも、実際のAPIトレースのためのルールは分離して持つデザインとしている。apitraceは生成されたソースコードコンパイルしてしまうのでエンドユーザが定義を追加するチャンスは無いが、API MonitorはXMLでユーザが拡張することができる。代わりに、apitraceは目的に特化しているためリプレイのような高度な解析テクニックを提供している。API MonitorもAPI呼び出し条件ブレークなどの強力な解析ツールは備えているが、リプレイに使えるほどrobustではない。

API記述から生成できるもの

APIトレースのために必要なのは、APIのパラメタをシリアライズするためのコードで、これはAPI記述が(FFIライブラリの生成のために必要十分な機能を備えてれば)自然に実現できるものといえる。
APIはバッファや構造体のようなデータを受け取ることもあるため、バッファを"回収"するためのコードも必要となる。バッファを回収するためにはパラメタとして渡した構造体の先を読む必要が有るかもしれないし、リンクリストを辿らないといけないかもしれない。
... というわけで、その手のコードを手で書くのは非常に辛いのでAPI記述からこの手のコードを生成できることには大いに価値がある。

ランタイム(= API記述から生成できないもの)

寧ろ興味深いのは、API記述から生成できないランタイム部分、つまり、APIに対するhookのインストールやトレースデータの書き出し部分だろう。APIトレースのユースケースの殆どはパフォーマンスへの影響を必要最低限に保つ必要がある。probe効果が大きいと、トレース元のアプリケーションが動作しなくなるかもしれない。
APIに対するhookはあまりトピックがない。最近のアプリケーションは大抵共有ライブラリを使用して構築されるので、LD_PRELOADなりproxy DLLを読ませるなどの方法で幾らでもhookが出来る。
トレースデータの処理は興味深い問題と言える。一般に、この手のトレース機構はプロデューサ/コンシューマモデルでデザインされ、ログへの書き出しは別プロセスや別スレッドに負担させることが多い。I/Oは非常にコストの掛かる処理であり、往々にして実際のトレースよりも負荷が高い。
DTraceやSystemTapのようなOSのカーネルトレースでは、この辺に関してそれなりの考察が成されている。例えば、LTTngでは

パフォーマンス面では、実はカーネルトレースよりもユーザランドのトレースの方が難易度が高い。
カーネル内ではプリエンプトを禁止することができるので、per-CPUバッファに対してトレースすれば書き込みの衝突が起こらないことを簡単に保証でき、キャッシュローカリティの面でも有利となる。
ユーザランドをトレースする場合はプリエンプトの禁止ができず、しかもper-ThreadのバッファにするにしてもTLS変数へのアクセスは地味に遅かったりして効率的な記録手段を用意することから難しい。lttngのUSTはそれなりに熱心にこの辺の考察をしている(userspace RCUとshared memoryで実現される高速なringbufferの実装を持つ)が、この辺をどこまで努力するべきなのかはなんとも言えない。