OSカーネル用 アスペクト指向システム KLASY

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(&amp;tv);
print(i-&gt;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(&amp;tv);
print(i-&gt;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(&amp;tv);
print(i-&gt;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(&amp;tv);
print(i-&gt;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(&amp;tv);
within_function() により選択範囲を
print(i-&gt;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(&amp;tv);
print(i-&gt;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(&amp;tv);
i_uidの値とともに保存
print(i-&gt;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(&amp;tv);
print(i-&gt;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-&gt;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