1 / 22

An Extension of AspectJ to Weave Aspect into an Arbitrary Code Region

An Extension of AspectJ to Weave Aspect into an Arbitrary Code Region. 赤井駿平 08M37025 千葉研究室. 目的 : 同期の粒度を切り替えたい. ライブラリが2種類の同期を提供 : 細かい粒度の同期 高並列性 粗い粒度の同期 低オーバーヘッド ライブラリのユーザが最適な粒度を選ぶ 環境に応じて 良い性能 同期のコードの付替が容易でなければならない アスペクトを利用してはどうか?. ライブラリ. 粗い同期. 細かい 同期. Motivation: ライブラリにおける同期処理.

jamuna
Download Presentation

An Extension of AspectJ to Weave Aspect into an Arbitrary Code Region

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. An Extension of AspectJ to Weave Aspect into an Arbitrary Code Region 赤井駿平 08M37025 千葉研究室

  2. 目的:同期の粒度を切り替えたい • ライブラリが2種類の同期を提供: • 細かい粒度の同期高並列性 • 粗い粒度の同期低オーバーヘッド • ライブラリのユーザが最適な粒度を選ぶ • 環境に応じて • 良い性能 • 同期のコードの付替が容易でなければならない • アスペクトを利用してはどうか? ライブラリ 粗い同期 細かい同期

  3. Motivation: ライブラリにおける同期処理 public classProxyFactory { public Class createClass() { if (thisClass == null) { ClassLoadercl = getClassLoader(); synchronized(proxyCache) { if (useCache){createClass2(cl);} else {createClass3(cl);} }} return thisClass;} private voidcreateClass2(ClassLoader cl) { CacheKey key = new CacheKey(…); HashMapcacheForTheLoader =…; if (cacheForTheLoader == null) { cacheForTheLoader = newHashMap(); proxyCache.put(cl, cacheForTheLoader); cacheForTheLoader.put(key, key); }else {...} Class c = isValidEntry(key); if (c == null) { createClass3(cl); key.proxyClass = newWeakReference(…); }else{thisClass = c;} }} • 2006年にJavassistに対してバグレポート • Not thread-safe! • 単純な修正は簡単 • synchronized文を追加

  4. 修正によるパフォーマンスへの影響 public classProxyFactory { public Class createClass() { if (thisClass == null) { ClassLoadercl = getClassLoader(); synchronized (proxyCache) { if (useCache){createClass2(cl);} else {createClass3(cl);} }} return thisClass;} private voidcreateClass2(ClassLoader cl) { CacheKey key = new CacheKey(…); synchronized (proxyCache) { HashMapcacheForTheLoader =…; if (cacheForTheLoader == null) { cacheForTheLoader = newHashMap(); proxyCache.put(cl, cacheForTheLoader); cacheForTheLoader.put(key, key); }else {...}} synchronized (key) { Class c = isValidEntry(key); if (c == null) { createClass3(cl); key.proxyClass = newWeakReference(…); }else{thisClass = c;} }}} Coarse-grained • synchronized文の付け方が問題 • 細かい粒度 • 高い並列性 • オーバーヘッドが多い • 粗い粒度 • 並列性が低い • 少コアのマシンでは早い Fine-grained

  5. アスペクト指向で同期を切り替えたい • 横断的関心事をモジュール化 • join point: プログラム実行中の実行点(メソッド呼び出し,フィールドアクセス…) • pointcut: join point を選ぶ手段 • advice: 選択したjoin point で実行するコード pointcut advice public String toString(){ foo(); return …; } void around (): call(* *.foo()) {bar(); proceed() ;} call join point

  6. アスペクト指向で同期を切り替えたい public classProxyFactory { public Class createClass() { if (thisClass == null) { ClassLoadercl = getClassLoader(); synchronized(proxyCache) { if (useCache){createClass2(cl);} else {createClass3(cl);} }} return thisClass;} private voidcreateClass2(ClassLoader cl) { CacheKey key = new CacheKey(…); synchronized (proxyCache) { HashMapcacheForTheLoader =…; if (cacheForTheLoader == null) { cacheForTheLoader = newHashMap(); proxyCache.put(cl, cacheForTheLoader); cacheForTheLoader.put(key, key); }else {...}} synchronized (key) { Class c = isValidEntry(key); if (c == null) { createClass3(cl); key.proxyClass = newWeakReference(…); }else{thisClass = c;} }}} • 領域に対して around adviceを 織り込みたい void around (): pointcut(coarse_grained_region) { synchronized(…) { proceed(); } } void around (): pointcut(fine_grained_regions) { synchronized(…) { proceed(); } }

  7. Our Proposal • Regioncut • 領域を選択する指定子 • Assertion for Advice • fragile性の問題を解決するため • 指定したアドバイスが織り込まれていないと警告 void around(): region[ call(* Map.get(..)), call(* Map.put(..)) ] { …; proceed(); …;} @AssertAdvised(“lock_map”) void foo(){ … } @SolveProblem(“Foo.lock_map”) void around(): … { … }

  8. AspectJでは実現不可 • Pointcutは領域を選択できない • execution “point”のみ選択可能 • Call: メソッド呼び出しを選択 • Get, set: フィールドアクセスを選択 • Execution: メソッドボディを選択 • around advice を使えばメソッドボディ全体は同期可能 • メソッドボディが最適な粒度とは限らない→リファクタリングが必要 • 全ての粒度の同期の箇所をメソッドに抽出するのは大変

  9. なぜAspectJは同期/領域を扱えないか • Fragile性を減らせない • コードが変更されると選択できなくなる可能性 • 領域にはpointcut より指定に多くの情報が必要 • pointcut より変更に弱い • 同期は必須の関心事 • 同期アスペクトを織り込み忘れると正しく動かない • AspectJでは織り込み忘れを発見できない

  10. Our Proposal:Regioncut • 新しいポイントカット指定子のようなもの • 領域を選択 • 領域を指定するには • 領域内のexecution pointの中で重要なものを列挙 • call, get, set, が使える • 選択したい典型的な領域はそれで指定できる voidfoo(Map map){ Object o=map.get(key); println(o); o=nextValue(o); map.put(key,o);} region[ call(* Map.get(..)), call(ObjectnextValue(Object)), call(* Map.put(..)) ]

  11. 領域の拡大 • 領域と制御構造が衝突 • around advice を織り込めない • 領域を拡大: • 元の領域を含み • 制御構造を含み • かつできるだけ小さく voidfoo(Map map){ … Object o=map.get(key); println(o); o=nextValue(o); if(…){ map.put(key,o); … } … } Conflict Expanded

  12. Fragile性を 減らすため Our Proposal: Assertion for Advice • 織り込まれなくなったアドバイスを見つけて警告 • @AssertAdvised(“<concern_name>”) • adviceが必要なメソッドに付加.関心事の名前を付ける • @SolveProblem(“<ClassName>.<concern_name>”) • 対象の関心事を解決するadviceに付加 class Foo{ @AssertAdvised(“lock_map”) voidfoo(Map map){ … } } @SolveProblem(“Foo.lock_map”) void around(): region[ … ]{ synchronize(…){ proceed(); } }

  13. Assertion for Advice チェッカー • @AssertAdvicedの付いたメソッドが対応するadviceを持つかチェック • 以下の場合警告なし: • adviceがメソッドを呼んでいる • メソッドがadviceを呼んでいる • 間接的にでもOK @SolveProblem(“Foo.lock_map”) void around(): … { … } Call the method @AssertAdvised(“lock_map”) void foo(){ … } Call the advice @SolveProblem(“Foo.lock_map”) void around(): … { … }

  14. 2つのチェッカーを開発 • 静的なチェッカー • クラスファイルを解析 • コールグラフを調べる • 制限 • リフレクションに対応できない • 動的なチェッカー • 実行時に(呼び出した|呼ばれた)かを調べる • 実際に実行された部分のみチェック可能

  15. Implementation • the AspectBench Compiler (abc)を拡張 • Regioncut • 中間言語Jimpleを解析/変換 • Assertion for Advice • dynamic: ASTを変換してダイナミックにチェック • static: Sootを利用 • 10,000+ LOC

  16. Implementation Issue(1/2): Around advice • abcで around adviceを織り込む場合 • join points/regions を抽出しメソッドに分ける • 問題 • ローカル変数を共有できない • 領域の外へジャンプできない public void toBeAdvised(intx){ a(); b(x); c(); } public void toBeAdvised(intx){ advice(x); } public static void advice(intx){ beforeJoinPoint(); shadow(x); afterJoinPoint(); } public static shadow(intx){ a(); b(x); c(); }

  17. Implementation Issue(2/2): 解決法 • ローカル変数を保存するオブジェクト • 引数経由で共有して対処 • ジャンプ先を示す値を変数に入れて共有 • 領域を抜けてからジャンプするように変換 { intx; intjmpTgt; } share public void toBeAdvised(intx){ advice(x); } public static void advice(Objo){ beforeJoinPoint(); shadow(x); afterJoinPoint(); } public static shadow(Objo){ a(); b(x); c(); }

  18. 評価: regioncutの記述力 • Hadoopのsynchronized文をアスペクトに分離 • regioncutが領域を十分に選択できるかを評価 • Hadoop 0.16.4 • 通常のpointcutで選択できなかったものは全て選択できた • 12の内の8領域が拡大が必要

  19. 評価: Assertion が有効に働くか • Hadoop を 0.16.4 から 0.18.3に更新 • dynamic版を使用 • Hadoopのユニットテストを動かしてチェック • 6個が正しく織り込まれなかった • 2個は検知 • 残りは実行されていなかったので検知不可

  20. Current Limitation • 選択した2つ以上の領域が重なると • around adviceをweaveできない • 何らかの優先順位を付ける必要がある void withConflict(){ beginA(); beginB(); endA(); endB(); }

  21. Related Work • 領域へのpointcutは重要な問題 • 限定的な解 • Loop join point: ループボディにマッチ • Synchronized join point: synchronized文にマッチ • 同等の解 • Transactional pointcut • 同じ会議で同時にaccept

  22. Conclusion • アスペクト指向言語で領域を選択を実現 • Regioncut • Assertion for advice • これまでの成果 • 査読付き • GPCE'09, 2009-10, Denver • 査読なし/ワークショップ • ソフトウェア科学会大会,2008-07,東京 • ACP4IS’09, 2009-03,Charlottesville

More Related