任意粒度機能モデルに基づくコードクローン検出手法の大規模プログラムの適用に向けた改善...

27
2013/07/26 IPSJ SIGSS 2013 7 年 月研究会 任意粒度機能モデルに基づく コードクローン検出手法の改善 神谷年洋 公立はこだて未来大学 大規模プログラムへの 適用に向けた 論文のwordle. www.wordle.netにて作成

Upload: kamiya-toshihiro

Post on 27-Jun-2015

607 views

Category:

Technology


4 download

DESCRIPTION

神谷年洋, "任意粒度機能モデルに基づくコードクローン検出手法の大規模プログラムの適用に向けた改善", 電子情報通信学会 2013年7月 ソフトウェアサイエンス研究会

TRANSCRIPT

Page 1: 任意粒度機能モデルに基づくコードクローン検出手法の大規模プログラムの適用に向けた改善

2013/07/26 IPSJ SIGSS 2013 7年 月研究会

任意粒度機能モデルに基づくコードクローン検出手法の改善

神谷年洋公立はこだて未来大学

大規模プログラムへの適用に向けた

論文のwordle.www.wordle.netにて作成

Page 2: 任意粒度機能モデルに基づくコードクローン検出手法の大規模プログラムの適用に向けた改善

2013/07/26 IPSJ SIGSS 2013 7年 月研究会

任意粒度機能モデルに基づくコードクローン検出手法とは

● ソースコードのリファクタリングの機会を探すため● ソフトウェアのソースコード内の類似した機能を持つコード断片を検出

する

● 類似した機能の判定: 2つのコード断片で呼び出す手続きの列が同じである

ただし

● 任意の粒度: 手続きは入れ子になって定義される。任意の階層で一致すれば一致と判定する

● 全実行パス: プログラムのあらゆる実行を考えて、そのいずれかの実行で一致すれば一致と判定する

Page 3: 任意粒度機能モデルに基づくコードクローン検出手法の大規模プログラムの適用に向けた改善

2013/07/26 IPSJ SIGSS 2013 7年 月研究会

字面の一致を用いない理由

● なぜ「任意の粒度」「全実行パス」とか面倒なことをいってるのか– ⇔ 字面の一致を利用したコードクローン検出ツール

CCFinder(および-X)

● コードが書かれた後、書き換えられることを想定しているため– リファクタリング=ソースコードの機能を変えずに構造を

変更する

リファクタリングの例

Page 4: 任意粒度機能モデルに基づくコードクローン検出手法の大規模プログラムの適用に向けた改善

2013/07/26 IPSJ SIGSS 2013 7年 月研究会

お題: FizzBuzz

● FizzBuzzとは– 1から順に数えあえげ。ただし

– 3で割り切れる数字ならfizz

– 5で割り切れる数字ならbuzz

– 3と5の両方で割り切れる数字ならfizzbuzz

● 1から20までのFizzBuzz– 1, 2, fizz, 4, buzz, fizz, 7, 8, fizz, buzz,

– 11, fizz, 13, 14, fizzbuzz, 16, 17, fizz, 19, buzz

● 元々は英語圏の子供の遊び。転じて、プログラミングの例題

http://rosettacode.org/wiki/FizzBuzz

170以上の言語で記述したfizzbuzz

Page 5: 任意粒度機能モデルに基づくコードクローン検出手法の大規模プログラムの適用に向けた改善

2013/07/26 IPSJ SIGSS 2013 7年 月研究会

FizzBuzzWrong

● 最初の実装– 3で割り切れたら→fizz()

– 5で割り切れたら→buzz()

– それ以外なら→数字

● 仕様に合致せず – 「3と5の両方で割り切れ

る数字ならfizzbuzz」になっていない

Page 6: 任意粒度機能モデルに基づくコードクローン検出手法の大規模プログラムの適用に向けた改善

2013/07/26 IPSJ SIGSS 2013 7年 月研究会

FizzBuzz1

● 仕様通り– 3で割り切れたらfizz()

● fizz(): fizzを出力してさらに5で割り切れたら→・・・

● 構造が汚い– テストを通すため、あまり考

