(57)【要約】【課題】プログラム実行時のコールフローに関する情報をプログラムの実行速度の低下を抑制しつつ確実に取得する技術を提供する。【解決手段】プローブ挿入装置は、対象プログラムを構成する手続単位毎に、呼出形態種と呼出構成とを含む制御構文データを取得する取得手段と、上記制御構文データで示される複数の手続単位の中の、順次実行を示しかつ呼出構成の被呼メソッドリストに手続単位自身を含まない手続単位である順次実行メソッドと、該順次実行メソッドの当該被呼メソッドリストに含まれるメソッドであって内部でメソッド呼び出しを行わない最下位メソッドとを除外した残りから、コールフロー情報を得るためのプローブ挿入対象を特定する特定手段と、特定されたプローブ挿入対象に対してプローブを挿入するプローブ挿入手段と、を有する。【選択図】図２
2014056539.tif 000002
【特許請求の範囲】
【請求項１】
メソッド、分岐フロー毎にメソッドを呼び出す分岐手続単位、及び、ループ中でメソッドを呼び出すループ手続単位に対応する、対象プログラムを構成する手続単位毎に、該手続単位内部でのメソッドの呼び出し形態を、順次実行、分岐、又は、ループで表す呼出形態種と、該手続単位内部の処理を、呼び出される少なくとも１つのメソッドを含む被呼メソッドリスト、該分岐手続単位、及び、該ループ手続単位の少なくとも１つを用いて表す呼出構成と、を含む制御構文データを取得する構文取得手段と、
前記対象プログラムの開始点となるメソッドから実行順に沿って前記手続単位毎に前記制御構文データを参照することにより、前記制御構文データで示される複数の手続単位の中の、順次実行を示しかつ前記被呼メソッドリストに手続単位自身を含まない手続単位である順次実行メソッドと、該順次実行メソッドの前記被呼メソッドリストに含まれるメソッドであって内部でメソッド呼び出しを行わない最下位メソッドを除外した残りから、コールフロー情報を得るためのプローブ挿入対象を特定する対象特定手段と、
前記対象特定手段により特定された前記プローブ挿入対象に対してプローブを挿入するプローブ挿入手段と、
を備えるプローブ挿入装置。
【請求項２】
前記対象特定手段は、前記分岐手続単位内で呼び出されるメソッドと、再帰呼び出しを行うメソッドと、前記ループ手続単位内で呼び出されるメソッドと、複数のメソッドから呼び出されるメソッドを呼び出すメソッドとを前記プローブ挿入対象として特定するか、又は、前記分岐手続単位内で呼び出されるメソッドと、再帰呼び出しを行うメソッドを呼び出すメソッドと、前記ループ手続単位を持つメソッドと、複数のメソッドから呼び出されるメソッドを呼び出すメソッドとを前記プローブ挿入対象として特定する、
請求項１に記載のプローブ挿入装置。
【請求項３】
前記対象特定手段は、
前記手続単位の前記被呼メソッドリストに含まれるメソッドが他の手続単位の被呼メソッドリストに含まれるか否かにより、前記手続単位を、前記複数のメソッドから呼び出されるメソッドを呼び出すメソッドとして特定する第１判定手段と、
前記手続単位の前記被呼メソッドリストに該手続単位を含むメソッドが含まれるか否かにより、前記手続単位を前記再帰呼び出しを行うメソッドとして特定するか、又は、前記手続単位を前記被呼メソッドリストに含む手続単位を、前記再帰呼び出しを行うメソッドを呼び出すメソッドとして特定する第２判定手段と、
前記呼出形態種が分岐を示す前記手続単位の前記被呼メソッドリストに含まれる他のメソッドを前記分岐手続単位内で呼び出されるメソッドとして特定する第３判定手段と、
前記呼出形態種がループを示す前記手続単位の前記被呼メソッドリストに含まれる他のメソッドを前記ループ手続単位内で呼び出されるメソッドとして特定するか、又は、前記呼出形態種がループを示す前記手続単位を含むメソッドを前記ループ手続単位を持つメソッドとして特定する第４判定手段と、
を含む、
請求項２に記載のプローブ挿入装置。
【請求項４】
前記制御構文データに含まれる手続単位毎の被呼メソッドリストを参照することにより、各手続単位に関する前記プローブ挿入対象を含まないネスト段数をそれぞれカウントするカウント手段と、
前記カウント手段によりカウントされたネスト段数と所定閾値との比較により、該ネスト段数を持つ手続単位を前記プローブ挿入対象に追加する挿入対象追加手段と、
を更に備える請求項１から３のいずれか１項に記載のプローブ挿入装置。
【請求項５】
前記対象特定手段は、
前記制御構文データ内で特定された前記各プローブ挿入対象について、マーク情報をそれぞれ付加することにより、拡張制御構文データを生成する拡張構文生成手段、
を更に含み、
前記プローブ挿入手段は、前記拡張構文生成手段により生成される前記拡張制御構文データの前記マーク情報に基づいて、前記プローブの挿入位置を決定する、
請求項１から４のいずれか１項に記載のプローブ挿入装置。
【請求項６】
前記対象プログラムのソースコード又は実行コードを構文解析することにより、前記制御構文データを生成する構文抽出手段、
を更に備える請求項１から５のいずれか１項に記載のプローブ挿入装置。
【請求項７】
コンピュータが、
メソッド、分岐フロー毎にメソッドを呼び出す分岐手続単位、及び、ループ中でメソッドを呼び出すループ手続単位に対応する、対象プログラムを構成する手続単位毎に、該手続単位内部でのメソッドの呼び出し形態を、順次実行、分岐、又は、ループで表す呼出形態種と、該手続単位内部の処理を、呼び出される少なくとも１つのメソッドを含む被呼メソッドリスト、該分岐手続単位、及び、該ループ手続単位の少なくとも１つを用いて表す呼出構成と、を含む制御構文データを取得し、
前記対象プログラムの開始点となるメソッドから実行順に沿って前記手続単位毎に前記制御構文データを参照することにより、前記制御構文データで示される複数の手続単位の中の、順次実行を示しかつ前記被呼メソッドリストに手続単位自身を含まない手続単位である順次実行メソッドと、該順次実行メソッドの前記被呼メソッドリストに含まれるメソッドであって内部でメソッド呼び出しを行わない最下位メソッドを除外した残りから、コールフロー情報を得るためのプローブ挿入対象を特定し、
前記特定されたプローブ挿入対象に対してプローブを挿入する、
ことを含むプローブ挿入方法。
【請求項８】
前記プローブ挿入対象の特定は、前記分岐手続単位内で呼び出されるメソッドと、再帰呼び出しを行うメソッドと、前記ループ手続単位内で呼び出されるメソッドと、複数のメソッドから呼び出されるメソッドを呼び出すメソッドとを前記プローブ挿入対象として特定するか、又は、前記分岐手続単位内で呼び出されるメソッドと、再帰呼び出しを行うメソッドを呼び出すメソッドと、前記ループ手続単位を持つメソッドと、複数のメソッドから呼び出されるメソッドを呼び出すメソッドとを前記プローブ挿入対象として特定する、
請求項７に記載のプローブ挿入方法。
【請求項９】
前記コンピュータが、
前記手続単位の前記被呼メソッドリストに含まれるメソッドが他の手続単位の被呼メソッドリストに含まれるか否かにより、前記手続単位を、前記複数のメソッドから呼び出されるメソッドを呼び出すメソッドとして特定し、
前記手続単位の前記被呼メソッドリストに該手続単位を含むメソッドが含まれるか否かにより、前記手続単位を前記再帰呼び出しを行うメソッドとして特定するか、又は、前記手続単位を前記被呼メソッドリストに含む手続単位を、前記再帰呼び出しを行うメソッドを呼び出すメソッドとして特定し、
前記呼出形態種が分岐を示す前記手続単位の前記被呼メソッドリストに含まれる他のメソッドを前記分岐手続単位内で呼び出されるメソッドとして特定し、
前記呼出形態種がループを示す前記手続単位の前記被呼メソッドリストに含まれる他のメソッドを前記ループ手続単位内で呼び出されるメソッドとして特定するか、又は、前記呼出形態種がループを示す前記手続単位を含むメソッドを前記ループ手続単位を持つメソッドとして特定する、
ことを更に含む請求項８に記載のプローブ挿入方法。
【請求項１０】
前記コンピュータが、
前記制御構文データに含まれる手続単位毎の被呼メソッドリストを参照することにより、各手続単位に関する前記プローブ挿入対象を含まないネスト段数をそれぞれカウントし、
前記カウントされたネスト段数と所定閾値との比較により、該ネスト段数を持つ手続単位を前記プローブ挿入対象に追加する、
ことを更に含む請求項７から９のいずれか１項に記載のプローブ挿入方法。
【請求項１１】
前記コンピュータが、
前記制御構文データ内で特定された前記各プローブ挿入対象について、マーク情報をそれぞれ付加することにより、拡張制御構文データを生成する、
ことを更に含み、
前記プローブの挿入は、前記拡張制御構文データの前記マーク情報に基づいて、前記プローブの挿入位置を決定する、
請求項７から１０のいずれか１項に記載のプローブ挿入方法。
【請求項１２】
前記コンピュータが、
前記対象プログラムのソースコード又は実行コードを構文解析することにより、前記制御構文データを生成する、
ことを更に含む請求項７から１１のいずれか１項に記載のプローブ挿入方法。
【請求項１３】
コンピュータにプローブ挿入方法を実行させるプログラムであって、
前記プローブ挿入方法は、
メソッド、分岐フロー毎にメソッドを呼び出す分岐手続単位、及び、ループ中でメソッドを呼び出すループ手続単位に対応する、対象プログラムを構成する手続単位毎に、該手続単位内部でのメソッドの呼び出し形態を、順次実行、分岐、又は、ループで表す呼出形態種と、該手続単位内部の処理を、呼び出される少なくとも１つのメソッドを含む被呼メソッドリスト、該分岐手続単位、及び、該ループ手続単位の少なくとも１つを用いて表す呼出構成と、を含む制御構文データを取得し、
前記対象プログラムの開始点となるメソッドから実行順に沿って前記手続単位毎に前記制御構文データを参照することにより、前記制御構文データで示される複数の手続単位の中の、順次実行を示しかつ前記被呼メソッドリストに手続単位自身を含まない手続単位である順次実行メソッドと、該順次実行メソッドの前記被呼メソッドリストに含まれるメソッドであって内部でメソッド呼び出しを行わない最下位メソッドを除外した残りから、コールフロー情報を得るためのプローブ挿入対象を特定し、
前記特定されたプローブ挿入対象に対してプローブを挿入する、
ことを含むプログラム。
【請求項１４】
前記プローブ挿入対象の特定は、前記分岐手続単位内で呼び出されるメソッドと、再帰呼び出しを行うメソッドと、前記ループ手続単位内で呼び出されるメソッドと、複数のメソッドから呼び出されるメソッドを呼び出すメソッドとを前記プローブ挿入対象として特定するか、又は、前記分岐手続単位内で呼び出されるメソッドと、再帰呼び出しを行うメソッドを呼び出すメソッドと、前記ループ手続単位を持つメソッドと、複数のメソッドから呼び出されるメソッドを呼び出すメソッドとを前記プローブ挿入対象として特定する、
請求項１３に記載のプログラム。
【請求項１５】
前記プローブ挿入方法は、
前記手続単位の前記被呼メソッドリストに含まれるメソッドが他の手続単位の被呼メソッドリストに含まれるか否かにより、前記手続単位を、前記複数のメソッドから呼び出されるメソッドを呼び出すメソッドとして特定し、
前記手続単位の前記被呼メソッドリストに該手続単位を含むメソッドが含まれるか否かにより、前記手続単位を前記再帰呼び出しを行うメソッドとして特定するか、又は、前記手続単位を前記被呼メソッドリストに含む手続単位を、前記再帰呼び出しを行うメソッドを呼び出すメソッドとして特定し、
前記呼出形態種が分岐を示す前記手続単位の前記被呼メソッドリストに含まれる他のメソッドを前記分岐手続単位内で呼び出されるメソッドとして特定し、
前記呼出形態種がループを示す前記手続単位の前記被呼メソッドリストに含まれる他のメソッドを前記ループ手続単位内で呼び出されるメソッドとして特定するか、又は、前記呼出形態種がループを示す前記手続単位を含むメソッドを前記ループ手続単位を持つメソッドとして特定する、
ことを更に含む請求項１４に記載のプログラム。
【請求項１６】
前記プローブ挿入方法は、
前記制御構文データに含まれる手続単位毎の被呼メソッドリストを参照することにより、各手続単位に関する前記プローブ挿入対象を含まないネスト段数をそれぞれカウントし、
前記カウントされたネスト段数と所定閾値との比較により、該ネスト段数を持つ手続単位を前記プローブ挿入対象に追加する、
ことを更に含む請求項１３から１５のいずれか１項に記載のプログラム。
【請求項１７】
前記プローブ挿入方法は、
前記制御構文データ内で特定された前記各プローブ挿入対象について、マーク情報をそれぞれ付加することにより、拡張制御構文データを生成する、
ことを更に含み、
前記プローブの挿入は、前記拡張制御構文データの前記マーク情報に基づいて、前記プローブの挿入位置を決定する、
請求項１３から１６のいずれか１項に記載のプログラム。
【請求項１８】
前記プローブ挿入方法は、
前記対象プログラムのソースコード又は実行コードを構文解析することにより、前記制御構文データを生成する、
ことを更に含む請求項１３から１７のいずれか１項に記載のプログラム。
【発明の詳細な説明】
【技術分野】
【０００１】
本発明は、ソフトウェアの挙動を監視する技術に関する。
【背景技術】
【０００２】
近年、プログラムを書き換えてプローブを挿入することで、プログラムの実行状況を把握することが多くなってきている。ここで、プローブとは、プログラムの実行状況を監視するためにプログラムの任意の箇所に挿入される計測点であり、ライブラリ関数やメソッドなどの命令列により実現される。例えば、ＪＡＶＡ（登録商標）バイトコードインスツルメント技術によれば、ＪＡＶＡ（登録商標）プログラミング言語で記載されたプログラム中のメソッドにプローブを差し込み、稼働された実行経路、すなわち、実行時のコールフローを記録することができる。記録された実行時のコールフローは、障害時などに原因箇所の絞り込みに活用することができる。このようなプローブは、例えば、プログラム中の関数、サブルーチン、メソッドの入り口や出口などに挿入される。
【０００３】
このようにプローブを用いたソフトウェア監視手法が下記特許文献１及び２において提案されている。下記特許文献１には、コンポーネントにプローブを自動的に付加し、アプリケーション実行中にプローブからデータを受信し、そのデータに基づいてその付加されたプローブに対するメトリックを決定し、そのメトリックに基づいてそのプローブを修正するか否かを判定するというソフトウェア監視技術が提案されている。下記特許文献２には、第１コンポーネントの内部から起動される第２コンポーネントの起動前に、スタブ開始ログデータをスタブで記録し、その第２コンポーネントからの応答が受信された後に、スタブ終了ログデータをスタブで記録することで、コンポーネントベースソフトウェアシステム内の第２コンポーネントの実行に関するランタイム情報を収集する手法が提案されている。
【０００４】
ところが、プローブを挿入することで、プローブがオーバヘッドとなり、ソフトウェアの実行速度が低下するという問題がある。このような問題を解決するために下記特許文献３から５及び下記非特許文献１には次のような手法が提案されている。
【０００５】
下記特許文献３には、指定されたテストカバレッジの種類（セグメントカバレッジ、モジュールカバレッジ、タスクカバレッジ）に応じた特定のプログラム構造の位置にプローブを挿入することで、種類の異なるテストカバレッジを効率よく計測する手法が提案されている。下記特許文献４には、デバイスの記憶容量又はＣＰＵ性能に基づいて、デバイスごとにプローブの挿入数を決定し、その挿入数分の挿入位置を乱数を用いて選択して、その選択された各位置にそれぞれプローブを挿入することで、プローブ実行時間の削減及びメモリ資源の削減を図る手法が提案されている。下記非特許文献１には、プローブに、乱数に従ってｎ回に１回の割合でログを記録させることで、プローブによるオーバヘッドを削減する手法が提案されている。
【０００６】
下記特許文献５には、プログラムソースコードに対して構文解析を行い、この解析結果からコールフローグラフ及び逆コールフローグラフを生成し、これらグラフから、注目サブルーチンに対して従属するサブルーチンの候補を抽出するといったプログラムソースコードの分析手法が提案されている。
【先行技術文献】
【特許文献】
【０００７】
【特許文献１】特開２０１２−０８４１５０号公報
【特許文献２】特表２００５−５２７００８号公報
【特許文献３】特開平６−１６１８２５号公報
【特許文献４】特開２００８−１４０１６２号公報
【特許文献５】特開２００１−０９２６５２号公報
【非特許文献】
【０００８】
【非特許文献１】Ben Liblit, Alex Aiken, Alice X. Zheng, and Michael I. Jordan.，" Bug Isolation via Remote Program Sampling"，University of California, 2003
【発明の概要】
【発明が解決しようとする課題】
【０００９】
しかしながら、上述の各文献で提案される手法は、プログラム実行時のコールフローに関する情報を確実に取得することを目的としているわけではないため、コールフローに関する情報を得るために適切なプローブ挿入位置について言及していない。ここで、コールフローとは、対象プログラムを構成するメソッド間のコール（呼び出される又は呼び出す）関係と、対象プログラムの実行によりそのコール関係の発生順序とを少なくとも示す情報である。また、メソッドとは、プログラムを形成する、命令列の論理的な集まりであり、上記コール関係に含まれ得るソフトウェア要素を意味する。このようなソフトウェア要素は、関数やライブラリ等として実現されることもある。以降、このようなソフトウェア要素を総称してメソッドと表記する。
【００１０】
本発明は、このような事情に鑑みてなされたものであり、プログラム実行時のコールフローに関する情報をプログラムの実行速度の低下を抑制しつつ確実に取得する技術を提供する。
【課題を解決するための手段】
【００１１】
本発明の各態様では、上述した課題を解決するために、それぞれ以下の構成を採用する。
【００１２】
第１の態様は、プローブ挿入装置に関する。第１態様に係るプローブ挿入装置は、メソッドと、分岐フロー毎にメソッドを呼び出す分岐手続単位と、ループ中でメソッドを呼び出すループ手続単位とに対応する、対象プログラムを構成する手続単位毎に、その手続単位内部でのメソッドの呼び出し形態を、順次実行、分岐、又は、ループで表す呼出形態種と、その手続単位内部の処理を、呼び出される少なくとも１つのメソッドを含む被呼メソッドリスト、分岐手続単位、及び、ループ手続単位の少なくとも１つを用いて表す呼出構成とを含む制御構文データを取得する構文取得手段と、上記対象プログラムの開始点となるメソッドから実行順に沿って手続単位毎に上記制御構文データを参照することにより、上記制御構文データで示される複数の手続単位の中の、順次実行を示しかつ上記被呼メソッドリストに手続単位自身を含まない手続単位である順次実行メソッドと、該順次実行メソッドの上記被呼メソッドリストに含まれるメソッドであって内部でメソッド呼び出しを行わない最下位メソッドとを除外した残りから、コールフロー情報を得るためのプローブ挿入対象を特定する対象特定手段と、対象特定手段により特定されたプローブ挿入対象に対してプローブを挿入するプローブ挿入手段と、を有する。
【００１３】
第２の態様は、コンピュータにより実行されるプローブ挿入方法に関する。第２態様に係るプローブ挿入方法は、コンピュータが、メソッドと、分岐フロー毎にメソッドを呼び出す分岐手続単位と、ループ中でメソッドを呼び出すループ手続単位とに対応する、対象プログラムを構成する手続単位毎に、その手続単位内部でのメソッドの呼び出し形態を、順次実行、分岐、又は、ループで表す呼出形態種と、その手続単位内部の処理を、呼び出される少なくとも１つのメソッドを含む被呼メソッドリスト、分岐手続単位、及び、ループ手続単位の少なくとも１つを用いて表す呼出構成とを含む制御構文データを取得し、上記対象プログラムの開始点となるメソッドから実行順に沿って手続単位毎に上記制御構文データを参照することにより、上記制御構文データで示される複数の手続単位の中の、順次実行を示しかつ上記被呼メソッドリストに手続単位自身を含まない手続単位である順次実行メソッドと、該順次実行メソッドの上記被呼メソッドリストに含まれるメソッドであって内部でメソッド呼び出しを行わない最下位メソッドとを除外した残りから、コールフロー情報を得るためのプローブ挿入対象を特定し、特定されたプローブ挿入対象に対してプローブを挿入する、ことを含む。
【００１４】
なお、本発明の他の態様としては、上記第１態様の構成をコンピュータに実現させるプログラムであってもよいし、このようなプログラムを記録したコンピュータが読み取り可能な記録媒体であってもよい。この記録媒体は、非一時的な有形の媒体を含む。
【発明の効果】
【００１５】
上記各態様によれば、プログラム実行時のコールフローに関する情報をプログラムの実行速度の低下を抑制しつつ確実に取得する技術を提供することができる。
【図面の簡単な説明】
【００１６】
【図１】第１実施形態におけるプローブ挿入装置のハードウェア構成例を概念的に示す図である。
【図２】第１実施形態におけるプローブ挿入装置の処理構成例を概念的に示す図である。
【図３】第１実施形態におけるプローブ挿入装置の動作例を示すフローチャートである。
【図４】変形例におけるプローブ挿入装置の処理構成例を概念的に示す図である。
【図５】変形例におけるプローブ挿入装置の動作例を示すフローチャートである。
【発明を実施するための形態】
【００１７】
以下、本発明の実施の形態について説明する。なお、以下に挙げる実施形態は例示であり、本発明は以下の実施形態の構成に限定されない。
【００１８】
本実施形態に係るプローブ挿入装置は、メソッドと、分岐フロー毎にメソッドを呼び出す分岐手続単位と、ループ中でメソッドを呼び出すループ手続単位とに対応する、対象プログラムを構成する手続単位毎に、その手続単位内部でのメソッドの呼び出し形態を、順次実行、分岐、又は、ループで表す呼出形態種と、その手続単位内部の処理を、呼び出される少なくとも１つのメソッドを含む被呼メソッドリスト、分岐手続単位、及び、ループ手続単位の少なくとも１つを用いて表す呼出構成とを含む制御構文データを取得する構文取得手段と、上記対象プログラムの開始点となるメソッドから実行順に沿って手続単位毎に上記制御構文データを参照することにより、上記制御構文データで示される複数の手続単位の中の、順次実行を示しかつ上記被呼メソッドリストに手続単位自身を含まない手続単位である順次実行メソッドと、該順次実行メソッドの上記被呼メソッドリストに含まれるメソッドであって内部でメソッド呼び出しを行わない最下位メソッドとを除外した残りから、コールフロー情報を得るためのプローブ挿入対象を特定する対象特定手段と、対象特定手段により特定されたプローブ挿入対象に対してプローブを挿入するプローブ挿入手段と、を有する。
【００１９】
本実施形態に係るプローブ挿入方法は、コンピュータが、メソッドと、分岐フロー毎にメソッドを呼び出す分岐手続単位と、ループ中でメソッドを呼び出すループ手続単位とに対応する、対象プログラムを構成する手続単位毎に、その手続単位内部でのメソッドの呼び出し形態を、順次実行、分岐、又は、ループで表す呼出形態種と、その手続単位内部の処理を、呼び出される少なくとも１つのメソッドを含む被呼メソッドリスト、分岐手続単位、及び、ループ手続単位の少なくとも１つを用いて表す呼出構成とを含む制御構文データを取得し、上記対象プログラムの開始点となるメソッドから実行順に沿って手続単位毎に上記制御構文データを参照することにより、上記制御構文データで示される複数の手続単位の中の、順次実行を示しかつ上記被呼メソッドリストに手続単位自身を含まない手続単位である順次実行メソッドと、該順次実行メソッドの上記被呼メソッドリストに含まれるメソッドであって内部でメソッド呼び出しを行わない最下位メソッドとを除外した残りから、コールフロー情報を得るためのプローブ挿入対象を特定し、特定されたプローブ挿入対象に対してプローブを挿入する、ことを含む。
【００２０】
本実施形態では、まず、対象プログラムに関する制御構文データが取得される。制御構文データは、対象プログラムを構成する手続単位毎に呼出形態種と呼出構成とを含む。ここで、手続単位とは、対象プログラムを構成する、メソッド、分岐フロー毎にメソッドを呼び出す分岐手続単位、及び、ループ中でメソッドを呼び出すループ手続単位である。呼出形態種は、手続単位内部でのメソッドの呼び出し形態を、順次実行、分岐、又は、ループで示す。呼出構成は、手続単位内部の処理を、分岐手続単位、ループ手続単位、及び、呼び出される少なくとも１つのメソッドを含む被呼メソッドリストの少なくとも１つを用いて表す。
【００２１】
本実施形態では、取得された制御構文データに基づいて、制御構文データで示される複数の手続単位の中の、順次実行を示しかつ被呼メソッドリストに手続単位自身を含まない手続単位である順次実行メソッドと、この順次実行メソッドの被呼メソッドリストに含まれるメソッドであって内部でメソッド呼び出しを行わないメソッドとを除外した残りから、コールフロー情報を得るためのプローブ挿入対象が特定され、特定されたプローブ挿入対象に対してプローブが挿入される。
【００２２】
このように、本実施形態によれば、内部でメソッドを順次呼び出すに過ぎないメソッド（順次実行メソッド）、及び、その順次実行メソッドにより呼び出されかつその内部でメソッド呼び出しを行わないメソッドがプローブ挿入対象から除外される。これにより、本実施形態によれば、全てのメソッドに対してプローブを挿入する形態に比べ、プローブ挿入に伴うソフトウェアの実行速度の低下を抑制することができる。
【００２３】
上述のようなメソッドがプローブ挿入対象から除外された場合、プローブの実行結果には、その除外されたメソッドのコールフローは反映されない。しかしながら、対象プログラム、その対象プログラムの実行コード、上述の制御構文データなどから、順次実行メソッド、及び、順次実行メソッドから呼び出されるメソッドは容易に把握され得る。従って、本実施形態のように、上述のようなメソッドをプローブ挿入対象から除外したとしても、ユーザ（対象プログラムの分析者など）は、プローブの実行結果以外の情報を参照することにより、対象プログラムの全コールフローを確実に得ることができる。
【００２４】
このようにして、本実施形態では、プログラム実行時の全コールフローの情報を確実に取るのに必要最低限の数のプローブを挿入するために、最適なプローブ挿入位置が特定される。言い換えれば、本実施形態における最適なプローブ挿入位置とは、対象プログラム及びそれから入手可能な他の情報から容易に取得し得るコールフロー情報を除いた全コールフロー情報をプローブの実行結果から取得することができる位置である。
【００２５】
以下、上述の実施形態について更に詳細を説明する。
［第１実施形態］
【００２６】
〔装置構成〕
図１は、第１実施形態におけるプローブ挿入装置１のハードウェア構成例を概念的に示す図である。第１実施形態におけるプローブ挿入装置１は、いわゆるコンピュータであり、例えば、バス５で相互に接続される、ＣＰＵ（Central Processing Unit）２、メモリ３、入出力インタフェース（Ｉ／Ｆ）４等を有する。メモリ３は、ＲＡＭ（Random Access Memory）、ＲＯＭ（Read Only Memory）、ハードディスク、可搬型記憶媒体等である。
【００２７】
入出力Ｉ／Ｆ４は、入力部（図示せず）、出力部（図示せず）、ネットワーク（図示せず）を介して他のコンピュータと通信を行う通信装置７等と接続される。入力部は、キーボード、マウス等のようなユーザ操作の入力を受け付ける装置である。出力部は、ディスプレイ装置やプリンタ等のようなユーザに情報を提供する装置である。なお、プローブ挿入装置１のハードウェア構成は制限されない。
【００２８】
図２は、第１実施形態におけるプローブ挿入装置１の処理構成例を概念的に示す図である。第１実施形態におけるプローブ挿入装置１は、構文抽出手段１１、拡張構文生成手段１２、プローブ挿入手段１３等を有する。これら各処理部は、例えば、ＣＰＵ２によりメモリ３に格納されるプログラムが実行されることにより実現される。また、当該プログラムは、例えば、ＣＤ（Compact Disc）、メモリカード等のような可搬型記録媒体やネットワーク上の他のコンピュータから入出力Ｉ／Ｆ４を介してインストールされ、メモリ３に格納される。
【００２９】
構文抽出手段１１は、対象プログラムのソースコード又は実行コード（以降、プログラムコードＤ１と表記する）を取得する。プログラムコードＤ１は、メモリ３に格納されるファイルから取得されてもよいし、可搬型記録媒体、他のコンピュータ等から入出力Ｉ／Ｆ４を経由して取得されてもよい。また、本実施形態で分析の対象となる対象プログラムの記述言語は、制限されない。よって、対象プログラムは、ＰａｓｃａｌやＣ等のような一般的な構造型手続き型プログラミング言語で記述されてもよいし、オブジェクト指向言語で記述されてもよい。
【００３０】
構文抽出手段１１は、取得されたプログラムコードＤ１を構文解析することにより、制御構文データＤ２を生成する。制御構文データＤ２は、例えば、次のような文法Ｓにより表わされる。本実施形態は、制御構文データＤ２の記述形態をこのような文法Ｓで表わされる形態に制限しない。
Ｓ＝｛ｓ，Ｍ，Ｒ｝
ｓは開始記号であり、Ｍは上述の手続単位の集合を示し、Ｒは次のようなルールを示す。
【００３１】
Ｒ１：ｐ−＞ｑ１  ・・・  ｑｎ
Ｒ２：ｐ−＞ｑ｜ｒ
Ｒ３：ｐ−＞ｑ＊
Ｒ４：ｐ⊃ｑ
ルールＲにおいて、左辺のｐは、メソッド、分岐フロー毎にメソッドを呼び出す分岐手続単位、又は、ループ中でメソッドを呼び出すループ手続単位であり、右辺は、左辺の手続単位に関する上述の呼出形態種及び上述の被呼メソッドリストに対応する。ルールＲ１の呼出形態種は順次実行を示し、ルールＲ２の呼出形態種（｜）は分岐を示し、ルールＲ３の呼出形態種（＊）はループを示し、ルールＲ４の呼出形態種（⊃）はオーバライドメソッドを示す。右辺のｑ（ｑ１、ｑｎなど）及びｒは、左辺の手続単位から呼び出されるメソッド、又は、左辺の手続単位に含まれる分岐手続単位又はループ手続単位、若しくは、左辺のメソッドのオーバライドメソッドである。
【００３２】
以降、ｐ、ｑ、ｒを単に手続単位と表記し、上記ルールＲ１からＲ４で示される式を手続単位の展開式と表記する。これにより、上記各ルールＲ１からＲ４で表わされる手続単位の各展開式は次のように説明することができる。ルールＲ１で表わされる手続単位ｐは、手続単位ｑ１からｑｎを順次実行する。ルールＲ２で表わされる手続単位ｐは、分岐処理で構成され、分岐フロー毎に手続単位ｑ及びｒを実行する。ルールＲ３で表わされる手続単位ｐは、ループ処理で構成され、ループ内で手続単位ｑを実行する。ルールＲ４で表わされる手続単位（メソッド）ｐは、手続単位（メソッド）ｑでオーバライドされる。
【００３３】
拡張構文生成手段１２は、構文抽出手段１１により生成された制御構文データＤ２から、拡張制御構文データＤ３を生成する。拡張制御構文データＤ３は、制御構文データＤ２で示される複数の手続単位の中でプローブ挿入対象として特定されたメソッドにマーク情報が付加された制御構文データである。
【００３４】
拡張構文生成手段１２は、対象プログラムの開始点から実行順に沿って手続単位毎に制御構文データＤ２を参照することにより、制御構文データＤ２で示される複数の手続単位の中から、コールフロー情報を得るためのプローブ挿入対象を特定する。よって、拡張構文生成手段１２は、対象特定手段と呼ぶこともできる。拡張構文生成手段１２は、分岐手続単位内で呼び出されるメソッド、再帰呼び出しを行うメソッド、ループ手続単位内で呼び出されるメソッド、及び、複数のメソッドから呼び出されるメソッドを呼び出すメソッドを当該プローブ挿入対象として特定する。
【００３５】
拡張構文生成手段１２は、次のようにしてプローブ挿入対象を特定する。
拡張構文生成手段１２は、手続単位の被呼メソッドリストに含まれるメソッドが他の手続単位の被呼メソッドリストに含まれるか否かにより、当該手続単位を、複数のメソッドから呼び出されるメソッドを呼び出すメソッドとして特定する（第１判定手段に相当）。更に、拡張構文生成手段１２は、手続単位の被呼メソッドリストにその手続単位を含むメソッドが含まれるか否かにより、当該手続単位を再帰呼び出しを行うメソッドとして特定する（第２判定手段に相当）。更に、拡張構文生成手段１２は、呼出形態種が分岐を示す手続単位の被呼メソッドリストに含まれる他のメソッドを分岐手続単位内で呼び出されるメソッドとして特定する（第３判定手段に相当）。更に、拡張構文生成手段１２は、呼出形態種がループを示す手続単位の被呼メソッドリストに含まれる他のメソッドをループ手続単位内で呼び出されるメソッドとして特定する（第４判定手段に相当）。
【００３６】
拡張構文生成手段１２の上述の特定処理は次のような関数として表すこともできる。即ち、拡張構文生成手段１２は、次のような補助関数ｆ、ｅ、ｈ及びｇを用いて、プローブ挿入対象を特定してもよい。
【００３７】
補助関数ｆ：対象プログラムの開始点となる開始メソッド（ｍａｉｎ関数など）や共通ライブラリを処理する関数。以下の式において、マークが付加された手続単位には下線が引かれている。
ｆ１：ｆ（ｓ→ｐ）＝｛ｓ→ｐ，ｇ（ｐ）｝
ｆ２：ｆ（ｐ→・・・）＝ｅ（ｐ→・・・）
ｆ３：ｆ（ｐ→・・・）＝ｅ（ｐ→・・・）
【００３８】
補助関数ｆは、開始記号ｓが引数として与えられた場合、上記ｆ１を実行する。上記ｆ１では、その開始点となるメソッドを引数として補助関数ｇが実行される。補助関数ｆは、引数として与えられた対象手続単位の被呼メソッドリストに含まれるメソッドが他の手続単位の被呼メソッドリストに含まれる場合に、上記ｆ２を実行する。上記ｆ２では、その対象手続単位にマークを付加し、その対象手続単位の展開式を引数として補助関数ｅが実行される。補助関数ｆは、対象手続単位の被呼メソッドリストに含まれるメソッドが他の手続単位の被呼メソッドリストに含まれない場合に、上記ｆ３を実行する。上記ｆ３では、マークを付加することなくその対象手続単位の展開式を引数として補助関数ｅが実行される。
【００３９】
補助関数ｅ：順次実行（再帰呼び出しを含む）、分岐及びループを示す手続単位を処理する関数。
ｅ１：ｅ（ｐ→ｑ１・・・ｑｎ）＝｛ｈ（ｐ）→ｑ１・・・ｑｎ，ｇ（ｑ１），・・・，ｇ（ｑｎ）｝
ｅ２：ｅ（ｐ→ｑ１・・ｐ・・ｑｎ）＝｛ｈ（ｐ）→ｑ１・・ｐ・・ｑｎ，ｇ（ｑ１），・・，ｇ（ｐ）・・，ｇ（ｑｎ）｝
ｅ３：ｅ（ｐ→ｑ｜ｒ）＝｛ｈ（ｐ）→ｑ｜ｒ，ｇ（ｑ），ｇ（ｒ）｝
ｅ４：ｅ（ｐ→ｑ＊）＝｛ｈ（ｐ）→（ｑ）＊，ｇ（ｑ）｝
【００４０】
補助関数ｅは、引数に与えられた手続単位の呼出形態種が順次実行を示しかつその手続単位の被呼メソッドリストにその手続単位を含むメソッドが含まれない場合、上記ｅ１を実行する。上記ｅ１では、その手続単位を引数に関数ｈが実行されると共に、被呼メソッドリストに含まれる、メソッド、ループ手続単位及び分岐手続単位の各々を引数に補助関数ｇがそれぞれ実行される。補助関数ｅは、呼出形態種が順次実行を示す手続単位であってその被呼メソッドリストにその手続単位を含むメソッドが含まれる場合、上記ｅ２を実行する。上記ｅ２では、その手続単位にマークを付加し、その手続単位を引数に補助関数ｈが実行されると共に、被呼メソッドリストに含まれる、メソッド、ループ手続単位及び分岐手続単位の各々を引数に補助関数ｇがそれぞれ実行される。補助関数ｅは、引数として与えられた手続単位の呼出形態種が分岐を示す場合、上記ｅ３を実行する。上記ｅ３では、その手続単位を引数に補助関数ｈが実行されると共に、その手続単位の被呼メソッドリストに含まれる他のメソッドにマークが付加され、それら各メソッドを引数に補助関数ｇが実行される。補助関数ｅは、引数として与えられた手続単位の呼出形態種がループを示す場合、上記ｅ４を実行する。上記ｅ４では、その手続単位を引数に補助関数ｈが実行されると共に、その手続単位の被呼メソッドリストに含まれる他のメソッドにマークが付加され、そのメソッドを引数に補助関数ｇが実行される。
【００４１】
補助関数ｈ：オーバライドメソッドを処理する関数。
ｈ１：ｈ（ｐ）＝ｐ
ｈ２：ｈ（ｐ）＝ｐ
ｈ３：ｈ（ｐ）＝ｐ
【００４２】
補助関数ｈは、引数として与えられた手続単位にマーク情報が付加されている場合、上記ｈ１のようにそのまま何もしない。補助関数ｈは、引数として与えられた手続単位（メソッド）のオーバライドメソッドが存在する場合、上記ｈ２に示されるように、その手続単位（メソッド）にマーク情報を付加する。補助関数ｈは、数として与えられた手続単位にマーク情報が付加されておらずかつそのオーバライドメソッドが存在しない場合、上記ｈ３に示されるように何もしない。
【００４３】
補助関数ｇ：メソッドを展開する関数。
ｇ１：ｇ（ｐ）＝ｆ（ｐ→・・・）
ｇ２：ｇ（ｐ）＝Φ
【００４４】
補助関数ｇは、引数として与えられた手続単位が内部でメソッド呼び出しを行なっている場合に、上記ｇ１を実行する。上記ｇ１では、引数として与えられた手続単位の展開式を引数として補助関数ｆが実行される。補助関数ｇは、引数として与えられた手続単位が内部でメソッド呼び出しを行なっていない場合には何もしない。
【００４５】
プローブ挿入手段１３は、拡張制御構文データＤ３を参照することにより、マーク情報が付加されたプローブ挿入対象に対してプローブを挿入し、プローブが挿入されたプログラムコードＤ４を出力する。プローブは、例えば、挿入されるメソッド毎に、そのメソッドの名前を示すテキストデータをファイル出力するプログラムとして実現される。また、プローブは、挿入されるメソッド毎にユニークなＩＤをファイル出力するプログラムとして実現されてもよい。この場合、プローブ挿入手段１３は、そのＩＤとメソッドとの対応関係を示すデータを拡張制御構文データＤ３を参照しながら生成するようにしてもよい。本実施形態は、プローブ挿入手段１３により挿入されるプローブ自体の実現形態を制限しない。
【００４６】
また、プローブ挿入対象に決定されたメソッドの中のプローブ挿入位置についても、制限されない。例えば、プローブは対象メソッドの中の先頭に挿入されてもよい。また、プローブ挿入対象に対して２つのプローブが挿入されてもよい。この場合、対象メソッドの先頭と最後とにプローブが挿入され、各プローブが実行時刻をファイル出力するように実現されてもよい。このようにすれば、メソッドの起動時刻と終了時刻とを計測することができ、対象プログラムの中でボトルネックとなっているメソッドを判別することもできる。
【００４７】
〔動作例〕
以下、第１実施形態におけるプローブ挿入方法について図３を用いて説明する。図３は、第１実施形態におけるプローブ挿入装置１の動作例を示すフローチャートである。
【００４８】
プローブ挿入装置１は、対象プログラムのプログラムコードＤ１を取得する（Ｓ３１）。
プローブ挿入装置１は、取得されたプログラムコードＤ１を構文解析することにより、制御構文データＤ２を生成する（Ｓ３２）。
【００４９】
プローブ挿入装置１は、対象プログラムの開始点から実行順に沿って手続単位毎に制御構文データＤ２を参照することにより、制御構文データＤ２で示される手続単位毎の展開式からプローブ挿入対象を特定する（Ｓ３３）。具体的には、プローブ挿入装置１は、分岐手続単位内で呼び出されるメソッド、再帰呼び出しを行うメソッド、ループ手続単位内で呼び出されるメソッド、及び、複数のメソッドから呼び出されるメソッドを呼び出すメソッドを当該プローブ挿入対象として特定する。
【００５０】
プローブ挿入装置１は、特定された各プローブ挿入対象に対してマーク情報をそれぞれ付加し（Ｓ３４）、結果として、拡張制御構文データＤ３を生成する（Ｓ３５）。
【００５１】
プローブ挿入装置１は、拡張制御構文データＤ３のマーク情報を参照することにより、各プローブ挿入対象に対してプローブを挿入する（Ｓ３６）。
プローブ挿入装置１は、プローブが挿入されたプログラムコードを生成する（Ｓ３７）。
【００５２】
〔第１実施形態の作用及び効果〕
上述したように第１実施形態では、対象プログラムのプログラムコードから、ＢＮＦ（Backus-Naur Form）のような記法により記述された制御構文データＤ２が生成される。この制御構文データＤ２で示される、各手続単位についての呼出形態種（順次実行、分岐、ループ）及び被呼メソッドリストに基づいて、プローブ挿入対象とすべき手続単位が特定され、そのプローブ挿入対象にマーク情報が付加された拡張制御構文データＤ３が生成される。そして、拡張制御構文データＤ３のマーク情報に基づいて、プローブ挿入対象にプローブが挿入されたプログラムコードが生成される。これにより、第１実施形態では、分岐手続単位内で呼び出されるメソッド、再帰呼び出しを行うメソッド、ループ手続単位内で呼び出されるメソッド、及び、複数のメソッドから呼び出されるメソッドを呼び出すメソッドに対して、プローブが挿入される。
【００５３】
従って、本実施形態によれば、内部でメソッドを順次呼び出すに過ぎないメソッド（順次実行メソッド）、及び、その順次実行メソッドにより呼び出されかつその内部でメソッド呼び出しを行わないメソッドがプローブ挿入対象から除外されている。つまり、本実施形態によれば、プログラム実行時の全コールフローの情報を確実に取るのに必要最低限の数のプローブを挿入するための、最適なプローブ挿入位置を特定することができる。この最適なプローブ挿入位置とは、対象プログラム及びそれから入手可能な他の情報から容易に取得し得るコールフロー情報を除いた全コールフロー情報をプローブの実行結果から取得することができる位置である。
【００５４】
従って、本実施形態によれば、対象プログラム、それから入手可能な他の情報、及び、プローブ出力結果に基づいて、全コールフロー情報を入手可能とすることができると共に、全てのメソッドに対してプローブを挿入する形態に比べ、プローブ挿入に伴うソフトウェアの実行速度の低下を最小限とすることができる。
【００５５】
［第２実施形態］
上述の第１実施形態では、ループ手続単位内で呼び出されるメソッド、及び、再帰呼び出しを行うメソッドが共にプローブ挿入対象とされた。ところが、ループの回数や再帰呼び出しの回数が多い場合、プローブの実行回数が増大することになるため、プローブのオーバヘッドが増大する場合がある。そこで、第２実施形態では、上述の２つの対象に代え、ループ手続単位を持つメソッド及び再帰呼び出しを行うメソッドを呼び出すメソッドをプローブ挿入対象とする。以下、第２実施形態におけるプローブ挿入装置１について、第１実施形態と異なる内容を中心説明する。以下の説明では、第１実施形態と同様の内容については適宜省略する。
【００５６】
拡張構文生成手段１２は、手続単位の被呼メソッドリストにその手続単位を含むメソッドが含まれるか否かにより、その手続単位を再帰呼び出しを行うメソッドとして特定し、その特定された再帰呼び出しを行うメソッドを被呼メソッドリストに含む手続単位を、再帰呼び出しを行うメソッドを呼び出すメソッドとして特定する。また、拡張構文生成手段１２は、呼出形態種がループを示す手続単位を含むメソッドをループ手続単位を持つメソッドとして特定する（第４判定手段に相当）。
【００５７】
第２実施形態では、上述の補助関数ｆ、ｅ、ｈ及びｇの中の補助関数ｆ及びｅが次のように表わされる。補助関数ｆ及びｅは、第２実施形態では補助関数ｆ'及びｅ'と表記される。
ｆ１'：ｆ（ｓ→ｐ）＝｛ｓ→ｐ，ｇ（ｐ）｝
ｆ２'：ｆ（ｐ→・・・）＝ｅ'（ｐ→・・・）
ｆ３'：ｆ（ｐ→ｑ  ｒ  ｔ）＝｛ｐ→ｑ  ｒ  ｔ、ｅ'（ｐ→ｑ  ｒ  ｔ）｝
ｆ４'：ｆ（ｐ→・・・）＝ｅ'（ｐ→・・・）
【００５８】
補助関数ｆ'は、第１実施形態におけるｆ１からｆ３（ｆ１'、ｆ２'及びｆ４'に相当）に加えて、新たなｆ３'を更に持つ。補助関数ｆ'は、引数として与えられた手続単位の被呼メソッドリストに再帰呼び出しを行うメソッドが存在する場合に、ｆ３'を実行する。ｆ３'では、当該手続単位にマーク情報が付加され、その手続単位の展開式を引数として補助関数ｅ'が実行される。
【００５９】
ｅ１'：ｅ'（ｐ→ｑ１・・・ｑｎ）＝｛ｈ（ｐ）→ｑ１・・・ｑｎ，ｇ（ｑ１），・・・，ｇ（ｑｎ）｝
ｅ２'：ｅ'（ｐ→ｑ｜ｒ）＝｛ｈ（ｐ）→ｑ｜ｒ，ｇ（ｑ），ｇ（ｒ）｝
ｅ３'：ｅ'（ｐ→ｑ＊）＝｛ｈ（ｐ）→（ｑ）＊，ｇ（ｑ）｝
【００６０】
補助関数ｅ'では、第１実施形態におけるｅ２が省かれ、第１実施形態におけるｅ４がｅ３'に変更される。補助関数ｅ'は、引数として与えられた手続単位の呼出形態種がループを示す場合、上記ｅ３'を実行する。上記ｅ３'では、その手続単位（ループ手続単位）にマーク情報が付加されると共に、その手続単位を引数に補助関数ｈが実行され、更に、その手続単位の被呼メソッドリストに含まれるメソッドを引数に補助関数ｇが実行される。
【００６１】
プローブ挿入手段１３は、上述のように、繰り返し実行される側ではなく繰り返し実行する側がプローブ挿入対象とされるため、プローブ挿入対象内の、繰り返し実行する処理の前にプローブを挿入することが望ましい。具体的には、ループに入る前に、プローブが挿入されることが望ましい。また、プローブ挿入手段１３は、プローブが挿入されるメソッドの名前ではなく、繰り返し呼び出されるメソッドの名前を示すテキストデータをファイル出力するプローブを挿入することが望ましい。
【００６２】
〔第２実施形態の作用及び効果〕
上述のように、第２実施形態では、ループ手続単位内で呼び出されるメソッド、及び、再帰呼び出しを行うメソッドに代えて、ループ手続単位を持つメソッド及び再帰呼び出しを行うメソッドを呼び出すメソッドがプローブ挿入対象とされる。これにより、第２実施形態では、再帰呼び出しを行うメソッドが呼び出される度にプローブで実行を記録するのではなく、再帰呼び出しを行うメソッドを呼び出す側でプローブを用いてその実行を記録する。従って、第２実施形態によれば、再帰呼び出しによるプローブの繰り返し実行を避けることができ、プローブ実行によるオーバヘッドを一層削減することができる。
【００６３】
更に、第２実施形態では、ループ内でメソッドが呼び出される度にプローブで実行が記録されるのではなく、ループを実行するメソッドに挿入されたプローブにより実行が記録される。従って、第２実施形態によれば、ループによるプローブの繰り返し実行を避けることができ、プローブ実行によるオーバヘッドを一層削減することができる。
いる。
【００６４】
［変形例］
上述の各実施形態では、プローブ実行によるオーバヘッドを可能な限り削減するために、プログラム実行時の全コールフローの情報を確実に取るのに必要最低限の数のプローブの挿入箇所が特定された。しかしながら、コールフローだけでなく、詳細なプログラムの振る舞いを得たい場合には、上述の各実施形態で特定されるプローブ挿入対象に、プログラムの実行速度が低下し過ぎない程度に更なる挿入対象が加えられてもよい。そこで、以下、拡張制御構文データＤ３内で、プローブの挿入密度が低い箇所を検出し、その検出された箇所をプローブ挿入対象に加える形態が変形例として以下説明される。
【００６５】
図４は、変形例におけるプローブ挿入装置１の処理構成例を概念的に示す図である。変形例におけるプローブ挿入装置１は、上述の各実施形態の構成に加えて、カウント手段４１及び挿入対象追加手段４２を更に有する。これら各処理部についても、例えば、ＣＰＵ２によりメモリ３に格納されるプログラムが実行されることにより実現される。
【００６６】
カウント手段４１は、拡張構文生成手段１２により生成された拡張制御構文データＤ３に含まれる手続単位毎の被呼メソッドリストを参照することにより、各手続単位に関するプローブ挿入対象を含まないネスト段数をそれぞれカウントする。例えば、カウント手段４１は、対象プログラムの開始点となるメソッド（手続単位）から、被呼メソッドリストを参照しながら、マーク情報が付加された手続単位を見つけるまで、ネスト段数をインクリメントする。例えば、開始点となるメソッドにより呼び出される次段メソッドのネスト段数を１に設定し、その次段メソッドから呼び出される次々段メソッドのネスト段数を２に設定する。
【００６７】
挿入対象追加手段４２は、カウント手段４１によりカウントされたネスト段数と所定閾値との比較により、そのネスト段数を持つ手続単位にマーク情報を付加することで、その手続単位をプローブ挿入対象に追加する。
【００６８】
図５は、変形例におけるプローブ挿入装置１の動作例を示すフローチャートである。図５では、図３に示される工程と同じ内容の工程には、図３と同じ符号が付されている。変形例では、工程（Ｓ５１）及び工程（Ｓ５２）が追加される。工程（Ｓ５１）では、プローブ挿入装置１は、拡張制御構文データＤ３に含まれる手続単位毎の被呼メソッドリストに基づいて、各手続単位に関するプローブ挿入対象を含まないネスト段数をそれぞれカウントする。工程（Ｓ５２）では、プローブ挿入装置１は、工程（Ｓ５１）でカウントされたネスト段数の中で所定閾値を超えるネスト段数を持つ手続単位を特定し、この手続単位にマーク情報を付加することで、その手続単位をプローブ挿入対象に追加する。
【００６９】
この変形例によれば、プローブ挿入密度が低い箇所に更にプローブが挿入されるため、プローブ実行結果から、コールフローだけでなく、詳細なプログラムの振る舞いを示す情報を得ることができる。
【００７０】
また、上述の各実施形態では、対象プログラムの開始点となるメソッドがプローブ挿入対象とされていない。これは、開始点となるメソッドは、対象プログラムのソースコードや実行コードなどから明らかだからである。しかしながら、開始点となるメソッドは、基本的には１つであるため、プローブ挿入対象としたとしてもそれによりソフトウェアの実行速度が著しく低下することはないと考えられる。よって、対象プログラムの開始点となるメソッドをプローブ挿入対象に加えるようにしてもよい。この場合、上記補助関数ｆのｆ１は次のように表わされる。
ｆ１：ｆ（ｓ→ｐ）＝｛ｓ→ｐ，ｇ（ｐ）｝
この場合、ｆ１では、その開始点となるメソッドにマーク情報が付加されると共に、そのメソッドを引数として補助関数ｇが実行される。
【００７１】
以下に実施例を挙げ、上述の各実施形態及び変形例を更に詳細に説明する。
【実施例１】
【００７２】
上述の第１実施形態の実施例を実施例１として説明する。実施例１では、プローブ挿入装置１は、以下に示すプログラムコードＤ１を取得する。
class A {
public static void main(String[] a)
{   A a = new A();
System.out.println(a.f("abc", "b");)
}
String f(String s, String t) {
int i = s.length();
int j = t.length();
int ret = 0;
if (i > j) {
ret = s.substring(0, j);
} else {
ret = t.substring(0, i);
}
for (int p = min(i, j); p<max(i, j); p++) {
ret.append(" ");
}
return ret;
}
}
【００７３】
構文抽出手段１１は、上述のプログラムコードＤ１から、以下に示す制御構文データＤ２を生成する。ｓは開始記号であり、Ｒは分岐手続単位に相当し、Ｔはループ手続単位に相当する。
s → (A::main)
(A::main) → (A::f)  (PrintStream::println)
(A::f) → (String::length)  (String::length)  R  T
R → (String::substring)|(String::substring)
T → (String::append)*
【００７４】
拡張構文生成手段１２は、このような制御構文データＤ２から、以下に示す拡張制御構文データＤ３を生成する。
s → (A::main)
(A::main) → (A::f)  (PrintStream::println)
(A::f) → (String::length)  (String::length)  R  T
R → (String::substring)|(String::substring)
T → (String::append)＊
【００７５】
以下、拡張構文生成手段１２が制御構文データＤ２から拡張制御構文データＤ３を生成する具体的処理について、上述の補助関数を用いて説明する。拡張構文生成手段１２は、上述の制御構文データＤ２の開始記号を含む展開式から順番に処理を行う。
（１）補助関数ｆは、開始記号を含む展開式を引数として実行される。ここで上記ｆ１が実行されることにより、拡張制御構文データＤ３の１行目「s → (A::main)」が出力され、(A::main)を引数として補助関数ｇが実行される。
ｆ（s → (A::main)）＝｛s → (A::main)， ｇ（(A::main)）｝
（２）補助関数ｇは、上記ｇ１を実行することにより、引数として与えられた(A::main)の展開式を引数として補助関数ｆを実行する。
ｇ（(A::main)）＝ｆ（(A::main) → (A::f) (PrintStream::println)）
（３）補助関数fは、引数として与えられた展開式の右辺（被呼メソッドリスト）に含まれるメソッドが他の手続単位の右辺（被呼メソッドリスト）に含まれていないため、上記ｆ３を実行する。
ｆ（(A::main) → (A::f) (PrintStream::println)）
＝ｅ（(A::main) → (A::f) (PrintStream::println)）
（４）補助関数ｅは、引数として与えられた手続単位（A::main）が順次実行を示すため、上記ｅ１を実行する。
ｅ（(A::main) → (A::f) (PrintStream::println)）＝｛ｈ（(A::main)）→(A::f) (PrintStream::println)，ｇ（(A::f)），ｇ（(PrintStream::println)）｝
（５）補助関数ｈは、引数として与えられた手続単位（A::main）がオーバライドされるメソッドでないから、(A::main)を出力し、結果として、拡張制御構文データＤ３の２行目「(A::main) → (A::f)  (PrintStream::println)」が出力される。
（６）補助関数ｇは、引数として与えられた手続単位（PrintStream::println)が内部でメソッド呼び出しを行なっていないため、そのまま処理を終える。
（７）補助関数ｇは、上記ｇ１を実行することにより、引数として与えられた(A::f)の展開式を引数として補助関数ｆを実行する。
ｇ（(A::f)）＝ｆ（(A::f) → (String::length)  (String::length)  R  T）
（８）補助関数ｆは、引数として与えられた展開式の右辺（被呼メソッドリスト）に含まれるメソッドが他の手続単位の右辺（被呼メソッドリスト）に含まれていないため、上記ｆ３を実行する。
ｆ（(A::f) → (String::length)  (String::length)  R  T）
＝ｅ（(A::f) → (String::length)  (String::length)  R  T）
（９）補助関数ｅは、引数として与えられた手続単位（A::f）が順次実行を示すため、上記ｅ１を実行する。
ｅ（(A::f) → (String::length)  (String::length)  R  T）＝｛ｈ(A::f) → (String::length)  (String::length)  R  T，ｇ（(String::length)），ｇ（(String::length)），ｇ（R），ｇ（T）｝
（１０）補助関数ｈは、引数として与えられた手続単位（A::f）がオーバライドされるメソッドでないから、(A::f)を出力し、結果として、拡張制御構文データＤ３の３行目「(A::f) → (String::length)  (String::length)  R  T」が出力される。
（１１）補助関数ｇは、引数として与えられた手続単位（String::length)が内部でメソッド呼び出しを行なっていないため、そのまま処理を終える。
（１２）補助関数ｇは、上記ｇ１を実行することにより、引数として与えられた(R)及び（T）の展開式を各引数として補助関数ｆをそれぞれ実行する。
ｇ（R）＝ｆ（R → (String::substring)  |  (String::substring)）
ｇ（T）＝ｆ（T → (String::append)*）
（１３）補助関数ｆは、いずれの引数についても同様の理由により、上記ｆ３をそれぞれ実行する。
ｆ（R → (String::substring)  |  (String::substring)）
＝ｅ（R → (String::substring)  |  (String::substring)）
ｆ（T → (String::append)*）＝ｅ（T → (String::append)*）
（１４−１）補助関数ｅは、引数として与えられた手続単位（R）が分岐を示すため、上記ｅ３を実行する。結果、各分岐フローで呼び出される各(String::substring)にマーク情報（下線）がそれぞれ付され、各(String::substring)を引数として補助関数ｇがそれぞれ実行される。
ｅ（R → (String::substring)  |  (String::substring)）
＝｛ｈ（R）→ (String::substring) | (String::substring)，ｇ（String::substring），ｇ（String::substring）｝
（１４−２）補助関数ｈは、引数として与えられた手続単位（R）がオーバライドされるメソッドでないから、(R)を出力し、結果として、拡張制御構文データＤ３の４行目「R → (String::substring)|(String::substring)」が出力される。
（１５−１）補助関数ｅは、引数として与えられた手続単位（T）がループを示すため、上記ｅ４を実行する。結果、ループ内で呼び出される(String::append)にマーク情報（下線）が付され、(String::append)を引数として補助関数ｇが実行される。
ｅ（T → (String::append)*）
＝｛ｈ（T）→ (String::append)*，ｇ（String::append）｝
（１５−２）補助関数ｈは、引数として与えられた手続単位（T）がオーバライドされるメソッドでないから、(T)を出力し、結果として、拡張制御構文データＤ３の５行目「T → (String::append)＊」が出力される。
（１６）補助関数ｇは、引数として与えられた手続単位（String::length)及び（String::append）が内部でメソッド呼び出しを行なっていないため、そのまま処理を終える。
【００７６】
プローブ挿入手段１３は、上述の拡張制御構文データＤ３でマーク情報（下線）が付加されている(String::substring)メソッド及び(String::append)メソッド内にプローブを挿入する。
【実施例２】
【００７７】
上述の第２実施形態の実施例を実施例２として説明する。実施例２では、プローブ挿入装置１は、実施例１と同様のプログラムコードＤ１を取得し、実施例１と同様の制御構文データＤ２を生成する。実施例１では、拡張制御構文データＤ３の５行目でループ内で呼び出される（String::append）にマーク情報が付された。実施例２では、（String::append）を呼ぶ側、即ち、ループ手続単位（Ｔ）にマーク情報が付される。以下が、実施例２で生成される拡張制御構文データＤ３を示す。
s → (A::main)
(A::main) → (A::f)  (PrintStream::println)
(A::f) → (String::length)  (String::length)  R  T
R → (String::substring)|(String::substring)
T → (String::append)＊
【００７８】
これにより、プローブ挿入手段１３は、(String::substring)メソッド内と、ループ手続単位（Ｔ）を含むメソッド内にプローブを挿入する。
【実施例３】
【００７９】
上述の変形例の実施例を実施例３として説明する。実施例３では、プローブ挿入装置１は、以下に示すプログラムコードＤ１を取得する。
class A {
public static void main(String[] a) 
{   A a = new A(); 
System.out.println(a.f("abc", "b");)
}
String f(String s, String t) {
int i = s.length();
int j = t.length();
int ret = 0;
ret = s.substring(0, j);
dec(ret);
return ret;
}
int  dec(int r) {
return minus(r, 1);
}
int minus(int a, int b) {
return plus(a, -b);
}
int plus(int a, int b) {
return a+b;
}
}
【００８０】
構文抽出手段１１は、上述のプログラムコードＤ１から、以下に示す制御構文データＤ２を生成する。ｓは開始記号である。
s → (A::main)
(A::main) → (A::f)  (PrintStream::println)
(A::f) → (String::length)  (String::length)  (String::substring)  (A::dec)
(A::dec) → (A::minus)
(A::minus) → (A::plus)
【００８１】
拡張構文生成手段１２は、このような制御構文データＤ２から拡張制御構文データＤ３を生成する。実施例３では、プローブ挿入対象となる手続単位は存在しないため、マーク情報が付加された手続単位は存在しない。
【００８２】
そこで、カウント手段４１が各手続単位のネスト段数をカウントする。ここでは、例えば、以下のようなネスト段数がカウントされる。
(A::f)：ネスト段数＝１
(PrintStream::println)：ネスト段数＝１
(String::length)：ネスト段数＝２
(String::substring)：ネスト段数＝２
(A::dec)：ネスト段数＝２
(A::minus)：ネスト段数＝３
(A::plus)：ネスト段数＝４
【００８３】
挿入対象追加手段４２は、このネスト段数に基づいてプローブ挿入対象を追加する。実施例３では、挿入対象追加手段４２は、所定閾値として３を保持する。よって、挿入対象追加手段４２は、ネスト段数４となる(A::plus)メソッドをプローブ挿入対象に追加する。結果、拡張制御構文データＤ３は以下のように示される。
s → (A::main)
(A::main) → (A::f)  (PrintStream::println)
(A::f) → (String::length)  (String::length)  (String::substring)  (A::dec)
(A::dec) → (A::minus)
(A::minus) → (A::plus)
【００８４】
プローブ挿入手段１３は、(A::plus)メソッド内にプローブを挿入する。
【００８５】
なお、上述の説明で用いたフローチャートでは、複数の工程（処理）が順番に記載されているが、本実施形態で実行される工程の実行順序は、その記載の順番に制限されない。本実施形態では、図示される工程の順番を内容的に支障のない範囲で変更することができる。また、上述の各実施形態及び変形例は、内容が相反しない範囲で組み合わせることができる。
【符号の説明】
【００８６】
１  プローブ挿入装置
２  ＣＰＵ
３  メモリ
１１  構文抽出手段
１２  拡張構文生成手段
１３  プローブ挿入手段
Ｄ１  プログラムコード
Ｄ２  制御構文データ
Ｄ３  拡張制御構文データ
Ｄ４  プローブ挿入プログラムコード
４１  カウント手段
４２  挿入対象追加手段
【図１】
2014056539.tif 000003
【図２】
2014056539.tif 000004
【図３】
2014056539.tif 000005
【図４】
2014056539.tif 000006
【図５】
2014056539.tif 000007