同期処理のモジュール化を 可能にする

同期処理のモジュール化を
可能にする
アスペクト指向言語
理学部 情報科学科
04_00290 赤井駿平
指導教員 千葉滋
同期処理の分離の必要性
 同期処理を適用する範囲を
切り替えたい
同期処理は計算機の特性に
より最適な粒度が変化
Javassistのバグレポート
public class ProxyFactory {
public Class createClass() {
if (thisClass == null) {
粗い粒度
ClassLoader cl = getClassLoader();
synchronized (proxyCache) {
if (useCache){createClass2(cl);}
else {createClass3(cl);}
}}
return thisClass;
}
細かい粒度
private void createClass2(ClassLoader
cl) {
CacheKey key = new CacheKey(…);
synchronized (proxyCache) {
HashMap cacheForTheLoader =…;
if (cacheForTheLoader == null) {
cacheForTheLoader = new HashMap();
proxyCache.put(cl, cacheForTheLoader);
cacheForTheLoader.put(key, key);
}else {...}}
synchronized (key) {
Class c = isValidEntry(key);
if (c == null) {
createClass3(cl);
key.proxyClass = new WeakReference(…);
}else{thisClass = c;}
}}
[JASSIST-28 :
http://jira.jboss.org/jira/browse/JASSIST-28]
細かい粒度と粗い粒度の同
期処理を切り替えて,動作
速度を調べる
 同期を行う箇所が散らばって
いるので切り替えが大変
}
アスペクト指向言語による同期の分離
- コード範囲をポイントカットすることの困難さ
 Fragile pointcut problem
ソースコードを変更により
 意図してしない場所をポイントカットしてしまう
 意図した場所をポイントカットできなくなってしまう
範囲のポイントカットはソースコードの変更に弱い
 例:行番号の指定
• 改行を追加するだけで意図した場所をポイントカットできなくなる
 ソースコードの変更に強い指定方法が必要
Fragile pointcut problemの要因
 プログラムのブロック構造の変化
 GluonJ/R [熊原ら ’07]
 始点・終点をポイントカットで指定
 ブロックの構造を無視したポイントカットを行えてしまう
 適用できるアドバイスは例外処理のみ
 類似したコード範囲の出現
 LoopsAJ [Harbulot et al. ’06]
 ループのみポイントカット可能
 メソッド内のループの区別ができない
 取得するコンテキストに含まれる変数の名前・順序の変更
 ローカル変数をアドバイスで利用したい
 ローカル変数の指定方法を工夫しないと,fragile pointcut
提案:ブロックポイントカット
ブロックのような複数の実行点を含む範囲を
ジョインポイントとして指定
その範囲に対しアドバイスを実行できる
同期処理の分離や差し替えが容易
ソースコードの変更に強い範囲の指定方法
Fragile pointcut problemに対処可能
ポイントカットする範囲に条件を指定する
取得するコンテキストの指定
ブロック構造を考慮した範囲の指定
begin/endポイントカット
始点,終点となるジョイン
ポイントを指定し,その2
点間がポイントカットされ
る
ブロックの深さが違う場合
は,同じ深さまでブロック
をさかのぼる
制御構造やブロックと重な
らないように範囲を決定
void foo(){
…
start();
…
if(n>0){
finish();
}else{
...
}
…
}
×If文と重なる
If文
void around():
begin(call(* *.start())) &&
end(call(* *.finish()))
{proceed();}
類似したコード範囲の区別
include/excludeポイ
ントカットを利用して絞
り込む
範囲の中に含まれなけ
ればいけない,含まれ
てはいけないジョインポ
イントを指定
void bar(){
start();
a();
finish();
…
start();
b();
finish();
}
後から追加
void around():
begin(* *.start()) &&
end(* *.finish())
&& include(call(* *.a()))
{
proceed();
}
コンテキストの取得
同期処理を行う場合,
ローカル変数を取得
できなければならない
型を指定して取得する
ローカル変数を選ぶ
変数の名前や宣言順
で指定すると fragile
pointcut problem が起
こりやすい
List list = (List)map.get("list");
synchronize(list){
start();
list.remove(0);
finish();
}
void around(List l) :
begin(* *.start()) &&
end(* *.finish()) &&
args(List) && args(l)
{
synchronized(l){
proceed(l);
}
}
実装
AspectJを拡張
AspectBench Compiler を改造して実装
中間表現上にブロック,制御構造,文の情報
を記録する
開始・終了を表す命令を新たに用意し,前後に挿入
ブロックを解析し,ポイントカットで指定された条件に
マッチする範囲を選ぶ
適用例
Javassistのバグレポートにおける同期処理
の粒度を切り替える
粗い粒度の場合
static WeakHashMap proxyCache;
public Class createClass() {
if (thisClass == null) {
ClassLoader cl = …;
if (useCache)
createClass2(cl);
else
createClass3(cl);
}
return thisClass;
}
void around():
begin(call(* *.createClass2(..)))&&
end(call(* *.createClass3(..)))
{
synchronized(
ProxyFactory.proxyCache){
proceed();
}
}
適用例(続き)
細かい粒度の場合
static WeakHashMap proxyCache;
private void createClass2(ClassLoader cl) {
CacheKey key =…;
HashMap cacheForTheLoader =
(HashMap)proxyCache.get(cl);
if (cacheForTheLoader == null) {
proxyCache.put(...);
cacheForTheLoader.put(...);
}else{...}
Class c = isValidEntry(key);
if (c == null) {
createClass3(cl);
key.proxyClass =
new WeakReference(thisClass);
}else{...}
}
void around():
begin(call(* WeakHashMap.get(..)))
&& end(call(* WeakHashMap.put(..))){
synchronized(
ProxyFactory.proxyCache){
proceed();
}
}
void around(CacheKey key):
begin(call(* *.isValidEntry(..))) &&
end(call(WeakReference.new(..))) &&
args(CacheKey) && args(key){
synchronized(key){
proceed(key);
}
}
速度の測定
 Javassistの同期の粒度をアスペクトを用いて変更し,バ
グレポートに投稿されたマイクロベンチマークを使用して
実行時間を測定(1000回試行)
4コア,40スレッド
 細かい粒度 : 平均実行時間 8.97秒,標準偏差 0.36
 粗い粒度 : 平均実行時間 11.94秒,標準偏差 0.17
2コア,40スレッド
 細かい粒度 : 平均実行時間 13.31秒,標準偏差 1.02
 粗い粒度 : 平均実行時間 13.08秒,標準偏差 0.26
実験環境
CPU:Xeon 3.00GHz 最大4コア
メモリ: 2GB
OS: Linux 2.6.22-14
JVM: java 1.6.0_03
アスペクトを用いて粒度を切り替
えた方が性能が良くなる
粒度の切り替えによる性能の向上
 2コアで40スレッドの場合,粗い粒度の方が安定した速度
 速度の安定性を考えると,粗い粒度の方が良い性能を出すことが分
かる
細かい粒度(2コア,40スレッド)
粗い粒度(2コア,40スレッド)
700
600
600
500
500
400
400
度数
度数
700
300
300
200
200
100
100
0
0
10~11
11~12
12~13
13~14
14~15
15~16
16~17
実行時間(秒) 平均:13.31秒
17~18
21~22
10~11
11~12
12~13
13~14
14~15 15~16
16~17
実行時間(秒) 平均:13.08秒
17~18
21~22
まとめと今後の課題
範囲をポイントカットする機構を提案
同期処理を分離して記述することができる
AspectBench Compilerを改造して実装
Javassistに適用して実験
今後の課題
コンテキスト渡しの指定方法の改善
より柔軟な範囲の指定方法