えずにfizz()メソッドに仕事を押し込んだ

– fizz()が名前からは想像できない仕事をやっている

– fizz()とbuzz()の対称性が無くなった

Page 7: 任意粒度機能モデルに基づくコードクローン検出手法の大規模プログラムの適用に向けた改善

2013/07/26 IPSJ SIGSS 2013 7年 月研究会

FizzBuzz3

● 仕様通り– 3と5で割り切れたら

→fizz()とbuzz()

● 構造もキレイ– fizz()内の処理を外側

に追い出した

– fizz()とbuzz()の対称性が回復した

Page 8: 任意粒度機能モデルに基づくコードクローン検出手法の大規模プログラムの適用に向けた改善

2013/07/26 IPSJ SIGSS 2013 7年 月研究会

RQ(前回の)

● FizzBuzz1とFizzBuzz3から、等価な処理(「3と5の両方で割り切れる数字ならfizzbuzz」)を見つけてくることができるか?– 字面は全く異なる

Page 9: 任意粒度機能モデルに基づくコードクローン検出手法の大規模プログラムの適用に向けた改善

2013/07/26 IPSJ SIGSS 2013 7年 月研究会

ope: java/lang/Integer.valueOf:(I)Ljava/lang/Integer; java/io/PrintStream.format:(Ljava/lang/String;⇩ [Ljava/lang/Object;)Ljava/io/PrintStream; java/io/PrintStream.print:(Ljava/lang/String;)V buzz:(Ljava/io/PrintStream;)V java/io/PrintStream.println:(Ljava/lang/String;)Vtrace: FizzBuzz1.java: 16 >0 // main:([Ljava/lang/String;)V FizzBuzz1.java: 16 >0 // main:([Ljava/lang/String;)V FizzBuzz1.java: 6 >1 // fizz:(Ljava/io/PrintStream;I)V FizzBuzz1.java: 8 >1 // fizz:(Ljava/io/PrintStream;I)V FizzBuzz1.java: 24 >0 // main:([Ljava/lang/String;)Vtrace: FizzBuzz3.java: 14 >0 // main:([Ljava/lang/String;)V FizzBuzz3.java: 14 >0 // main:([Ljava/lang/String;)V FizzBuzz3.java: 6 >1 // fizz:(Ljava/io/PrintStream;)V FizzBuzz3.java: 18 >0 // main:([Ljava/lang/String;)V FizzBuzz3.java: 25 >0 // main:([Ljava/lang/String;)V

・・・できます

● メソッド呼び出し列としてみれば一致する

● 右はツールの出力の一部– 「3と5の両方で割り切れる

数字ならfizzbuzz」の部分– 「trace:」の行で始まる2つの

実行系パス– 「ope:」で始まる実行がメ

ソッド呼び出し列

●「任意の粒度」「全実行パス」を考慮する手法により● このような書き換えを同じコード断片として検出

全て解決...?

* 神谷年洋, "任意粒度機能モデルに基づくバイトコードからのコードクローン検出手法", 電子情報通信学会技術研究報告書, vol. 113, no. 24, pp. 43-48 (2013/05/10).

Page 10: 任意粒度機能モデルに基づくコードクローン検出手法の大規模プログラムの適用に向けた改善

2013/07/26 IPSJ SIGSS 2013 7年 月研究会

≒ 104倍

入力:15.2MiB(Java逆アセンブルコード)

中間ファイル:1.54GiB(n-gramデータ:後述)

出力:0.278MiB(コードクローン)

≒ 1/5600

バイト数

問題: 組み合わせ爆発

● 「任意の粒度」の「全実行パス」を生成

⇨ 容易に組み合わせ爆発を起こす– 小さなプログラムでも膨大な量の実

行パスを生成する

● 右は後述の実験の例– jEdit 5.0

● クラス数1122個● メソッド数6417個

– 本発表で説明する手法を活用して組み合わせ爆発を抑えた結果

Page 11: 任意粒度機能モデルに基づくコードクローン検出手法の大規模プログラムの適用に向けた改善

2013/07/26 IPSJ SIGSS 2013 7年 月研究会

任意粒度機能モデルに基づくコードクローン検出手法とは

● ソースコードのリファクタリングの機会を探すため● ソフトウェアのソースコード内の類似した機能を持つコード断片を検出

する

● 類似した機能の判定: 2つのコード断片で呼び出す手続きの列が同じである

ただし

● 任意の粒度: 手続きは入れ子になって定義される。任意の階層で一致すれば一致と判定する

● 全実行パス: プログラムのあらゆる実行を考えて、そのいずれかの実行で一致すれば一致と判定する

ただし、現実的な時間で実行できること

Page 12: 任意粒度機能モデルに基づくコードクローン検出手法の大規模プログラムの適用に向けた改善

2013/07/26 IPSJ SIGSS 2013 7年 月研究会

RQ

● 任意の粒度、全実行パスから同じ手続き呼び出し部分列を検出するコードクローン検出手法

● 組み合わせ爆発をしないように枝刈りを取り入れられるか– 大規模なプログラムに適用できるように

● ただし、興味深い対象を逃すことなく– 字面は異なるが機能は同じ(リファクタリングの適用対象になりそうな)

コードクローンを検出できるか

より正確には

Page 13: 任意粒度機能モデルに基づくコードクローン検出手法の大規模プログラムの適用に向けた改善

2013/07/26 IPSJ SIGSS 2013 7年 月研究会

任意の粒度の全実行パスを考慮するコードクローン検出手法

理想的(ナイーブ)な定式化

1. プログラムのエントリポイントから制御構造を辿る– 分岐 ⇨ 分岐の数だけ実行パスを分ける

– 手続き(m)の呼び出し ⇨ mを呼び出す実行パスと、mの定義の中を辿る実行パスに分ける

2. 特定されたすべての実行パスから、すべての一致 部分列を探す

3. 一致部分列をコードクローンとして出力するこれがどのように組み合わせ爆発するのか

Page 14: 任意粒度機能モデルに基づくコードクローン検出手法の大規模プログラムの適用に向けた改善

2013/07/26 IPSJ SIGSS 2013 7年 月研究会

Fizzbuzzの例から実行パスを作るFizzBuzz1.main()のfor文の中身

fizz() buzz() print()

fizz()

print()

buzz()

print()

buzz()

println()

Page 15: 任意粒度機能モデルに基づくコードクローン検出手法の大規模プログラムの適用に向けた改善

2013/07/26 IPSJ SIGSS 2013 7年 月研究会

Fizzbuzzの例から実行パスを作るmain()のfor文の中身

fizz() buzz() print()

print()

buzz()

println()

{fizz, println}

{{print}, println}

{{print, buzz}, println}

{{print, {print}}, println}

{buzz, println}

{{print}, println}

{print, println}

実行パスの総数= O((分岐 * 2^呼び出し) ^ 呼び出し階層)

fizz()

print()

buzz()

分岐

呼び出し

呼び出し階層

→ ∞

Page 16: 任意粒度機能モデルに基づくコードクローン検出手法の大規模プログラムの適用に向けた改善

2013/07/26 IPSJ SIGSS 2013 7年 月研究会

導入した枝刈り

● メソッドディスパッチの絞り込み (3.3節)● 実行パスの窓による取りつくし (3.2節)● ファンイン-ファンアウトクローンの除去 (3.3節)● ループに関するヒューリスティクス (3.4節)

Page 17: 任意粒度機能モデルに基づくコードクローン検出手法の大規模プログラムの適用に向けた改善

2013/07/26 IPSJ SIGSS 2013 7年 月研究会

実行パスの窓による取りつくし(3.2)

● すべての実行パスを作り、それらの任意の長さの部分列から一致している部分を探す

● 実行パス上の n-gram (固定長の部分列)から一致している部分を探す(「窓」)

● 実行パスを辿りながらn-gramを生成する(「窓」の取りつくし)– 実行パスを作った後でn-gram を生成する、ではなく

・・・のをやめて

Page 18: 任意粒度機能モデルに基づくコードクローン検出手法の大規模プログラムの適用に向けた改善

2013/07/26 IPSJ SIGSS 2013 7年 月研究会

「すべての実行パスを作る」

b1

s11 s12

b2

s21 s22

b3

s31 s32

b1

s11

b2

s21

b3

s31

b1

s12

b2

s21

b3

s31

b1

s11

b2

s22

b3

s31

b1

s12

b2

s22

b3

s31

b1

s11

b2

s21

b3

s32

b1

s12

b2

s21

b3

s32

b1

s11

b2

s22

b3

s32

b1

s12

b2

s22

b3

s32

Page 19: 任意粒度機能モデルに基づくコードクローン検出手法の大規模プログラムの適用に向けた改善

2013/07/26 IPSJ SIGSS 2013 7年 月研究会

「窓の取りつくし」

b1

s11 s12

b2

s21 s22

b3

s31 s32

分岐があることを記録しておく

b1

s11 s12

b2

s21 s22

b3

s31 s32

b1

s11 s12

b2

s21 s22

b3

s31 s32

分岐から初めて合流したら終わり b1

s11 s12

b2

s21 s22

b3

s31 s32

Page 20: 任意粒度機能モデルに基づくコードクローン検出手法の大規模プログラムの適用に向けた改善

2013/07/26 IPSJ SIGSS 2013 7年 月研究会

任意の粒度の全実行パスを考慮するコードクローン検出手法

現ツールの実装

1. プログラムのすべての手続きから制御構造を辿って n-gramを生成する

– 実行パスの窓による取りつくし(3.2)

2. 特定されたすべての n-gram を分類する

3. ある分類に2つ以上n-gramがあるものをコード クローンとして出力する

– ファンイン-ファンアウトクローンの除去(3.3)

Page 21: 任意粒度機能モデルに基づくコードクローン検出手法の大規模プログラムの適用に向けた改善

2013/07/26 IPSJ SIGSS 2013 7年 月研究会

ファンイン-ファンアウト クローンの除去(3.3)

a

m

a

m

a

m

a

m

b

n

m

p q

C.n D.n

・・・

・・・

c c

● いくつかの実行パスが途中で同じ箇所を通る– 手続きp, q, ・・・ が手続きmを呼

び出す

– 手続きmはC.n, D.n, ...のいずれかを呼び出す

⇨ 生成される n-gram {a,{b,{c}}} はすべて手続きmを通る

● そのようなコードクローン(FFクローン)をフィルタリングによって取り除く

≒ 自然言語処理でコーパスを使って自立語と付属語を特定する手法

ファンイン

ファンアウト

Page 22: 任意粒度機能モデルに基づくコードクローン検出手法の大規模プログラムの適用に向けた改善

2013/07/26 IPSJ SIGSS 2013 7年 月研究会

実験による評価

● (比較に用いた適用対象は1例のみ)● n = 4

実行パスの窓による取りつくし⇩

実行時間を約84倍短縮

ファンイン-ファンアウトクローンの除去

⇩コードクローンの数が約18分の1

Page 23: 任意粒度機能モデルに基づくコードクローン検出手法の大規模プログラムの適用に向けた改善

2013/07/26 IPSJ SIGSS 2013 7年 月研究会

int dragStart = xyToOffset(x,y,!(painter.isBlockCaretEnabled()|| isOverwriteEnabled()));

if(getSelectionCount() == 0 || multi)moveCaretPosition(dragStart,false);

GUIUtilities.showPopupMenu(popup,painter,x,y);

JEditTextArea.handlePopupTrigger:(Ljava/awt/event/MouseEvent;)V

Dimension size = popup.getPreferredSize();

Rectangle screenSize = getScreenBounds();

GUIUtilities.showPopupMenu:(Ljavax/swing/JPopupMenu; Ljava/awt/Component;IIZ)V

Rectangle bounds = GraphicsEnvironment. getLocalGraphicsEnvironment().

getMaximumWindowBounds();

GUIUtilities.getScreenBounds:()Ljava/awt/Rectangle;

int dragStart = xyToOffset(x,y,!(painter.isBlockCaretEnabled()|| isOverwriteEnabled()));

if(getSelectionCount() == 0 || multi)moveCaretPosition(dragStart,false);

showPopupMenu(popup,this,x,y,false);

TextArea.handlePopupTrigger:(Ljava/awt/event/MouseEvent;)V

Dimension size = popup.getPreferredSize();

Rectangle screenSize = GraphicsEnvironment.getLocalGraphicsEnvironment()

.getMaximumWindowBounds();

TextArea.showPopupMenu:(Ljavax/swing/JPopupMenu; Ljava/awt/Component;IIZ)V

図 4 jEdit から検出されたコードクローンの例 (1)Fig. 4 A sample code clone (1) detected from jEdit

検出されたコードクローンの例 (n=6)

呼び出しの深さが異なる

Page 24: 任意粒度機能モデルに基づくコードクローン検出手法の大規模プログラムの適用に向けた改善

2013/07/26 IPSJ SIGSS 2013 7年 月研究会

まとめ

● 大規模プログラムに適用することを目的とした● 任意粒度機能モデルに基づくコードクローン検出手法への

様々な枝刈り手法の導入を説明● 呼び出しの深さが異なるコード断片のコードクロー

ンの例を紹介

+ アルファ

Page 25: 任意粒度機能モデルに基づくコードクローン検出手法の大規模プログラムの適用に向けた改善

2013/07/26 IPSJ SIGSS 2013 7年 月研究会

● タイトルの「大規模プログラムへの適用に向けた」はどうなった?

● 最新の実装を、より大きなソースコード(6938個のクラス)に適用しました– n = 4

追補

プロダクト

1122 6417 104 372 534414 36 469 1305

1700 8888 192 530 1118364 68 574 3415

6938 34335 5956 1357 715282 79 1701 2875

ステップ1 ステップ2 クラス

(個)メソッド定義(個)

時間(秒)

メモリ(MiB)

生成 n-gram (個)

時間(秒)

メモリ(MiB)

検出クローン(クラス数)

JEdit 5.0(テキストエディタ)ArgoUML 0.28.1(UMLはモデリング)Vuze 5.0.0.0(BitTorrentクライアント)

Page 26: 任意粒度機能モデルに基づくコードクローン検出手法の大規模プログラムの適用に向けた改善

2013/07/26 IPSJ SIGSS 2013 7年 月研究会

研究の方向

● 小さなn-gramから段階的に伸長するように変更する– 例えば n = 4 → n = 8

– n-gram生成→分類→(n-gram再生成→分類)*● ≒たくさんあるオートマトン(すべての状態が初期状態となりうる)から共通の語を受

理するものを探す

● 曖昧な一致(順序の入れ替え、ギャップ)?– n-gramの段階的な伸長と整合性のあるアルゴリズム?

● シンボリック実行の導入?意味的な曖昧性の導入?– int ⇔ Integer

– /2 ⇔ >> 1 (メソッド呼び出し以外の命令も見ることを前提として)

– “ab” + “c” ⇔ “abc” (式の簡約をオンザフライに行う?)

Page 27: 任意粒度機能モデルに基づくコードクローン検出手法の大規模プログラムの適用に向けた改善

2013/07/26 IPSJ SIGSS 2013 7年 月研究会

最新の実装

● 論文以降さらに様々な最適化を導入しています– 分岐やジャンプを最適化

● ジャンプした直後にジャンプ→ジャンプ

– 上記を利用して、ループの検出ルーチンを改良

● 現在)ブロックを作って、ブロックに入る辺を監視する

● 以前)若いアドレスへのジャンプを「ループの戻り」とみなしていた

– 上記ブロック入り辺の監視を利用すれば「最大2回ループを回る」実行パスをたどることが可能

● まだ実装はしてません

– クラス改装を利用してメソッドディスパッチの解析を改善

● 現在)クラス階層とメソッド定義の情報を利用して、レシーバーが簡単に特定できる場合には、呼び出されるメソッドを限定する

– そのクラスが導出階層の末端でなくても、最適化可能

● 以前)クラスが導出の階層の末端であるか/ないかだけを利用していた

– そのクラスに属するメソッドの呼び出しはすべてそのクラスで定義しているメソッドとしていた

github.com/tos-kamiya/agec2 に公開予定