OSカーネル用 アスペクト指向システム KLASY 柳澤 佳里 光来 健一 千葉 滋 石川 零 東京工業大学 情報理工学研究科 数理・計算科学専攻 1 プロファイリングコードを 実行中のカーネルに挿入するには? 目的: 任意の点でタイムスタンプをロギング 性能チューニングのため 例) パケット到達からカーネルバッファにいたるまでの 経過時間を調査 既存の方法 カーネルプロファイラを利用? 決まった点でしかログを取得できない カーネルソースコードを変更し、再コンパイル? 面倒くさくて、ミスしがち 2 プロファイリングコード Linux カーネルソースコード (fs/attr.c) int inode_change_ok(…) { … if ((ia_valid & ATTR_UID) && … attr->ia_uid != inode->i_uid) … goto error; 挿入 if ((ia_valid & ATTR_GID) && … } ソースコードの指定した行にて 変数の値とタイムスタンプを 記録 再コンパイル、再起動 無しでプロファイリングしたい プロファイリングコード struct timeval tv; do_gettimeofday(&tv) ; print_tv(tv); printk(“%ld”, inode->i_uid); 3 Kerninst [Tamches et al. ’99] 実行時コード操作ツール アセンブリレベルの抽象度 開発者は次のアドレスの調査が必要: コードを挿入する機械語のアドレス 記録する変数が格納された場所のアドレス サンプルコード: Kerninst を用いてログを取得 kmgr.findModule(“kernel”, &kmod); kmod.findFuction(“inode_change_ok”, &ifunc);{ void print_log() ifunc.findEntryPoint(&entries); … kmgr.findModule(“profiler”, &kmod); __asm__ (“movl %%ebp, %0” : “=r”(ebp)); kmod.findFunction(“print_log”, &pf); uid = ((struct inode*)ebp[11])->i_uid; hook = kapi_call_expr(pf.getEntryAddr(), /* ebp[11]args); is inode */ … kmgr.insertSnippet(hook, entries[0]); 4 KLASY Kernel-level Aspect-Oriented System ソースコードレベルの抽象度 アスペクト指向プログラミング(AOP)を用いた利点 KLASYにより開発者は: ソースコードレベルの視点で任意の実行点を選択可能 ポイントカット C言語でプロファイリングコードを記述可能 アドバイス 選択された点で実行されるコード 実行点で利用可能な変数にアクセス可能 5 ロギング AOPのキラーアプリケーション ロギング(or プロファイリング)コードは独立した別個の モジュールに分離 なぜ新しいAOPシステムが必要か? 既存のC言語用動的AOPシステムの問題 実行時コンテキストの取得が不可能: 変数アクセスができない 構造体メンバーアクセスのポイントカットが不可能 たとえば、inode->i_uidがアップデートされたときのタイムスタンプ を調査不可能 プロファイリングに不可欠 6 KLASYのアスペクト例 アスペクト Linux カーネルコード (fs/attr.c) <aspect> int inode_change_ok(…) <import>linux/time.h</import> { … pointcut <advice><pointcut> if ((ia_valid & ATTR_UID) && … access(inode.i_uid) AND attr->ia_uid != inode->i_uid) … within_function(inode_change_ok) goto error; 選択 AND target(inode_value) </pointcut> if ((ia_valid & ATTR_GID) && advice <before> … struct inode *i = inode_value; } struct timeval tv; do_gettimeofday(&tv); print(i->i_uid, tv.tv_sec, tv.tv_usec); </before> </advice> </aspect> 7 KLASYのアスペクト例 アスペクト Linux カーネルコード (fs/attr.c) アドバイスボディで使う int inode_change_ok(…) ヘッダーファイルを指定 <aspect> <import>linux/time.h</import> { … pointcut <advice><pointcut> if ((ia_valid & ATTR_UID) && … access(inode.i_uid) AND attr->ia_uid != inode->i_uid) … within_function(inode_change_ok) goto error; 選択 AND target(inode_value) </pointcut> if ((ia_valid & ATTR_GID) && advice <before> … struct inode *i = inode_value; } struct timeval tv; do_gettimeofday(&tv); print(i->i_uid, tv.tv_sec, tv.tv_usec); </before> </advice> </aspect> 8 KLASYのアスペクト例 アスペクト Linux カーネルコード (fs/attr.c) <aspect> int inode_change_ok(…) <import>linux/time.h</import> { … pointcut <advice><pointcut> if ((ia_valid & ATTR_UID) && … access(inode.i_uid) AND attr->ia_uid != inode->i_uid) … within_function(inode_change_ok) goto error; 選択 AND target(inode_value) </pointcut> if ((ia_valid & ATTR_GID) && advice <before> … struct inode *i = inode_value; } struct timeval tv; do_gettimeofday(&tv); print(i->i_uid, tv.tv_sec, tv.tv_usec); </before> </advice> </aspect> 9 KLASYのアスペクト例 アスペクト Linux カーネルコード (fs/attr.c) <aspect> int inode_change_ok(…) <import>linux/time.h</import> { … pointcut <advice><pointcut> if ((ia_valid & ATTR_UID) && … access(inode.i_uid) AND attr->ia_uid != inode->i_uid) … within_function(inode_change_ok) goto error; 選択 AND target(inode_value) </pointcut> if ((ia_valid & ATTR_GID) && advice <before> … struct inode *i = inode_value; } struct timeval tv; do_gettimeofday(&tv); print(i->i_uid, tv.tv_sec, tv.tv_usec); </before> access(inode.i_uid) ポイントカットで </advice> inode->i_uid を選択 </aspect> 10 KLASYのアスペクト例 アスペクト Linux カーネルコード (fs/attr.c) <aspect> int inode_change_ok(…) <import>linux/time.h</import> { … pointcut <advice><pointcut> if ((ia_valid & ATTR_UID) && … access(inode.i_uid) AND attr->ia_uid != inode->i_uid) … within_function(inode_change_ok) goto error; 選択 AND target(inode_value) </pointcut> if ((ia_valid & ATTR_GID) && advice <before> … struct inode *i = inode_value; } struct timeval tv; do_gettimeofday(&tv); within_function() により選択範囲を print(i->i_uid, tv.tv_sec, tv.tv_usec); inode_change_ok関数内に制限。 </before> </advice> </aspect> 11 KLASYのアスペクト例 アスペクト Linux カーネルコード (fs/attr.c) <aspect> int inode_change_ok(…) <import>linux/time.h</import> { … pointcut <advice><pointcut> if ((ia_valid & ATTR_UID) && … access(inode.i_uid) AND attr->ia_uid != inode->i_uid) … within_function(inode_change_ok) goto error; 選択 AND target(inode_value) </pointcut> if ((ia_valid & ATTR_GID) && advice <before> … 実行時コンテキスト取得: struct inode *i = inode_value; } inode_valueに選択した struct timeval tv; 構造体(inode)への参照を do_gettimeofday(&tv); print(i->i_uid, tv.tv_sec, tv.tv_usec); 設定 </before> </advice> </aspect> 12 KLASYのアスペクト例 アスペクト Linux カーネルコード (fs/attr.c) <aspect> int inode_change_ok(…) <import>linux/time.h</import> { … pointcut <advice><pointcut> if ((ia_valid & ATTR_UID) && … access(inode.i_uid) AND attr->ia_uid != inode->i_uid) … within_function(inode_change_ok) goto error; 選択 AND target(inode_value) </pointcut> if ((ia_valid & ATTR_GID) && advice <before> … struct inode *i = inode_value; } struct timeval tv; タイムスタンプを取得し、 do_gettimeofday(&tv); i_uidの値とともに保存 print(i->i_uid, tv.tv_sec, tv.tv_usec); </before> </advice> </aspect> 13 KLASYの対応する 主なポイントカット、アドバイス ポイントカット access execution 本研究で提案 構造体メンバーアクセスを選択 関数実行を選択 アドバイス before 選択された点の前でプロファイリングコードを実行 after 選択された点の後でプロファイリングコードを実行 14 実行時コンテキストの取得に使う ポイントカット ポイントカット記述子 target local_var accessポイントカットで選択したメンバーを持つ構造体変数への参 照を取得 accessポイントカットで選択した箇所でローカル変数への参照を取 得 argument executionポイントカットで選択した関数の引数への 参照を取得 15 KLASYの実装 Source-based binary-level dynamic weaving GNU C コンパイラ(gcc)を拡張 生成した拡張シンボル情報を用い: Kerninstをバックエンドに利用 構造体メンバーへのアクセスをポイントカット可能 実行時コンテキスト(変数のアドレス)を取得可能 動的織り込みを実現 C言語でアドバイスを記述 ソースレベルの視点で記述可能 XML風のタグで囲まれている 16 処理の流れ OS ソースコード アスペクト アスペクトコンパイラー 拡張シンボル情 報 KLASY gcc ポイントカット insmod OSカーネル コンパイル済み アドバイス ウィーバー OS カーネル フック 本体 17 処理の流れ OS ソースコード アスペクト アスペクトコンパイラー 拡張シンボル情 報 KLASY gcc ポイントカット insmod OSカーネル コンパイル済み アドバイス ウィーバー OS カーネル フック 本体 18 KLASY gcc KLASY gccは次のシンボル情報を収集: 構造体メンバーアクセスのあるファイル名、行番号 コンパイラーのパーザーを拡張 従来のgccではこの情報は消失 各行の先頭命令のあるアドレス コンパイル時にデバッグオプション(-g)を利用 構造体メンバーアクセスのポイントカットにこれも必要 19 処理の流れ OS ソースコード アスペクト アスペクトコンパイラー 拡張シンボル情 報 KLASY gcc ポイントカット insmod OSカーネル コンパイル済み アドバイス ウィーバー OS カーネル フック 本体 20 ウィーバー Kerninstを用いポイントカットで選択した点に フック挿入 フック アドバイスボディを呼び出すためのコード フック挿入アドレスの取得方法 構造体メンバーアクセス ファイル名、行番号 行の先頭アドレス 拡張シンボル情 報を利用 21 アンウィーブ KLASYでは実行時にOSカーネルから織り込んだ アスペクトを削除可能 プロファイリングには重要な機能 一般に利用者は様々なアスペクトを試用 観察効果を避けるため不要なアスペクトの削除は必要 利用者はわかりやすい名前でアスペクトを指定可能 Kerninstを用いてウィーバーの入れたフックを消去 22 アスペクト例における 実行時コンテキストの取得 アスペクト Linux カーネルソースコード (fs/attr.c) <aspect> int inode_change_ok(…) <import>linux/time.h</import> { <advice><pointcut> ポイントカット … if ((ia_valid & ATTR_UID) && … access(inode.i_uid) AND attr->ia_uid != inode->i_uid) … within_function(inode_change_ok) goto error; AND target(inode_value) selected </pointcut> if ((ia_valid & ATTR_GID) && ローカル変数を取得し、 アドバイス <before> … アドバイス内で利用 struct inode *i = inode_value; } struct timeval tv; do_gettimeofday(&tv); print(i->i_uid, tv.tv_sec, tv.tv_usec); </before> </advice> </aspect> 23 実行時コンテキストの取得の実装 ウィーバーとKLASY gccの連携により実現 KLASY gccにて構造体への参照方法を保存 ローカル変数から目的の構造体への参照に至る方法を保存 例) inode.length → &inode inode_ptr->length → inode_ptr ウィーバーにて参照を得るトランポリンコードを作成 ローカル変数の格納場所をデバッグ情報をから取得 Gccの作成したデバッグ情報を利用 保存された方法で構造体への参照を得、アドバイスに渡す 24 ケーススタディ: ネットワークI/Oサブシステムの調査 目的 過負荷におけるLinuxネットワークサブシステムの 性能ボトルネックを発見 Sk_buff構造体へのアクセスをトレース Sk_buff構造体はLinuxにてネットワークサブシステム でバッファとして利用 Sk_buffのトレースによりネットワークサブシステムの挙動を 把握 KLASYの実行時コンテキスト取得機能を利用 個々のパケットを識別するため 無関係なパケットを無視するため 25 トレースに用いたアスペクト ワイルドカード <aspect><advice> <pointcut> access(sk_buff.%) AND target(arg0) </pointcut> <before> struct sk_buff *skb = arg0; skb->protocol unsigned long timestamp; if (skb->protocol != ETH_P_ARP) { STORE_DATA($pc$); プログラムカウンタ、 STORE_DATA(skb); ARPパケットを無視 sk_buff出現位置、 DO_RDTSC(timestamp); タイムスタンプを保存 STORE_DATA(timestamp); } </before> </advice></aspect> 26 トレース結果 プロセススケジューリングがボトルネックと判明 Skb_copy_datagram_iovec関数はプロセスの発行した システムコールから呼び出されるので pa cke pa cke 0.1 Time scale of packet arrival 差が大きい t2 t1 1 10 Elapsed time ip_rcv netif_receive_skb tcp_v4_rcv 1000_clean_rx_irq ip_rcv_finish 100 1000 __kfree_skb skb_copy_datagram_iovec tcp_rcv_established tcp_v4_do_rcv 27 ケーススタディでの accessポイントカットの有用性 Sk_buff構造体の全メンバーをaccessポイントカット Linuxネットワークサブシステムの挙動を把握 もし、executionポイントカットでやるとしたら… ネットワークサブシステムについての詳細な知識が必要 過不足なく関数を選択するため 本ケーススタディでは76箇所(関数21個)にてログ取得 最適化禁止が必須 Inline関数への対応が必要 現実と大幅に異なる OSカーネルは通常最適化オプションつきでコンパイルされる 例) Linux カーネルは-Os最適化オプションでコンパイル 本ケーススタディではstatic inline関数6箇所にてログ取得 28 KLASYの有用性 (まとめ) 構造体メンバーアクセスをポイントカット 構造体メンバーアクセスは大規模Cプログラムで使用 関数間でのデータの受け渡しに利用 ポリモルフィズムの実現に利用 メンバーに関数へのポインターを保持 例) 仮想ファイルシステム(VFS)、仮想デバイスなど 例) OS kernel (FreeBSD, Linux), X window System 実行時コンテキストの取得 実行時コンテキストがあると… 詳細な調査が可能 必要なデータのみのログ出力が可能 ログ保存領域を節約 29 既存の C言語用動的アスペクト指向システム TOSKANA [Engel ’05], DAC++ [Almajali ’05], TinyC2 [Zhang ’03],and Arachne [Douence ’05] 実行時コード操作 関数実行、呼び出しのみポイントカット可能 シンボル情報を不使用 TOSKANA-VM [Engel ’05] 仮想機械上でOSカーネルを実行 実際のハードウェア上のプロファイリングは不可能 30 実験 UnixBenchによるベンチマーク Linux: 通常gccでコンパイルしたカーネル -fomit-frame-pointerオプションあり KLASY: KLASY gccでコンパイルしたカーネル 実行時コンテキスト取得のため、-fomit-frame-pointerオプション 使用不可 デバッグ情報の示す変数位置と実位置がずれるため ほぼ-fomit-frame-pointer禁止によるオーバーヘッドを測定 実験環境 CPU: AthlonXP™ 1800+, Mem: 1GB, Linux 2.6.10 Kerninst 2.1.1, gcc 3.3.3, Intel Ethernet PRO/1000 31 実験結果 現実的なオーバーヘッドであることを確認 オーバーヘッド: Linux ex ec l co nt ex t dhry2reg: drystone syscall: システムコール pipe: pipeシステムコール execl: execlシステムコール context: コンテキストスイッチ 1000 800 600 400 200 0 pi pe 0 ~ 12 % 平均: 4.4 % sy sc all y2 re g dh r KLASY 32 関連研究 C言語用静的アスペクト指向システム 実行中のカーネルを変更可能 プロファイリングコードの変更に再起動が必要 例) AspectC [Coady ’01], AspectC++ [Spinczyk ’02] カーネルプロファイラー LKST、 DTrace [Cantrill ’04]、SystemTAP [Prasad ’05]、 LTT [Yaghmour ’00] カーネル内で発生したイベントについてログを取得するツール プロファイラー開発者の設定した箇所でのみプロファイリング 可能 33 まとめ KLASY (Kernel-level Aspect-oriented System)を 提案 Source-based binary-level dynamic weaving 構造体メンバーへのアクセスをポイントカットで選択可能 実行時コンテキストを取得可能 ネットワークI/Oサブシステムのプロファイリングに KLASYが有用であると確認 性能ボトルネックがプロセススケジューリングにあると判明 34
© Copyright 2024 ExpyDoc