AOP言語におけるDynamic Weavingのための一手法

効率的なJava Dynamic AOP
システムを実現する
Just-in-Time weaver
【発表のあらまし】
効率的なJava Dynamic AOPシステム
を実現する手法を提案
AOP:アスペクト指向プログラミング
提案手法を実装したWoolを説明
Jan 23-24, 2003
PRO-2002-4, Nagoya
佐藤芳樹 千葉滋
東京工業大学大学院
情報理工学研究科
1
0. AOP(Aspect-Oriented-Programming)
アスペクト指向とは
モジュール間にまたがる横断的関心事(crosscutting
concerns)をアスペクトとしてモジュール化
[ BookShelf ]
Book search(String key) {
Logger.info(“in
BookShelf#search()”);
while (_booklist.hasMoreElements())
while
if (_booklist.next().match(key))
(_booklist.hasMoreElements())
return book[i];
} if (_booklist.next().match(key)) return book[i];
Logger.info(“out BookShelf#search()”);
}
Aspect
あちこちに散らばるコード
searchとmatchの前後
Logger.info(…)
crosscutting
concern
どこかで無限ループし
てるからメソッドの出入
分散、同期、セキュリティ
りをロギングしてみよ
トランザクション、etc…
ロギング処理をプログラム
う!!
[Book]
[Book]
boolean
boolean match(String
match(String key)
key) {
{
Logger.info(“in
Article#match()”);
if (match0(key)) return true;
if
(match0(key))
else
return false; {
} Logger.info(“out Article#match()”);
return true;
} else {
else
Logger.info(“out Article#match()”);
return false;
}}
} Jan 23-24, 2003
PRO-2002-4, Nagoya
weaver と別に記述
アスペクトとプログラムを
静的に合成(weave)
2
1. 研究の背景
Dynamic AOPとその利点
アスペクトとプログラムを実行時に合成するDAOP
が注目されている
1.開発サイクルの高速化
1.down
3.restart
2.rebuild
(recompile,reweave)
要求、環境に応じサービスを
動的にカスタマイズ
1.dynamic weave
アプリケーションを止めずにロギングのon/off
やパッチ当て
分散GUIアプリケーション
aspects
2.適応的なサービスアスペクト
Jan 23-24, 2003
PRO-2002-4, Nagoya
・配置
・解像度
・ビットレート
・色数 etc…
3
2. Dynamic AOP
AOPを実現するモデル
join-point でアドバイスを実行する
適切に定義された
コードの断片
実行フロー上のポイント
・・・
・フィールド
アクセス
・メソッド
呼び出し
・オブジェクト
生成
Dynamic Join Point Model
(AspectJ[*1]で提案)
アスペクト
pointcut 場所の指定
(join-pointを指定)
advice 処理の記述
match()
search()
join-point
Logger.info()
*1 Xerox Corporation. “The AspectJ Programming Guide.
Online Documentation”, 2001. http://www.aspectj.org/
Jan 23-24, 2003
PRO-2002-4, Nagoya
4
2. Dynamic AOP
フックによる典型的な実装
アスペクトとプログラムの合成
= 静的コード変換によるフック挿入


join-pointにあたる場所にフックを挿入
フックにより実行がインターセプトされ適切なアドバイス
を実行
do_before_advice();
do_after_advice();
join
point
do_before_advice();
do_after_advice();
挿入された
フックコード
フック
pointcut
指定
Jan 23-24, 2003
PRO-2002-4, Nagoya
5
2. Dynamic AOP
既存のJava DAOPシステム
DAOPシステムを実現するためには、実行時にフッ
クを挿入する機能が必要

動作リフレクション(演算を横取りし変更できる機能)
• CLOS、Smalltalk、etc

処理系の改造
可搬性を損なう

静的コード変換
低品質のコードを生成 → 次に説明
Jan 23-24, 2003
PRO-2002-4, Nagoya
6
2. Dynamic AOP
静的コード変換
すべてのjoin-pointへ静的にフックを挿入


静的にフックを挿入する場所を特定できない
アドバイスを実行するかどうかをチェック
チェックのための分岐、無駄なフックに
pointcutでの
指定はここだけ
need_advice();
need_advice();
need_advice();
need_advice();
need_advice();
need_advice();
need_advice();
need_advice();
need_advice();
need_advice();
need_advice();
need_advice();
よるコードサイズの肥大化
常にすべてのjoin-pointでチェック
低品質のコードを生成

Jan 23-24, 2003
長時間稼動するサーバアプリに問題
PRO-2002-4, Nagoya
7
3. ジャストインタイム・フック埋め込み
ジャストインタイム・フック埋め込みの提案
フックを挿入するためにデバッガによる手法と動的
クラス書き換え手法をハイブリッド
1.デバッガによるフック挿入・実行(PROSE[*2])
• フックをbreakpointとして挿入
• デバッガがアドバイスを実行
2.動的クラス書き換え(我々が開発)
• コード変換でフックを挿入+ロード済みクラスの再定義
• 再定義を可能な限り遅延
*2 Andrei. P, Thomas. G and Gustavo. A. “Dynamic
Weaving for Aspect-Oriented Programming” In AOSD’02
Jan 23-24, 2003
PRO-2002-4, Nagoya
8
3. ジャストインタイム・フック埋め込み
デバッガによるフック挿入・実行
フックをbreakpointで挿入(PROSE[*2])

breakpointで実行をインターセプト+アドバイス実行
• 実行コードに無駄なフック無し
• JPDA(デバッガ)を使用し可搬性を損なわない
breakpointセット
デバッガ
デバッガ
do_advice();
デバッガが
アドバイス実行
*2 Andrei. P, Thomas. G and Gustavo. A. “Dynamic
Weaving for Aspect-Oriented Programming” In AOSD’02
Jan 23-24, 2003
PRO-2002-4, Nagoya
9
3. ジャストインタイム・フック埋め込み
動的クラス書き換え
フックをコードに埋め込む

必要になるまで遅延し、Just-in-Timeに埋め込む
• 無駄なフックを挿入しない


その後は高速にアドバイスを実行
HotSwap機能を使用(Sun JDK1.4 JPDA)
• デバッガの制御下でロード済みクラスを再定義できる機能
JVM
do_advice();
do_advice();
フック入り
クラス
JPDA
do_advice();
do_advice();
Jan 23-24, 2003
do_advice();
do_advice();
ロード済み
クラス
do_advice();
do_advice();
クラス再定義
PRO-2002-4, Nagoya
10
3. ジャストインタイム・フック埋め込み
ハイブリッドした手法
二段階のフック埋め込み


初めにフックはすべてbreakpointとして挿入
選択的に動的クラス書き換え
③-1
デバッガ
① アスペクトがweave
しjoin-pointが判明
② 指定されたすべての
join-pointへ
breakpointをセット
デバッグモード(-Xdebug)
でHotSpot実行
Jan 23-24, 2003
デバッガ
デバッガが
アドバイス実行
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
PRO-2002-4, Nagoya
③-2
動的クラス書き換え
対象プログラムが
アドバイス実行
11
3. ジャストインタイム・フック埋め込み
ハイブリッドする必要性
使用頻度の高いアドバイス

デバッガがアドバイス実行 → アドバイス実行がボトルネック
使用頻度の低いアドバイス

ア
ド
バ
イ
ス
実
行
時
間
高価な動的クラス書き換え → 変換がボトルネック
トレードオフ
デバッガ
標準でデバッガがアドバイス実行
ハイブリッド
動的クラス書き換え
システムロードに応じ効果的に
動的コード書き換え
フック埋め込み時間
Jan 23-24, 2003
PRO-2002-4, Nagoya
12
3. ジャストインタイム・フック埋め込み
JITコンパイラとの比較
JITコンパイラの動作との類似点・相違点

類似点
• オンデマンドにコード変換
• 性能向上のために2種類の実行法をハイブリッド

相違点
• weave後にコードのセマンティクスが変更
=>weave時にactiveなフレームへの配慮が必要
実行の途中で書き換えられるメソッドでのアドバイス
依存関係のあるアドバイス
Jan 23-24, 2003
PRO-2002-4, Nagoya
13
3. ジャストインタイム・フック埋め込み
実行途中で書き換えられるメソッド
activeフレームではデバッガがアドバイス実行
activeフレーム = 実行途中のメソッド

HotSwap時にactiveなフレームが参照するクラスは変
更されない(JPDAの仕様)
アドバイスが実行されず一貫性が崩れる
Book#match0()
Book#match()
BookShelf#search()
Jan 23-24, 2003
weave後に積まれる
フレームは変更後の
クラスを参照
do_advice();
do_advice();
クラス定義は元のまま
PRO-2002-4, Nagoya
do_advice();
14
3. ジャストインタイム・フック埋め込み
依存関係のあるアドバイス
activeフレームでのデバッガのアドバイス実行の
有無は手動で選択


beforeアドバイスは実行されていない
afterアドバイスの実行はユーザが選択
例: searchメソッドの前後で時間を計り検索時間を測定する機能を
アスペクトで追加
before
デバッガ
Book#match0()
Book#match()
BookShelf#search()
Jan 23-24, 2003
デバッガ
after
after
PRO-2002-4, Nagoya
beforeが実行されてい
なくてもafterのみ実行
15
3. ジャストインタイム・フック埋め込み
全体の流れ
join-pointでアドバイス実行手法を選択
= 動的に切り替え → 各問題を解決
デバッガに
よる実行
ボトル
ネックの
除去
デバッガに
よる実行
activeフレーム
do_advice();
do_advice();
動的クラス
書き換え
Jan 23-24, 2003
アドバイス間
に依存関係
activeフレーム
選択的に
実行
埋め込まれた
アドバイス実行
do_advice();
do_advice();
do_advice();
do_advice();
アドバイスが
実行されない
PRO-2002-4, Nagoya
16
4. Wool
Woolの実装
ジャストインタイムフック埋め込みをJava用に実装
したJust-in-Time weaver

JPDAでbreakpointセットとクラス再定義、Javassistでバイトコー
ド変換
クラス再定義
aspects
Javassist
+
JVM
バイトコード
変換
JPDA
breakpointセット、
アドバイス実行
Jan 23-24, 2003
do_advice();
do_advice();
PRO-2002-4, Nagoya
Wool
17
4. Wool
Woolの起動法
1.
外部プログラムから起動 => 開発サイクルの高速化
% wool –weave LoggingAspect –address islisp.ysk.csg.private
% wool –unweave LoggingAspect –address islisp.ysk.csg.private
2.
アプリケーションが起動 => サービスアスペクトの実現
WlAspect pda = WlAspect.forName(“PDAAspect”);
WlAspect pc = WlAspect.forName(“PCAspect”);
Wool wool = Wool.connect(“somedomain”,5432);
switch(client) {
case PDA : wool.weave(pda);
case PC : wool.weave(pc);
}
Jan 23-24, 2003
PRO-2002-4, Nagoya
18
4. Wool
アドバイス実行手法選択の記述
アスペクトプログラムからWoolを制御する機構
• コンテキストに応じてアドバイス実行手法を選択
• 外部からweaveする場合、反映されるタイミングが不定
Woolの初期化
合成の前後
切り離しの前後

コールバックメソッドに各タイミングで
Woolを制御するコードを記述する
メタな処理(実行フロー外のポ
イント)なのでjoin-pointでは
表現しない
Jan 23-24, 2003
例
public void beforeWeave(Wool wool) {
if (wool.joinMethodExit()) wool.skip();
}
public void afterWeave(Wool wool) {
if (wool.countActiveFrame() > 0)
wool.regardActiveFrame();
}
PRO-2002-4, Nagoya
19
5. 性能測定
比較実験
実験環境
Arch : SunBlade1000、
CPU : UltraSPARC-III 750MHzX2、Memory : 1GB
OS : Solaris8
JVM : Sun J2SDK1.4.0 HotSpotTMClient VM
Wool
現在は最初のjoin-pointで必ず動的クラス書き換え
実験プログラム
1.
2.
SpecJVM98のjess
自然数の和を求める再帰メソッド
Jan 23-24, 2003
PRO-2002-4, Nagoya
20
5. 性能測定
結果と考察(1)
目的-実行時間と合成処理にかかる時間の測定(activeフレーム処理無し)
方法-ナンバーパズル〈N〉、モンキーバナナ〈M〉
〈1〉protectedメソッド(4of146、734615回呼び出し)にnullアドバイス
〈2〉1つのメソッド(1of146、1338回呼び出し)にnullアドバイス
結果
AspectJ
デバッガ手法
〈N〉
〈1〉
8590
7388812
〈N〉
〈2〉
8522
〈M〉
〈1〉
1063
Wool
総実行時間のうちわけ
join-point抽出
変換再定義
実行時間
19638
1680
4057
13901
23307
11832
1680
806
9376
45817
11003
1680
4057
5266
5回計測の最小値
単位[msec]
考察
〈M〉
1003
3833
3993
1680
806
1507
・アドバイス実行回数が多いほど良い結果、少ないほど動的クラス書き換
〈2〉
えのオーバーヘッド
・join-point抽出+変換再定義を差し引いた実行時間がAspectJに近い
Jan 23-24, 2003
PRO-2002-4, Nagoya
21
5. 性能測定
結果と考察(2)
目的-デバッガでのactiveフレーム処理の性能劣化
方法-sum()実行中にnullアドバイスをweave
activeフレームの個数を変化
結果
デバッガ手法
Wool
30000
26000
処理時間[ms]
25000
20000
15000
10000
5000
2500
0
0
5
10
20
40
60
80
100 120 140 160 180 200
activeフレームの個数
考察
・デバッガでのアドバイス実行回数が多いほど性能劣化
・扱うactiveフレームが0の場合性能劣化がだいぶ小さい
Jan 23-24, 2003
PRO-2002-4, Nagoya
22
6. まとめ
まとめと課題
ジャストインタイム・フック埋め込みを提案し、Java
用のweaverであるWoolをJavaで実装した



実行時に無駄なフックの無い良質のコードを生成
アスペクトと合成後に高速実行
weaverを柔軟に制御する機能を提供
今後の課題




追加実験(静的コード変換)
未実装機能の実装(Introduction,aroundアドバイス)
パフォーマンスチューニング
動的プロファイラの実装
Jan 23-24, 2003
PRO-2002-4, Nagoya
23
7. 別の実装手法
別の実装手法1
アドバイス実行方式の選択を自動化

手動選択(現在)
• アドバイス実行方式を手動で選択できる機構

自動選択
• 環境(システムロードなど)に応じ適切な実行方式を選択
HotSpot技術のように動的プロファイラで実行時
の傾向をプロファイリング
アドバイスの実行回数が閾値を超える
=> 動的クラス書き換えを施す
Jan 23-24, 2003
PRO-2002-4, Nagoya
24
7. 別の実装手法
別の実装手法2
自己反映的なOpenJITで実装
• アスペクトのディレクティブでコンパイルコードを変更
• 動的に再コンパイル

メソッド単位でアスペクトの合成
• 無駄なフックの挿入をより抑えられる

同様のactiveフレーム対応処理
さらなる高速化が期待できるが可搬性を
損なうので現実的ではない
Jan 23-24, 2003
PRO-2002-4, Nagoya
25
付録
アスペクトの記述
Javaでのアスペクト記述
public class LoggingAspect extends WlAspect {
WlCrosscut record = pointcut("*","BookShelf","search",
ポイントカット
"(Ljava/lang/String;)V").joinCall();
public void doit() {
記述
teach(new WlBeforeAdvice(record) {
public void advice(TargetInfo tinf) {
Target t = tinf.getTarget();
アドバイス
Logging.info(“in ” + t.className()+”#”+t.name());
記述
}
});
}
public void initWeave(Wool wool) throws Exception {
weaverの
wool.filter(" ^java.*|^sun.*“,false);
制御記述
}
}
Jan 23-24, 2003
PRO-2002-4, Nagoya
26
付録
デバッガによるフック挿入・実行
do_advice();
Jan 23-24, 2003
PRO-2002-4, Nagoya
27
付録
動的コード書き換え
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
Jan 23-24, 2003
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
PRO-2002-4, Nagoya
28
付録
ジャストインタイム・フック埋め込
み(ハイブリッド)
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
do_advice();
Jan 23-24, 2003
PRO-2002-4, Nagoya
29