XenLASY: XenのI/O処理を 追跡するための アスペクト指向プロファイラ 柳澤 佳里 光来 健一 千葉 滋 東京工業大学 情報理工学研究科
VMを考慮したチューニングを支援するツール OS単体でのチューニングでは不十分 I/Oがドメイン0を通る 複数のVMのI/Oが競合 例) XenのI/O処理 OS ドメインU ドメイン0 仮想マシンモニタ (VMM) 仮想ドライバ 実ドライバ ハードウェア
I/Oフローの追跡が大切 I/Oフローとは 個別のデータの動き (フロー) の追跡が必要 I/Oを発行してデバイスが送出する流れ デバイスで受信しアプリケーションが受け取る流れ 個別のデータの動き (フロー) の追跡が必要 データがドメインUやドメイン0でどう処理されるかを知りたい 複数のドメインがI/Oした場合に、区別して追跡したい 余計なフローは取りたくない 個々のフローはフロー識別子 (ID) が必要 一つ一つのデータの流れを区別するため
単純なフロー追跡では不十分 コールフロー 単純なデータフロー 関数呼び出しの流れを追跡 実行スレッドが変わると追跡不可 ドメイン間の追跡が不可能 トップハーフ / ボトムハーフの追跡が不可能 単純なデータフロー データのポインタを追跡 データ形式が変化すると追跡不可 ドメイン間ではデータ形式が変化し、追跡不可 データの複製、分割すると追跡不可
XenLASY Xen上のI/O処理をプロファイリングをするための アスペクト指向システム xflowポイントカット 指定した種類のフローに指定したデータが入っている時を選択 文法: xflow(フロー名, データへのポインタ) 追跡すべきデータの流れをきめ細かく指定可能 開始点、中継点、終了点を指定 データ形式の変化、分割などにも対処 余計なデータが含まれないようにできる xflow_idポイントカットでフローIDを取得 ポイントカットとは?一言軽く言う
KLASY を拡張して開発 KLASY [Yanagisawa ’06] とは、 xflow、xflow_idを扱えるよう言語拡張 カーネル用動的アスペクト指向システム ソースコードレベルの情報を実行時の織り込みで利用 accessポイントカットを実現 構造体メンバーへのアクセスをポイントカット Source-based binary-level dynamic weaving xflow、xflow_idを扱えるよう言語拡張 @ドメイン名を使えるよう言語拡張 Xen上のドメインに織り込めるよう変更
XenLASYのアスペクト例 accessポイントカットで選択 <aspect> データフロー (netflow) br_forward SkGeXmit Tcp_sendmsg Network_start_xmit Netif_rx Netif_receive_skb Netbk_fill_flags copy_from_user DomainU Domain0 accessポイントカットで選択 データフロー (netflow) id1 id2 <aspect> <advice> ポイントカット <pointcut> access(sk_buff.%) AND target(skb) AND xflow(netflow, skb) AND xflow_id(id) </pointcut> sk_buff構造体インスタンスが netflowのデータだった場合に pc、時間、フローidをログ出力 netflow: ネットワークI/Oの フロー <before> long long tsc; DO_RDTSC(tsc); STORE_DATA3($pc$, tsc, id); </before> </advice> </aspect> アドバイス
xflowポイントカットの定義 netflow start: 開始点 transit: 中継点 quit: 終了点 Xen上のネットワークI/O処理フロー start: 開始点 データフローの開始点を指定 transit: 中継点 データ形式が変わる場合 skb_cloneは複製を作成 ドメイン間の場合 quit: 終了点 <xflow name=“netflow”> <start><pointcut> access(sk_buff.data) AND within_function(alloc_skb_from_cache) </pointcut></start> <transit><pointcut> access(sk_buff.head) AND within_function(skb_clone) </pointcut> <move from=“skb” to=“n” /> </transit> ここでは、どういう関数でskbuffを出発としているか話す。 詳細(どのメンバー)かは話さない <quit><pointcut> access(sk_buff.%) AND within_function(__kfree_skb) </pointcut></quit> </xflow>
start/quit (開始点/終了点) 構造体インスタンスからIDを引けるよう登録、削除 構造体インスタンスの指定 省略時はaccessポイントカットで選択した構造体のインスタンスを選択 selectで任意の変数も指定可 DB登録/削除処理は自動で設定 任意のコードを指定する場合はactionを利用 <start><pointcut> access(sk_buff.data) AND within_function(alloc_skb_from_cache) </pointcut></start> そのほかの記述例 <start><pointcut>…</pointcut> <select local_var=“data” /> </start> <start><pointcut>…</pointcut> <action> int id = new_flowid(); … </action> </start>
transit (中継点) moveで対応付けを指示 エントリを保持するcopyも用意 skb: フローID格納元 n: フローID格納先 <transit><pointcut> access(sk_buff.head) AND within_function(skb_clone) </pointcut> <move from=“skb” to=“n” /> </transit> そのほかの記述例 <transit><pointcut> … </pointcut> <copy from=“skb” to=“n” /> </transit>
ドメインをまたがるtransit定義 xin_move、xout_move要素を用意 ドメインをまたがるとデータのアドレスからフローIDを引けない ドメイン間ではアドレス空間が違う ドメイン間ではデータベースを共有していない フローIDを送信先ドメインに伝搬 ドメイン間で渡されるヘッダの空き領域にIDを格納 ヘッダ ドメイン0 DomU フローIDを格納 実データ
ドメイン間transitの例 linUからlin0にフローIDを伝搬 xin_move xout_move skbのフローIDをtxに格納 flagsメンバーの下位4ビット目から12ビットを使用 xout_move xin_moveの逆処理でフローIDを取得し、skbに割当 対象xin_moveはnameで選択 @ドメイン名で選択するドメインを指定 <transit><pointcut> access(netif_tx_request.flags) AND within_file(drivers/../netfront.c@linU) </pointcut> <xin_move name=“netin” from=“skb” to=“tx”> <field name=“flags” offset=“4” size=“12” /> </xin_move> </transit> <transit><pointcut> access(netif_tx_request.flags) AND within_file(drivers/../netback.c@lin0) </pointcut> <xout_move name=“netin” from=”tx” to=“skb” /> </transit> @domainはインライン (@domUで…と話す) tx->flags 12bit 4bit
xflowの実装: start/quitの変換 <start><pointcut> access(sk_buff.data) AND within_function(alloc_skb_from_cache) </pointcut></start> targetポイントカットを追加 構造体インスタンスへの参照を取得 <pointcut> access(sk_buff.data) AND target(skb) AND within_function(alloc_skb_from_cache) </pointcut> <before> id = get_new_flowid(); register_flowid(netflow, id, skb); </before> DBに参照を鍵としてIDを取り出せるよう登録 こういうポイントカットとアドバイスに変換されます alloc_skb_from_cacheでskbから新規フローIDを引けるようDBに登録 quitも同様
xflowの実装: transitの変換 local_varポイントカットでローカル変数への参照取得 <transit><pointcut> access(sk_buff.head) AND within_function(skb_clone) </pointcut> <move from=“skb” to=“n” /> </transit> <pointcut> access(sk_buff.head) AND within_function(skb_clone) AND local_var(skb, skbp) AND local_var(n, np) </pointcut> <before> void *skb = *((void **)skbp); void *n = *((void **)np); int id = get_flowid(netflow, skb); if (id != 0) { register_flowid(netflow, id, n); remove_flowid(netflow, skb);} </before> もともとのtransit、startの文法よりはこれで何をやっていたか大雑把に フローIDの操作を中心に local_varポイントカットでローカル変数への参照取得 skbに割り当てられていたフローIDをnに割り当てる
xflowの実装: ドメイン間transitの変換 <transit><pointcut> access(netif_tx_request.flags) AND within_file(drivers/../netfront.c@linU) </pointcut> <xin_move name=“netin” from=“skb” to=“tx” /> <field name=“flags” offset=“4” size=“12” /> </xin_move> </transit> <pointcut> access(netif_tx_request.flags) AND within_file(drivers/.../netfront.c@linU) AND local_var(tx, txp) AND local_var(skb, skbp) </pointcut> <after> struct netif_tx_request *tx = txp; void *skb = *((void **)skbp); id = get_flowid(skb); if (id != 0) { tx->flags |= id << 4; id >>= 12; } remove_flowid(netflow, skb); </after> ポインタに対応づけられたフローIDをヘッダに格納 local_varポイントカットでローカル変数への参照取得 XenのネットワークI/OはドメインUでnetif_tx_request構造体にヘッダを格納 送信先でフローIDを 受け取るコードは割愛
実装: KerninstのXen対応 アスペクトの織り込みにKerninst [Tamches ’99]を使用 割り込みテーブル読み込みを除去 ブレークポイントトラップ処理関数をエクスポートし、Kerninstから直接参照 割り込みテーブル読み込みは特権命令 ドメインUやドメイン0から読み込めない 特権レベル判定を変更 Xen上ドメインでの実行に対応 Kerninstはring0でカーネルが動作していると仮定
マイクロベンチマーク 結果 目的 実験方法 実験環境 xflowのバックエンド関数の オーバーヘッドを調査 各関数を2000回呼び出し、平均を計算 実験環境 CPU: AMD Athlon™ 64 3500+ メモリー: 2GB ドメイン0: 256MB ドメインU: 128MB ドメイン0で実施 関数名 実行時間(ナノ秒) get_new_flowid 3 ± 0.0 空要素 get_flowid 9 ± 0.0 register_flowid 33 ± 4.0 get_flowid 15 ± 1.0 remove_flowid 32 ± 2.0 時間が押していると大まかに説明 バックエンド関数のオーバーヘッドは低い
ネットワークI/Oのボトルネックの調査 目的 xflowを用いて、ドメインUからドメイン0までのデータフローを調査 sk_buff構造体のメンバーにアクセスがあった箇所でフローIDを取得し、時間とともに記録 例に出したアスペクトを使用
実験結果 処理の流れがわかった ボトルネックはドメイン0の内部 ボトムハーフ → トップハーフのところ skb_clone関数でできた複製も追跡可能 TCP再送処理のためにTCP層で実行され、ドライバーは複製を利用 ボトルネックはドメイン0の内部 ボトムハーフ → トップハーフのところ netif_receive_skbはトップハーフの処理割り当て関数 FreeTxDescriptors network_start_xmit tcp_sendmsg netif_rx __br_forward netif_receive_skb alloc_skb_from_cache netbk_fill_flags SkGeXmit
xflowによるオーバーヘッドの削減 目的 方法 結果 xflowを使うことでプロファイルのオーバーヘッドを削減できるか調査 ApacheBenchを300リクエスト、10並列で実行 結果 メモリー使用量 ドメイン0 ドメインU 性能(req/s) xflowあり 1.6MB 10.6MB 382 xflowなし 13.6MB 15.7MB 約60%のメモリーを削減
関連研究 Dflow pointcut [Masuhara ’03] データの流れを選択するポイントカット 自動的にデータを追うのでデフォルトでは追跡しすぎる コンパイル時にdflowのためのコードを織り込み DJcutter [Nishizawa ’04]、DAC++ [Almajali ’05] 分散環境に対応したアスペクト指向システム ユーザーランドのアプリケーションを対象とする Causeway [Chanda ’05] メタデータを伝搬させ処理の流れを追跡 FreeBSDのネットワークI/Oコードを改造して実装
まとめ XenLASYを提案 ケーススタディ xflowポイントカットを提供 複数ドメインに自動でアスペクトを織り込み データフロー追跡をアスペクトとして容易に記述可能 複数ドメインに自動でアスペクトを織り込み KLASYを拡張した動的アスペクト指向システム ケーススタディ ネットワークI/Oのボトルネックがドメイン0の処理にあることを発見 フロー追跡機能により調査に必要なメモリー使用量の削減を確認
今後の課題 データフロー分割時のフローIDの割り当て方 ヘッダに空き領域がない場合に対応 例) TCPにおけるフラグメント処理