パターンマイニング技術を 用いたC言語プログラムからの コーディングパターン抽出 ○中村勇太1 崔恩瀞1 吉田則裕2 春名修介1 井上克郎1 1大阪大学 2名古屋大学 0:00~ それでは,パターンマイニング技術を用いたC言語プログラムからのコーディングパターン抽出と題しまして 大阪大学の中村が発表致します.
コーディングパターン 複数のモジュールに分散する定型的なコード[1] 守らなければいけないルールとして利用できる 例:ファイルのオープン・クローズ,例外処理など 守らなければいけないルールとして利用できる 例:fopen()を呼び出した後は必ずfclose()を呼び出す : fopen() fclose() : fopen() fclose() : fopen() fclose() まず,コーディングパターンについて説明します. コーディングパターンとは複数のモジュールに分散する定型的なコードを指します. 例えばC言語において複数モジュールに存在しているファイルのオープンとクローズを行うfopen()関数とfclose()関数の対応は コーディングパターンといえます.そして,例外処理のような定型的な処理もコーディングパターンの1つです. また,この例のようにオープンを行った後は必ずクローズしなければならない,あるいは例外が発生した場合は特定の処理を行わなければならないというように コーディングパターンは実装において守らなければいけないルールとして利用することができます. [1] 石尾ら.”シーケンシャルパターンマイニングを用いた コーディングパターン抽出”,情報処理学会論文誌(2009)
コーディングパターンの活用法 コーディングパターンに則った記述がされていないバグを含むコードが存在 開発者がコーディングパターンに基づいて ○コーディングパターン ×欠落 ×順序の誤り fopen() fclose() : fopen() : fclose() fopen() こうしたコーディングパターンの活用法としてはプログラム中のバグの検出が考えられます. 図の左側が抽出されたコーディングパターン(ルール)であり正しい記述だとします.例えばプログラム中にfopen()関数が呼び出されているにもかかわらずfclose()が記述されていない場合や fopen()とfclose()の順番に誤りがあればそれはバグとなります. 開発者は抽出されたコーディングパターンに基づいてプログラムを検査することでこうしたバグを見つけることができます. しかし,人が目で見てプログラム中のどれがコーディングパターンかを判断するのは難しいです. そこで,コーディングパターンの抽出を行う研究がいくつか行われてきました.ここではその1つを紹介します. 開発者がコーディングパターンに基づいて プログラムを検査し,バグを発見できる
関連研究 Javaプログラムからのコーディングパターン抽出[1] プログラムからメソッド呼び出し,制御構造を抽出 得られる要素列に対してパターンマイニング技術を適用 順序を考慮したパターンを見つけるシーケンシャルパターン マイニングを適用 石尾らはJavaプログラムを対象にコーディングパターンの抽出を行いました. 彼らの手法ではプログラムの振る舞いを理解するためにはメソッド呼び出しの列が有用であるとし, プログラムからメソッド呼び出しと制御構造を要素として取り出し,パターンマイニング技術の1つであるシーケンシャルパターンマイニングを適用してコーディングパターンの抽出を行っています. [1] 石尾ら.”シーケンシャルパターンマイニングを用いた コーディングパターン抽出”,情報処理学会論文誌(2009)
シーケンシャルパターンマイニング -概要- データ中に存在する,順序を考慮したパターンを 見つける 例:ユーザのWEBページのアクセス履歴から,よく閲覧されているページの順番を検出 入力は系列データベース,最小支持度(出現頻度) 出力は頻出系列パターン シーケンシャルパターンマイニングとはデータ中に存在する,順序を考慮したパターンを見つける技術で, 例えばユーザのWEBページのアクセス履歴から,よく閲覧されているページの順番検出に使われています. シーケンシャルパターンマイニングでは系列データーベースを入力にとり,データベース中に頻出するパターンを出力します.
シーケンシャルパターンマイニング -系列データベースと支持度- 複数の入力系列から構成される 各入力系列はIDとアイテム列を持つ 系列パターンPの支持度 系列パターンPを含む入力系列の数 例:系列パターン(c,a)は系列ID=1,2に含まれるため支持度は2 入力となる系列データベースは複数の入力系列から構成されます.入力系列はこの表のように,アイテムの列で構成され,それぞれの 入力系列にはIDが振られます. 系列ID アイテム列 1 a b c b a 2 b c d a b e 3 b b a c d e b 入力系列
シーケンシャルパターンマイニング -系列データベースと支持度- 複数の入力系列から構成される 各入力系列はIDとアイテム列を持つ 系列パターンPの支持度 系列パターンPを含む入力系列の数 例:系列パターン(c,a)は系列ID=1,2に含まれるため支持度は2 また,系列パターンの支持度とはその系列パターンを含む入力系列の数を表しています. 例えばこの表において系列パターン(c,a)は入力系列1と2に含まれています.この場合,この系列パターンの支持度は2となります. 系列ID アイテム列 1 a b c b a 2 b c d a b e 3 b b a c d e b
シーケンシャルパターンマイニング -頻出系列パターン- 指定した最小支持度を満たす系列パターン 系列長:系列パターンに含まれるアイテムの数 系列ID アイテム列 1 a b c b a 2 b c d a b e 3 a b a c d e b マイニングでは指定した最小支持度以上を満たす系列パターンを頻出系列パターンとして出力します. 例えば最小支持度2でマイニングを行ったとき,この表では支持度が2以上のパターンの一例として系列パターンB C Bが出力されます. B C Bは全ての入力系列に含まれるため,その支持度は3となります.また,系列パターンに含まれるアイテム数を系列長といいます. このB C Bだと系列長は3になります.以上がシーケンシャルパターンマイニングの入力と出力の説明です. 先ほど説明した関連研究は各関数から抽出したメソッド呼び出しと制御構造をアイテム列としてシーケンシャルパターンマイニングにより コーディングパターンの抽出を行いました. しかし,プログラムにはこの2つ以外の要素もあります.それが例えばジャンプ命令やプリプロセッサ命令です.一般的にこれらの命令はあまり 使われませんが,積極的にこれらの命令が使用されるプログラムがあります.それが組込みプログラムです. 最小支持度2でマイニングを行うと,一例として 系列パターン(b,c,b)(系列長3,支持度3)が出力される
組込みプログラムの特性 厳しい時間制約 ジャンプ命令,プリプロセッサ命令の多用 リアルタイム性 処理A 計算を正確に,時間内に完了することを保証する ジャンプ命令,プリプロセッサ命令の多用 処理A #ifdef 条件式 実行コード #else : #endif 組込みプログラムでは計算を時間内に正確に完了させることを保証するリアルタイム性を持つことが多いです. そのため,厳しい時間の制約が掛かります. これに対処するために組込みプログラムではジャンプ命令とプリプロセッサ命令が積極的に使われます. 実行時間の短縮を目的としてジャンプ命令が使われます.そして,組込みプログラムの開発においては 複数のハードウェアに対応可能なプログラムを記述する必要があります.それらを実行時に動的に切り替えようとすると 条件分岐の処理で時間が掛かってしまいます.そこでプリプロセッサ命令を用いてコンパイル前に 実行コードを切り替えることで実行時の条件分岐を減らします. (理想的には開発者がジャンプ命令を使わずともコンパイラ側が最適化をしてくれることが望ましいです. しかし,組込みプログラムの開発においては複数のコンパイラが存在しすべてが同じように理想的な最適化を行ってくれるとは 限りません.そのため,どのコンパイラにも対応できるように開発者がジャンプ文を記述するという配慮がなされます.) 実行コードの 切り替えによる 実行時間短縮 実行時間短縮 : goto文 処理B
研究動機 C言語プログラムからコーディングパターンを抽出 関連研究では組込みプログラムの特性を 考慮していない 高信頼性ソフトウェアである組込みプログラムの主な 開発言語 関連研究では組込みプログラムの特性を 考慮していない 本研究ではC言語プログラムからのコーディングパターン抽出を目的としました. これはC言語が高い信頼性が求められる組込みプログラムの主な開発言語だからであり, コーディングパターン抽出を行うことにより,信頼性の向上に繋がると考えました.そしてC言語プログラムからの抽出にあたって,組込みプログラムの主な開発言語であることを考慮する必要があります. つまり,先ほど説明したジャンプ命令やプリプロセッサ命令を組込みプログラムでは積極的に使われるということを考えなければいけません. しかし,関連研究の手法ではこれらを要素として考慮しておりません. (身の回りの機器に組込まれる組込みプログラムですが,例えば,自動車制御用プログラムや航空制御システムなどは不具合によっては人の命に係わる事故が 起こる可能性がありますし,事故ではなくても,製品に不具合があれば回収・修正を行う必要があります. そうするとコストがかかってしまい経済的な損失が発生してしまいます. このように高い信頼性が求められる組込みプログラムの開発言語であるC言語プログラムの) 特性を考慮してC言語プログラムから コーディングパターンを抽出する必要がある
研究概要 C言語プログラムからのコーディングパターン 抽出手法の提案 組込みプログラムへの適用実験及び評価 組込みプログラムの特性を考慮 コーディングパターンを抽出する手法を提案しました.さらに,手法を実際の組込みプログラムに適用し 得られたコーディングパターンをもとにその有用性について評価をしました. 7分
コーディングパターン抽出手法の概要 ステップ1 ステップ2 ステップ3 コーディング パターン抽出 結果の 絞り込み 要素抽出 絞り込み後のコーディングパターン プログラム 要素列 続いて本手法の説明をします.こちらは本手法の概要図です. 本手法は3つのステップから構成されています. ステップ1で入力プログラムからコーディングパターンを構成する要素を抽出し,ステップ2でその要素列をもとに コーディングパターンの抽出を行います.出力されるコーディングパターンの数は多く,開発者が手作業ですべてを確認することは困難です. そこで,ステップ3として結果の絞り込みを行います.これから各ステップについて説明していきます. ステップ1 ステップ2 ステップ3
ステップ1:構成要素の抽出 プログラムから各要素を抽出 マクロ呼び出し,関数呼び出し 制御構造 goto文,ラベル文,return文 fopen() CHECK() IF fgets() goto label END-IF label: fclose() fp = fopen(); CHECK(); if (flag) { fgets(); goto label; } label: fclose(fp); ステップ1ではプログラムからコーディングパターンを構成する各要素を抽出します. 図の左側はプログラムの一部,右側はステップ1によって得られる要素列を表しています. これから,抽出される各要素について説明していきます. 要素抽出
ステップ1:構成要素の抽出 プログラムから各要素を抽出 マクロ呼び出しや関数呼び出し 制御構造 goto文,ラベル文,return文 fopen() CHECK() IF fgets() goto label END-IF label: fclose() fp = fopen(); CHECK(); if (flag) { fgets(); goto label; } label: fclose(fp); 要素抽出 まず,関数呼び出しを要素として抽出します. ここでは引数などは無視して関数名のみを要素としています. さらに,C言語プログラムではマクロ定義された関数呼び出しも存在するためそちらも同様に名前のみを抽出します. (マクロ関数についてはマクロを展開しておりません.マクロ関数を展開した後のコードからコーディングパターンの抽出を行うよりも 識別しやすい名前のついたマクロ関数名で抽出を行ったほうが結果として出てくるルールがわかり易いものになると考えたからです.)
ステップ1:構成要素の抽出 プログラムから各要素を抽出 マクロ呼び出しや関数呼び出し 制御構造 goto文,ラベル文,return文 IF fopen() CHECK() IF fgets() goto label END-IF label: fclose() fp = fopen(); CHECK(); if (flag) { fgets(); goto label; } label: fclose(fp); また,そのほかの要素として制御構造を抽出します. こちらの図のように,if文であればその始まりと終わりを表す特別な要素が抽出されます. また,for文やwhile文といったループ文の場合はLOOPとEND-LOOPという要素が抽出されます. (例外処理などでは制御文と関数呼び出しがセットになっていることが経験上多かったので, コーディングパターンにもこれらの要素が表れるのではないかと考えました.) 要素抽出
ステップ1:構成要素の抽出 プログラムから各要素を抽出 マクロ呼び出しや関数呼び出し 制御構造 goto文,ラベル文,return文 fopen() CHECK() IF fgets() goto label END-IF label: fclose() fp = fopen(); CHECK(); if (flag) { fgets(); goto label; } label: fclose(fp); さらに,組込みプログラムではジャンプ命令が多用されるという考えに基づいてgoto文,ラベル文を要素として抽出しました. また,ジャンプ命令によって実行の流れが複雑化します.そこで処理の流れを明確にする必要があると考え,return文を要素として取り出しました. 以上,ここまでがステップ1のコーディングパターンを構成する要素の抽出です.ステップ2ではこれをもとにコーディングパターンの抽出を行います. 要素抽出
ステップ2:コーディングパターン抽出(1/3) シーケンシャルパターンマイニングを利用 順序を考慮する方がバグ検出において優秀[2] 使用アルゴリズムはSPADE[3] 最小支持度として10を指定 10個以上の関数に含まれるコーディングパターンを出力 ステップ2では抽出された要素列からコーディングパターンの抽出を行います. 抽出は始めに説明した,順番を考慮したパターンを見つけるシーケンシャルパターンマイニングを用いて行います. パターンの順番性を考慮しないパターンマイニング技術としてアイテムセットマイニングというマイニング技術がありますが, バグ検出の精度においては順番性を考慮するシーケンシャルパターンマイニングのほうが優れているという論文が出ております. したがって本研究ではシーケンシャルパターンマイニングを用いています. 本手法では使用アルゴリズムとしてSPADEを,そして最小支持度を10と指定してコーディングパターンの抽出を行います. [2] H.Kagdi et al.” Comparing Approaches to Mining Source Code for Call-Usage Patterns”, in Proc.of MSR 2007(2007) [3] Mohammed J. Zaki.” SPADE: An Efficient Algorithm for Mining Frequent Sequences”, Machine Learning(2001)
ステップ2:コーディングパターン抽出(2/3) 入力となる系列データベースはステップ1の 要素列を基に作成 系列IDはプログラム中の各関数に割り当て アイテム列は各関数中の要素列に対応 系列ID アイテム列 1 IF fopen() END-IF fgets() fclose() 2 fopen() goto label fgets() label: fclose() 3 fopen() IF fgets() return END-IF fclose() 4 fopen() fgets() fclose() 入力となる系列データベースは入力系列から構成されることはすでに説明しました.ここでは, プログラム中の各関数ごとに系列IDを割り当て,その関数中の要素列をアイテム列に対応させています. 例えば,プログラムにおいて1番目の関数から抽出される要素は系列ID1の行にその順番で記述されます.
ステップ2:コーディングパターン抽出(3/3) 例:最小支持度2でシーケンシャルパターン マイニング 系列ID アイテム列 1 IF fopen() END-IF fgets() fclose() 2 fopen() goto label fgets() label: fclose() 3 fopen() IF fgets() return END-IF fclose() 4 fopen() fgets() fclose() そしてこの系列データベースを基にコーディングパターンの抽出が行われます. 例えば最小支持度2でマイニングを行うと,一例としてfopen(),fgets(),fclose()という支持度が4のコーディングパターンが抽出されます. もちろん,このほかにも最小支持度2を満たすコーディングパターンは存在します. こうしてプログラムの全関数から抽出した要素と最小支持度からコーディングパターンが抽出されます. しかし,パターンマイニングの結果出力されるコーディングパターンは膨大な数となり,開発者がすべてを確認することはできません. そこでステップ3では抽出されたコーディングパターンの絞り込みを行います. fopen() fgets() fclose()という系列長が3, 支持度が4のコーディングパターンが抽出される
ステップ3:結果の絞り込み -コーディングパターンの除外- コーディングパターンとしての正確性 制御構造及びジャンプ命令の対応関係が取れていない 場合は除外 関数呼び出しの数 関数呼び出しの数が2つ未満の場合は除外 fopen() IF fclose() fopen() label: fclose() IF goto label END-IF label: まず,左の図のIFがあるにもかかわらず対応するEND-IFがないような制御構造の対応関係が取れていない場合や 真ん中の図のようにジャンプ文とラベルの対応関係が取れていないコーディングパターンはその正確性を失っているため除外しました. (コーディングパターンがルールを表すことを考えると,これらのコーディングパターンはその正確性を失っているため ルールとしての価値がないと判断しました.) また,右の図のように関数呼び出しの数が2つ未満のコーディングパターンは開発者にとって重要ではないと判断し除外しました. (open()を呼んだあとにclose()を呼び出すというルール,ある処理の結果に基づいて例外処理を行うというルール,のように ルールは処理と処理の対応によるものが多いです.したがって関数呼び出しが1つの場合ではルールを表しているとは 言い難いと判断し,関数呼び出しが2つ未満のコーディングパターンは除外しました.) END-IFがない goto文が ない 関数呼び出しの数が2つ未満
ステップ3:結果の絞り込み -マクロの考慮(1/3)- ジャンプ命令の対応関係について マクロ関数がgoto文を含んでいる場合に対応 コーディングパターン fopen() CHECK() fgets() label: fclose() ジャンプ命令の対応関係が 取れていないため除外される また,ジャンプ命令の対応関係を見るにあたり,図のように一見するとジャンプ命令の対応関係が取れていないために 除外されるコーディングパターンでも
ステップ3:結果の絞り込み -マクロの考慮(2/3)- ジャンプ命令の対応関係について マクロ関数がgoto文を含んでいる場合に対応 コーディングパターン マクロ関数の定義 fopen() CHECK() fgets() label: fclose() #define CHECK() do { : goto label; } while (0) マクロ関数がジャンプ文を含んでいて実は対応関係が取れていた,という場合がありました.このままでは本来ならば正確なコーディングパターンが 間違って除外されてしまいます.そこで,マクロ関数が存在する場合は同一ディレクトリに存在するヘッダファイルをみてgoto文が含まれているか調べ その情報をもとに正しい絞り込みを行いました. 実際は対応関係が取れている
ステップ3:結果の絞り込み -マクロの考慮(3/3)- #ifdef命令への対応 ラベルが再定義されている場合が存在 マクロ関数の定義 : #ifdef 条件式 define label labelA #else define label labelB #endif #define CHECK() do { : goto label; } while (0) さらに,そのジャンプ先のラベルが再定義されている場合があります. #ifdef命令を使って,条件によってジャンプ先を切り替えるということです. こうした場合が存在することも踏まえて,同じようにジャンプ命令の対応関係による正しい絞り込みを行いました.
ステップ3:結果の絞り込み -極大化- 極大化 部分パターンの中から系列長が最大のパターンを選択 系列長1のパターン 関数A : fopen() : fgets() fclose() 関数C : fopen() : fgets() fclose() fopen() fgets() fclose() コーディング パターン抽出 系列長2のパターン fopen() fgets() fopen() fclose() fgets() fclose() … また,絞り込みの最後に極大化を行います. 例えばこの図のようにいくつか関数があってどの関数にもopen(),gets(),close()の3つの関数呼び出しが記述されているとします. この場合の3つの呼び出しはコーディングパターンになるのですが,パターンマイニングアルゴリズムを適用すると この系列長3のパターンの他にも系列長1,系列長2のパターンが結果として出てきます. こうした部分パターンは除外し,最大長のパターンのみを結果として出力するようにしています. (部分パターンかどうかの判断はパターンの支持度が同じかどうかで見ています.同じ出現頻度でかつそれよりも長いパターンがあれば そちらを選択するということです.) ここまでの要素抽出,コーディングパターン抽出,絞り込みの3ステップが本研究の手法となります. 要素抽出においてジャンプ命令を,絞り込みにおいてプリプロセッサ命令を考慮した手法となっています. 8分 系列長3のパターン fopen() fgets() fclose() 系列長が最大の パターンを選択
適用実験 -概要- 提案手法の有効性を確認するための適用実験 提案手法の有効性,改善点を考察 実際の組込みプログラムに対して提案手法を適用し, 以下の項目を調査 コーディングパターンの数 計算速度 仕様に基づくコーディングパターンの評価 提案手法の有効性,改善点を考察 ここからは手法の適用実験の説明をしたいと思います. 本研究では,組込みプログラムの主な開発言語であることを考慮してジャンプ命令やプリプロセッサ命令を踏まえたコーディングパターンの抽出を行う手法を提案しました. その手法の有効性を確認するために,実際の組込みプログラムに対して手法を適用しコーディングパターンの抽出を行いました. 適用実験ではコーディングパターンがどれほど抽出されるか,抽出に掛かる時間はどの程度か調査しました. また,仕様に基づいてコーディングパターンの評価を行い,これらの結果から手法の有効性と改善点を考察しました.
適用対象 2種類の組込みプログラム,計6つ ATK2[4] Linuxカーネルソース(v4.0-rc1) TOPPERSプロジェクトが開発した自動車制御用の リアルタイムオペレーティングシステム(RTOS) 4つのリリース(SC1,SC3,SC1MC,SC3MC) Release 1.3.0 1.2.1 1.3.1 1.2.1 Linuxカーネルソース(v4.0-rc1) drivers/pci:PCI仮想ドライバのためのプログラム arch/arm :ARMアーキテクチャ固有のカーネルプログラム 今回の実験に用いた組込みプログラムの説明をします. 1つはATK2です.これはTOPPERSプロジェクトが公開しているオープンソースソフトウェアの1つで,自動車制御用の リアルタイムOSプログラムです.今回はSC1,SC3,SC1MC,SC3MCという4つのリリースを用いて実験を行いました. また,同じくオープンソースソフトウェアであるLinuxカーネルソースからも2つのプログラムを 対象として選択しました.1つはシステム上のデバイスドライバが置かれているdriversディレクトリから,PCI仮想ドライバのためのプログラムを選びました. もう1つはARMアーキテクチャ固有のカーネルプログラムを選択しました. デバイスドライバはハードウェアを制御するという意味で一種の組込みプログラムだといえます.また,archディレクトリにはハードウェアアーキテクチャに依存する 固有のプログラムが置かれています.こうしたプログラムもハードウェアを動作させるためのプログラムなので1つの組込みプログラムであるといえます.なので これら2つのプログラムも今回対象に加えました. [4] TOPPERSプロジェクト https://www.toppers.jp/
適用対象 -規模- 各プログラムの規模は以下の通り .cファイル数,関数の数,プログラムの総行数(LOC) 対象名 .cファイルの数 ATK2/SC1 12 81 4,620 ATK2/SC1MC 17 131 7,726 ATK2/SC3 16 134 7,698 ATK2/SC3MC 19 172 10,244 Linux/pci 30 991 24,441 Linux/arm 61 738 18,672 こちらの表は6つのプログラムの規模を表しています. 抽出に用いたcファイルの数,そこに含まれる関数の数,そしてプログラムの総行数が順に書かれています.
抽出されたコーディングパターンの数 抽出数と各絞り込みを適用後のコーディング パターンの数 開発者が手作業で確認できる数にまで削減 対象名 抽出数と各絞り込みを適用後のコーディング パターンの数 開発者が手作業で確認できる数にまで削減 対象名 抽出数 絞り込み後 (関数呼び出し) (制御構造) (ラベル) 極大化 後 ATK2/SC1 409K 393K 258K 9.03K 29 ATK2/SC1MC 176M 175M 172M 154K 240 ATK2/SC3 157K 150K 9.79K 3.64K 64 ATK2/SC3MC 343M 342M 341M 274K 511 Linux/pci 493K 991 296 197 Linux/arm 3.20K 17 14 7 こちらの表は抽出されたコーディングパターンの数と,ステップ3で行ったそれぞれの絞り込み後のコーディングパターンの数を表しています. KとMはそれぞれ一千,百万という単位を表しています. 抽出を行った直後のコーディングパターンの数は非常に多く,SC3MCでは3千万近く出力されています. このままでは確認が困難ですが,絞り込みによってその数が減少していることが分かります. 最終的な抽出結果は極大化を行った後のコーディングパターンの数ですが,いずれもその数は少なく 開発者が現実的な時間で確認することができる数字となっています.
計算速度 各ステップの所要時間を測定 要素抽出,パターンマイニング,絞り込みの3ステップ 対象名 ステップ1 ステップ2 ステップ3 合計時間 ATK2/SC1 0.0930秒 3.06秒 2.14秒 5.29秒 ATK2/SC1MC 0.0780秒 81.2秒 1.1秒 82.4秒 ATK2/SC3 0.108秒 4時間46分 74.3秒 4時間47分 ATK2/SC3MC 11時間1分 148秒 11時間3分 Linux/pci 0.158秒 376秒 2.12秒 378秒 Linux/arm 0.141秒 19.3秒 0.313秒 19.6秒 また,こちらは手法の各ステップの所要計算時間を示した表となっています. ほとんどのプログラムでは秒オーダーで終わっていますが,SC3では4時間,SC3MCについては半日ほど掛かっています. そして特にパターンマイニングのステップに時間が掛かっていることが分かります.
コーディングパターンの評価 -概要- ATK2の各プログラムのコーディングパターンに 対して系列長の上位5個,計20個を選択 4つのリリース×5個 コーディングパターンがATK2の仕様を反映して いるか確認 対象の内,ATK2についてはTOPPERSが外部仕様書を公開しています.そこで,コーディングパターンの評価としてATK2の各プログラムから抽出されたコーディングパターンに対して 系列長の上位5つ,計20個を選択しTOPPERS/ATK2の仕様がそれらのコーディングパターンに表れているか確認しました. (前提として,プログラムは正しい仕様書通りに正しく書いてあるとします.(何度もテストされてるはず・・・))
コーディングパターンの評価 -結果- 結果 20個中19個が仕様を反映したコーディングパターンで あることを確認 20個中19個が仕様を反映したコーディングパターンで あることを確認 コーディングパターンを今後の開発で利用していくことが可能だと判断 次回以降の開発においてコーディングパターンと比較することで,プログラム中のバグを検出 その結果,20個中19個のコーディングパターンが仕様を含んだコーディングパターンであることを確認し,これらのコーディングパターンを今後の開発で 利用していくことが可能だと判断しました.例えば,次回以降のプロジェクトの開発において抽出されたコーディングパターンを 用いてバグの検出に役立てることが考えられます.次に,実際にATK2の仕様がどうなっているか,そしてそれがプログラムにどう表れているか, 抽出されたコーディングパターンはどうなっているのかをお見せしたいと思います.
ATK2の仕様 ATK2のRTOSが提供する機能(外部仕様書[5]より) 割込み処理 エラー処理(エラーハンドリング) 割込みの禁止,許可操作(組で使用する必要がある) エラー処理(エラーハンドリング) OSが提供するシステムサービスはエラーチェックを行う (割込み管理,アラーム制御,カウンタ制御など) OSが提供するサービス内で発生したエラーの処理(ハンドリング) まず,ATK2の仕様についてですが,外部仕様書にはATK2のRTOSが提供する機能の一覧が記されています. その中の一部として割込み処理,エラー処理があります.割込み処理では,他からの割込みを禁止したり逆に割込みを 許可するという操作を提供しています.そして,これらの操作は組で使用しなければならないと記述してあります. また,アラームの制御やタスク管理,カウンタ制御などのシステムサービスはエラーチェックを行います.エラーが発生した場合は 対応するエラー処理が行われます. 続いて,実際のプログラムにこれらの仕様が表れていることをお見せします. [5]”ATK2 外部仕様書”, https://www.toppers.jp/docs/tech/ATK2-0010_ATK2_spec_100.pdf
ATK2のプログラムの一部 -割込みの禁止,許可操作- // アラームの状態参照 StatusType GetAlarm(AlarmType AlarmID, TickRefType Tick) { : x_nested_lock_os_int(); // カウンタの現在値を取得 curval = get_curval(p_cntcb, CNTID(p_cntcb)); *Tick = diff_tick(p_almcb->cntexpinfo.expiretick, curval, p_cntcb->p_cntinib->maxval2); x_nested_unlock_os_int(); } 他からの割込みを禁止する 割込みの操作はプログラム上ではこのように実現されています.Lock関数で他の処理からの割込みを禁止し, メインとなる処理を実行した後で割込みを許可しています.また,仕様通り,ちゃんと組になっているのが分かります. 他からの割込みを 許可する
ATK2のプログラムの一部 -エラーチェック- //アラームの状態参照 StatusType GetAlarm(AlarmType AlarmID, TickRefType Tick) { : LOG_GETALM_ENTER(AlarmID); CHECK_DISABLEDINT(); CHECK_CALLEVEL(CALLEVEL_GETALARM); CHECK_ID(AlarmID < tnum_alarm); CHECK_PARAM_POINTER(Tick); p_almcb = get_almcb(AlarmID); p_cntcb = p_almcb->p_alminib->p_cntcb; x_nested_lock_os_int(); } こちらはエラーチェックを行っている部分です.アラームの状態参照というサービス内で各種エラーチェックを行っているのが分かります. これは割込み可能かどうかのチェックやオブジェクトのIDに間違いはないかというチェックを行っています. システムサービス内の エラーチェック関数群
ATK2のプログラムの一部 -エラーハンドリング- : d_exit_no_errorhook: x_nested_unlock_os_int(); exit_no_errorhook: LOG_GETALM_LEAVE(ercd, Tick); return(ercd); #ifdef CFG_USE_ERRORHOOK exit_errorhook: x_nested_lock_os_int(); d_exit_errorhook: call_errorhook(ercd, OSServiceId_GetAlarm); goto d_exit_no_errorhook; #endif } エラーが発生した場合は エラーハンドリングを行う エラー処理はこのように実現されています. 実際に,エラーフック関数が呼び出されていたりとエラー処理の仕様を表したプログラムとなっております.
仕様を表すコーディングパターン プログラム名:ATK2/SC1 支持度:14 系列長:13 エラーチェック 割込み処理 エラー ハンドリング CHECK_DISABLEDINT() CHECK_CALLEVEL() CHECK_ID() x_nested_lock_os_int() d_exit_no_errorhook: x_nested_unlock_os_int() exit_no_errorhook: return exit_errorhook: call_errorhook() goto エラーチェック goto文 割込み処理 エラー ハンドリング 実際に抽出されたコーディングパターンがこちらです.これはATK2SC1の中でも 系列長が最大のコーディングパターンを選択しました. 先ほど説明した各仕様を含んだコーディングパターンになっているのが分かります. プログラム名:ATK2/SC1 支持度:14 系列長:13
Linuxカーネルソースからの コーディングパターン pci_read_config_word() pci_write_config_word() Linux/pciより,支持度48のコーディングパターン raw_spin_lock_irqsave() raw_spin_lock_irqstore() そして,Linuxカーネルソースから抽出されたコーディングパターンの一例はこちらになります. Readとwrite,saveとstoreという対応関係のある名前の関数が要素となっています. Linux/armより,支持度25のコーディングパターン
考察 ジャンプ命令,プリプロセッサ命令の有効性 実験対象を増やして手法が有効な場合を 明らかにする必要がある ATK2のコーディングパターンは2命令を含んでいる Linuxカーネルソース(pci,arm)のコーディングパターンは 含んでいない (プログラム中には存在) これらの結果を踏まえてジャンプ命令とプリプロセッサ命令を考慮したことの有効性について考察を行いました. ATK2については先ほどのコーディングパターンの例のように,評価により仕様を反映していることが分かりました.これらがラベルを含んでいることから, 有効性はあったと考えられます.その一方,Linuxカーネルソースの内今回用いたpciとarmからはプログラム中にはジャンプ命令を含んでいるものの, コーディングパターンにはそれらの要素が含まれていなかったので,今後さらに調査を行って,手法が有効な場合とそうでない場合を把握し,その境界について明らかにしていく必要があります. 実験対象を増やして手法が有効な場合を 明らかにする必要がある
今後の課題 -計算速度の改善- 計算速度の改善 解決案 コーディングパターンが多いプログラムでは計算に時間が掛かる パターンマイニングに掛かる時間が最も多い 解決案 パターンマイニングを並列処理化 今後の課題としてまず1つが計算速度の改善です. コーディングパターンの数が多いほどその抽出に掛かる時間が多くなるため プログラムのサイズを大きくした場合,非常に多くの時間が掛かると思われます. これに対してはパターンマイニングの処理を並列化することで計算速度を改善することを考えています. また,今回使用したアルゴリズムとは別のアルゴリズムでの実験を行い,計算速度に変化があるか調べてみたいと思います.
今後の課題 -コーディングパターンのグループ化- 同じ機能を表す類似コーディングパターンが多い 例:エラーチェック関数の差異 CHECK_DISABLEDINT() CHECK_CALLEVEL() CHECK_ID() x_nested_lock_os_int() : CHECK_DISABLEDINT() CHECK_CALLEVEL() x_nested_lock_os_int() : … また,今回は類似したコーディングパターンが多く抽出されました. 例えば先ほどのコーディングパターンだと,関数によってはチェック関数の数が変動する場合があります.そうしたコーディングパターンは1つにまとめることで 開発者が確認しやすくなると考えられます. 1つのコーディングパターン集合に
まとめ C言語プログラムからコーディングパターンを抽出 今後の課題 組込みプログラムの特性を考慮 計算速度の改善 コーディングパターンのグループ化 実験対象の拡大 まとめです.本研究では組込みプログラムの特性を考慮してC言語プログラムからコーディングパターンを抽出する手法を提案しました. 今後の課題につきましては先ほど述べたとおり,計算時間の改善やコーディングパターンのグループ化,実験の対象を増やすことが 挙げられます.さらに,他のアプローチとの比較にも興味があります.以上で発表を終わります.ご清聴ありがとうございました.