(57)【要約】      （修正有）【課題】コンピュータプログラムのパフォーマンス確認において、従来のインストルメント手法ではエラーを引き起こす可能性があるプラットフォーム向けに開発されるプログラムでもパフォーマンスを確認できるようにする。【解決手段】プローブ関数は、コンピュータプログラムが開発されるプラットフォームの制限的な呼び出し規約に従うように、ラッパー関数を介して呼び出される。呼び出し規約に従うことで、呼び出し規約に応じて例外ハンドラまたは他のプログラム要素が生じても、テスト中、コンピュータプログラムの適切な動作が行われる。【選択図】図４
2006268833.tif 000002
【特許請求の範囲】
【請求項１】
ソフトウェアプログラム内の所定の位置における動作状態に関する情報を記録するように適合された少なくとも１つのプローブ関数により、複数の位置および実行時に１つの動作状態を有するソフトウェアプログラムをインストルメントする方法であって、ラッパー関数を実行させるように前記ソフトウェアプログラムを修正することを備え、前期ラッパー関数は前記プローブ関数を実行させる少なくとも１つのコンピュータ実行可能命令を備えることを特徴とするソフトウェアプログラムをインストルメントする方法。
【請求項２】
前記プローブ関数は、前記ソフトウェアプログラムの前記動作状態に関する情報をログファイルに書き出す少なくとも１つのコンピュータ実行可能命令を備え、前記ラッパー関数は、前記ソフトウェアプログラムの前記動作状態を示す情報を記憶するラッパー関数を備えることを特徴とする請求項１に記載の方法。
【請求項３】
前記ソフトウェアプログラムは、少なくとも１つの実行可能ファイルにより表され、前記ソフトウェアプログラムを修正することは、
ａ）前記少なくとも１つの実行可能ファイルの最低限必要な部分を逆アセンブルすること、
ｂ）前記実行可能ファイルの前記逆アセンブルされた部分内において第３の関数を実行させる命令を特定すること、
ｃ）前記少なくとも１つの実行可能ファイル内にある前記第３の関数を実行させる前記命令を、前記ラッパー関数を実行させる命令に置き換えること、および、
ｄ）前記ラッパー関数内に前記第３の関数を実行させる命令を含むこと
を備えることを特徴とする請求項１に記載の方法。
【請求項４】
前記少なくとも１つの実行可能ファイル内にある前記第３の関数を実行させる前記命令を、前記ラッパー関数を実行させる命令に置き換えることは、前記第３の関数の呼び出しを前記ラッパー関数の呼び出しに置き換えることを備えることを特徴とする請求項３に記載の方法。
【請求項５】
前記ラッパー関数内にある前記第３の関数を実行させる命令を含むことは、前記ラッパー関数内に前記第３の関数を対象とするジャンプ命令を含むことを備えることを特徴とする請求項４に記載の方法。
【請求項６】
前記ソフトウェアプログラムは、少なくとも１つの実行可能ファイルにより表され、前記ソフトウェアプログラムを修正することは、
ａ）前記少なくとも１つの実行可能ファイルの最低限必要な部分を逆アセンブルすること、
ｂ）第３の関数内にあり、対象となる位置で命令を実行させる、前記実行可能ファイルの前記逆アセンブルされた部分内の命令を特定すること、
ｃ）前記少なくとも１つの実行可能ファイル内にある前記特定された命令を、前記ラッパー関数を実行させる命令に置き換えること、および、
ｄ）前記ラッパー関数内に、前記対象となる位置で前記命令を実行させる命令を含むこと
を備えることを特徴とする請求項１に記載の方法。
【請求項７】
前記ソフトウェアプログラムは、少なくとも１つの実行可能ファイルにより表され、前記ソフトウェアプログラムを修正することは、
ａ）前記少なくとも１つの実行可能ファイル内に前記ラッパー関数を実行させる実行すべき命令を挿入すること、および、
ｂ）前記ラッパー関数内に、前記ソフトウェアプログラム内の前記プローブ位置に隣接した位置にある命令を実行させる命令を含むこと
を備えることを特徴とする請求項１に記載の方法。
【請求項８】
前記実行可能ファイルは、Ｘ６４拡張機能を有するプロセッサにより処理することができる命令から構成されることを特徴とする請求項１に記載の方法。
【請求項９】
前記プローブ関数が呼ばれた後に、前記ラッパー関数は記憶された情報から前記ソフトウェアプログラムの前記動作状態を元に戻す少なくとも１つのコンピュータ実行可能命令を備えることを特徴とする請求項１に記載の方法。
【請求項１０】
値を持つレジスタ、および、関数呼び出しの際に少なくとも１つの前記レジスタの前記値が保持される呼び出し規約を有するプラットフォーム上でソフトウェアプログラムをテストする方法であって、前記プログラム内のインストルメントされる位置で少なくとも１つのプローブ関数を実行することを備え、前記プログラムを、
ａ）前記インストルメントされる位置で、ラッパー関数を実行させる命令を実行すること、および、
ｂ）前記ラッパー関数内から、
ｉ）前記プラットフォームの前記状態を保持すること、
ii）前記プローブ関数を呼び出すこと、および、
iii）前記プラットフォームの前記状態を元に戻すこと
により実行することをさらに備えることを特徴とするソフトウェアプログラムをテストする方法。
【請求項１１】
前記ラッパー関数を実行させる命令を前記実行することは、前記ラッパー関数用のスタックフレームを形成することをさらに備えることを特徴とする請求項１０に記載のソフトウェアプログラムをテストする方法。
【請求項１２】
前記プラットフォームの前記状態を前記保持することは、前記ラッパー関数用の前記スタックフレーム内に少なくとも１つの前記レジスタ値を格納することを備えることを特徴とする請求項１１に記載のソフトウェアプログラムをテストする方法。
【請求項１３】
ａ）前記ラッパー関数を実行させる命令を前記実行することは、前記ラッパー関数を対象とする呼び出し命令を実行することを備えること、および、
ｂ）前記方法は、前記ラッパー関数内から第２の関数を対象とするジャンプ命令を実行することをさらに備えること
を特徴とする請求項１０に記載のソフトウェアプログラムをテストする方法。
【請求項１４】
ａ）前記ラッパー関数を実行させる命令を前記実行することは、第２の関数内から前記ラッパー関数を対象とするジャンプ命令を実行することを備えること、および、
ｂ）前記方法は、前記ラッパー関数内からリターン命令を実行することをさらに備えること
を特徴とする請求項１０に記載のソフトウェアプログラムをテストする方法。
【請求項１５】
ａ）前記ラッパー関数を実行させる命令を前記実行することは、前記ラッパー関数を対象とする呼び出し命令を実行することを備えること、および、
ｂ）前記方法は、前記ラッパー関数内からリターン命令を実行することをさらに備えること
を特徴とする請求項１０に記載のソフトウェアプログラムをテストする方法。
【請求項１６】
ソフトウェアプログラムの開発環境を実装するためのコンピュータ実行可能命令を有するコンピュータ可読媒体であって、前記コンピュータ実行可能命令の実行ステップは、
ａ）プローブ関数および前記プローブ関数を呼び出すラッパー関数を含むように前記ソフトウェアプログラムの実行可能版を含むバイナリファイルを修正するステップ、
ｂ）プローブ関数が実行されるべき前記バイナリファイル内の特定位置を指定するステップ、および、
ｃ）前記ラッパー関数を実行させる命令を前記特定位置に提供するステップ
を備えることを特徴とするコンピュータ可読媒体。
【請求項１７】
前記コンピュータ実行可能命令の前記実行ステップであって、前記バイナリファイル内の特定位置を指定する前記ステップは、人間からの入力を受け取るステップを備えるコンピュータ実行可能命令の実行ステップを備えることを特徴とする請求項１６に記載のコンピュータ可読媒体。
【請求項１８】
前記コンピュータ実行可能命令の前記実行ステップであって、バイナリファイルを修正する前記ステップは、前記ラッパー関数および前記プローブ関数の実行可能版を前記バイナリファイルに付加するステップを備えるコンピュータ実行可能命令の実行ステップを備えることを特徴とする請求項１６に記載のコンピュータ可読媒体。
【請求項１９】
前記コンピュータ実行可能命令の前記実行ステップであって、バイナリファイルを修正する前記ステップは、前記ラッパー関数についての識別情報を含むように関数テーブルを修正するステップを備えるコンピュータ実行可能命令の実行ステップをさらに備えることを特徴とする請求項１８に記載のコンピュータ可読媒体。
【請求項２０】
前記コンピュータ実行可能命令の前記実行ステップであって、前記ラッパー関数を実行させる命令を前記特定位置に提供する前記ステップは、前記ソフトウェアプログラムの命令を表す前記バイナリファイルの一部を修正するステップを備えるコンピュータ実行可能命令の実行ステップを備えることを特徴とする請求項１８に記載のコンピュータ可読媒体。
【発明の詳細な説明】
【技術分野】
【０００１】
本願は、一般にソフトウェア開発に関し、より詳細には、ソフトウェアテストのためのツールに関する。
【背景技術】
【０００２】
ソフトウェアプログラムが開発される場合、プログラムが意図通りに動作することを判断するために、プログラムをテストすることがしばしば望ましい。ソフトウェアプログラムがより大きく、より複雑になると、プログラムはあまりにゆっくりと実行され、あまりに多くのメモリを消費し、また別の状況では、そのプログラムのすべての部分が望ましい結果を生んだとしても、望ましいパフォーマンス水準に達していない傾向にあった。
【０００３】
プログラムが望ましいパフォーマンス水準に達しているかどうかを判断するために、プログラムをテストすることがしばしば望ましい。ソフトウェアプログラムが望ましいパフォーマンス水準に達していない場合、パフォーマンスエンジニアは、パフォーマンス改善のために修正することができる部分を特定するため、実行しているプログラムを分析することがある。
【０００４】
パフォーマンスエンジニアリングを容易にするため、ソフトウェア開発システムは、プログラムを「インストルメント」することができるツールを備える。プログラムを「インストルメント」するには、一般に、「プローブ」と呼ばれる、特別な関数の呼び出しを挿入することが必要となる。各プローブは実行されるたびに、プローブが挿入されたプログラムの動作状況に関する情報を記録する。例えば、あるプローブは、プログラムが特定の関数を呼び出す前に、および別のプローブは、その関数を呼び出す後にプログラム内に挿入することができる。これらのプローブは実行されると、各プローブはそれぞれが実行された時間をログファイルに書き込むことができる。ログファイルを分析することにより、パフォーマンスエンジニアはその関数を実行するのに必要な時間を確認することができる。
【０００５】
別の例として、プローブは各関数の最初および最後に挿入することができる。これらのプローブにより収集された情報は、各関数が実行される回数または関数呼び出しの実行時間を分析するために使用することができる。このようなパフォーマンス情報は、比較的複雑なプログラムを分析する場合に重要となる。
【０００６】
インストルメントされたプログラムを分析して得られた結果が実際に動作中のプログラムのパフォーマンスを示す信頼性の高い指標となるように、プローブの追加がプログラムにできる限り影響を及ぼさないようにする必要がある。したがって、プローブは、一般に、分析されるプログラムを含むバイナリファイルまたは実行可能ファイルに挿入される。バイナリファイルは、プログラムが完全に最適化され、コンパイルされた後に、そのプログラムを含むことになる。したがって、プローブの挿入は、その最適化またはコンパイルプロセスを変更するものではない。
【０００７】
プローブをバイナリファイルに挿入するため、バイナリファイルは逆アセンブルされ、プログラム内におけるプローブの望ましい特定の位置が指定される。例えば、各関数を示す命令群の最初を指定するために、関数テーブルがバイナリファイルの一部としてしばしば含まれる。
【発明の開示】
【発明が解決しようとする課題】
【０００８】
プローブは、例えば、変数の記憶領域を変更することによって、または実行中のプログラムが依存する情報が格納されているフォーマットを破壊することによって、動作中のプログラムに対しエラーを発生させてはならない。アプリケーションプログラムが記述されているソフトウェアシステムは、特に関数内のレジスタ値の変更に関して様々なプログラミング規約を課すことがある。
【０００９】
例えば、多くの広く利用可能なアプリケーションは、特有の呼び出し規約を有するＸ８６プロセッサ群向けに開発されている。この呼び出し規約に従うため、Ｘ８６プロセッサ上で動くプログラムを処理するコンパイラは、ある導入部と終結部を有する各関数を実行することができる。その導入部では、その関数が変更する各レジスタ値をスタックに格納する。その終結部では、その関数がこれらのレジスタ値をスタックから取り出すことでレジスタ値を元に戻す。このような関数と相互に作用するように記述された他の任意のルーチンまたはツールも、情報がその呼び出し規約に従って格納されるという性質を呈する場合がある。その情報が呼び出し規約に従って格納されなければ、エラーが生じ得る。
【００１０】
その特有の呼び出し規約は、プログラムが動作するように意図されたプロセッサ向けにカスタマイズすることができる。例えば、プロセッサが高速で実行する命令を使用するように、呼び出し規約を設計することができる。したがって、ソフトウェアシステムとそのソフトウェアシステムが動作するように意図されたプロセッサの組合せにより形成された各プラットフォームは、異なる呼び出し規約を有することができる。例えば、一部のプラットフォームは、Ｘ８６プロセッサ群の６４ビット拡張機能を有するプロセッサを組み入れている。このようなプロセッサとして、ＡＭＤ６４またはＥＭＴ６４Ｔなどの名前のプロセッサが利用できる。これらのプロセッサはＸ６４拡張機能を有するものとして集合的に言及される。Ｘ６４拡張機能を有するプロセッサに基づくプラットフォームは、拡張機能を有さないＸ８６プロセッサに基づく類似のプラットフォームとは異なる呼び出し規約を使用することができる。
【００１１】
従来のインストルメント手法ではエラーを引き起こす可能性がある呼び出し規約を使用するＸ６４プラットフォーム向けに開発されるプログラムまたは他のアプリケーションをインストルメントすることが望まれる。
【課題を解決するための手段】
【００１２】
本発明は、従来のインストルメント手法ではエラーを引き起こす可能性があるプラットフォーム向けに開発されるプログラムをインストルメントする方法に関する。そのプロセスに従うと、プローブはラッパー関数内から呼び出される。ラッパー関数により、そのプラットフォームの呼び出し規約に違反することなく、プローブ関数を呼び出すことができる。
【００１３】
一態様においては、本発明は、ソフトウェアプログラム内の所定の位置の動作情報を記録するように適合された少なくとも１つのプローブ関数により、ソフトウェアプログラムをインストルメントする方法に関する。この方法は、制御をラッパー関数に移動するようにそのソフトウェアプログラムを修正することを備える。上記ラッパー関数はプローブ関数を呼び出す少なくとも１つのコンピュータ実行可能命令を備える。
【００１４】
別の態様においては、本発明は、値を持つレジスタ、および、少なくとも１つのレジスタ値が関数呼び出しの際に保持される呼び出し規約を有するプラットフォーム上でソフトウェアプログラムをテストする方法に関する。この方法は、プログラム内のインストルメントされる位置で、少なくとも１つのプローブ関数を実行することを含む。この方法に従うと、ソフトウェアプログラムが実行され、インストルメントされる位置に到達すると制御をラッパー関数に移動する。ラッパー関数内では、プラットフォームの状態が保持され、プローブ関数が呼び出され、その後、プラットフォームの状態が元に戻される。
【００１５】
別の態様においては、本発明は、ソフトウェアプログラムの開発環境を実装するコンピュータ実行可能命令を有するコンピュータ可読媒体に関する。コンピュータ実行可能命令は、プローブ関数およびプローブ関数を呼び出すラッパー関数を含むようにソフトウェアプログラムの実行可能版を含むバイナリファイルを修正し、プローブ関数が実行されるバイナリファイル内の特定位置を指定し、その特定位置でラッパー関数に制御を移動する制御移動命令を提供する。
【００１６】
添付図面は一定の縮尺で作成されてはいない。図面において、様々な図中に示される同一または類似の各要素が類似符号によって表されている。明瞭さの目的上、すべての図面中において、すべての構成要素に符号が付けられてはいない。
【発明を実施するための最良の形態】
【００１７】
発明者らは制限的な呼び出し規約を使用するプラットフォーム向けに記述されたコンピュータプログラムをインストルメントする際の問題を認識している。そのような呼び出し規約の１つの例は、Ｘ６４拡張機能を有するプロセッサ向けのマイクロソフト（登録商標）ウィンドウズ（登録商標）オペレーティングシステムから構成されるプラットフォーム上で使用されている。
【００１８】
図１は、このプラットフォーム向けに生成されたコードのアセンブリレベル版の一例を提供している。図１は例えば、実行可能ファイルの一部を逆アセンブルして生成されたものを示している。呼び出しプログラム１１０の一部が例示されている。呼び出しプログラム１１０は図中で「ＯｒｉｇｉｎａｌＦｕｎｃｔｉｏｎ」と表示された関数を呼び出す命令１１２を含む。
【００１９】
この例では、呼び出される関数１５０が「ＯｒｉｇｉｎａｌＦｕｎｃｔｉｏｎ」を示している。呼び出される関数１５０はリターン命令１５６で終了する。リターン命令１５６は関数呼び出し１１２に続く命令で呼び出しプログラム１１０にプログラム制御を返している。この例で使用されている呼び出し規約に従うと、プロセッサ内の一部のレジスタは、呼び出される関数にパラメータを渡すのに使用される。呼び出される関数は、その呼び出し規約に違反することなく、これらのレジスタ値を変更することができる。より一般的に、変更された値を有し、呼び出された関数から呼び出しプログラムに戻ることができるレジスタは、「揮発性レジスタ」と呼ばれる。
【００２０】
関数呼び出しの一環として、関数により使用されるパラメータ値は呼び出しプログラム１１０によって揮発性レジスタにロードされる。この例では、呼び出し前の命令１１４が関数に対するパラメータ値を揮発性レジスタに格納する。
【００２１】
揮発性レジスタに格納することができる数より多くのパラメータが必要とされる場合、呼び出しプログラム１１０と関連するスタックフレーム内の定められた位置に追加のパラメータを格納することができる。呼び出し前の命令１１５は、そのスタック上にパラメータを格納する命令であることを示す。呼び出しプログラム１１０はまた、関数呼び出し１１２の後に揮発性レジスタから関数の結果を示す値をアンロードする呼び出し後の命令１１６を含む。揮発性レジスタに格納することができる数より多くの結果が返される場合、追加の結果は呼び出しプログラム１１０と関連するスタックフレーム内のあらかじめ定められた位置に格納される。
【００２２】
この規約に従うと、呼び出される関数１５０は呼び出しプログラム１１０の動作を阻害することなく、揮発性レジスタを変更することができる。他のレジスタは不揮発性レジスタと考えられる。呼び出される関数１５０が任意の不揮発性レジスタを変更する場合には、それらのレジスタ値を記憶し、呼び出しプログラム１１０に戻る前にレジスタ値を元に戻さなければならない。したがって、呼び出される関数１５０は、関数１５０内で変更され得る任意の不揮発性レジスタの状態を記憶する導入部１５２を含む。呼び出される関数１５０はまた、導入部１５２で記憶された任意の不揮発性レジスタの状態を元に戻す終結部１５２を含む。呼び出される関数１５０がコンパイルされるときに、必要とされる不揮発性レジスタすべてを記憶するための十分なメモリ領域が確保されなければならない。
【００２３】
多くの場合、各関数はスタックとして実装されるメモリ構造内で実行するため、その関数用に記憶領域が確保される。各関数呼び出しの際、新たなスタックフレームが生成される。スタックフレームの生成は、関数によって使用される記憶領域を動的に確保する。関数が実行を終えると、そのスタックフレームはスタックから取り出され、プログラムの他の部分によって、その記憶領域は再び使用される。
【００２４】
場合によっては、フレームポインタがスタックフレームの上端（beginning）を特定するために使用される。このような実施形態では、１つのスタックフレームを取り出してスタックから取り除く情報量はフレームポインタから特定することができる。場合によっては、関数用のスタックフレームの大きさは、コンパイル時に定められる。スタックポインタはスタックフレームの下端（bottom）を示す。したがって、１つのスタックフレームを取り出してスタックから取り除く情報量は、スタックフレームの大きさの単位でスタックポインタをオフセットすることにより特定することができる。呼び出し規約によって、スタックフレームの大きさを特定するためにいずれか一方の手法を使用することが認められる場合は、プログラムへプローブを追加しても、いずれか一方の手法に対しエラーを引き起こすべきではない。
【００２５】
他の関数またはプログラムの一部は、呼び出し規約により定められたフォーマットを有するスタックに依存することがある。例えば、例外をハンドリングする場合、あらかじめ定められたフォーマット通りにメモリを配置することが重要である。例外発生時、通常の関数導入部を経て処理することなく、実行中の関数を終了することがしばしば必要である。しばしば「例外ハンドラ」と呼ばれる、例外の状況に対処するプログラムは、スタックフレームなどの関数についての情報に依存し、スタックを「巻き戻し（unwind）」、処理中のシステムを例外の状況が生じたポイント後の呼び出しプログラムの位置で再実行する状態にする。
【００２６】
例外ハンドラは、適切にスタックを巻き戻すために、呼び出される関数用に確保されるスタックフレームの大きさといった詳細情報など、各スタックフレームがどのように確立されているかを定義する情報にアクセスしなければならない。本明細書で説明されている実施形態では、この情報はコンパイルされたプログラムの一部として記憶される関数テーブル内に格納される。コンパイル時に、各関数用のスタックフレームの大きさを示す関数テーブルに登録がなされ、実行時に、その登録情報はスタックフレームの大きさを設定するために使用される。スタックを巻き戻すために必要とされる任意の付加情報もまた関数テーブル内に格納される。
【００２７】
説明されている実施形態では、フレームポインタはスタックフレームの上端を特定するためには使用されない。正確に言えば、スタックポインタがスタックフレームの下端を示すように設定される。特定の関数用のスタックフレーム内の記憶領域は、スタックポインタに対する相対位置を示すことで位置が示される。いったんスタックポインタがフレームの下端を示すように配置されると、スタックへの出し入れは使用されない。スタックフレームの上端は、スタックポインタから、その関数のためにあらかじめ定められた大きさを減じることで特定することができる。
【００２８】
この呼び出し規約により、単に実行可能ファイル内にプローブ関数の呼び出しを挿入するだけでは意図した結果を得ることができない場合がある。渡されるパラメータを保存するために必要な記憶領域は、呼び出しプログラムのスタックフレーム内では使用することができない場合がある。さらに、呼び出し規約のいずれかの部分が静的な情報（例えば、スタックフレームの大きさ）に依存する場合には、呼び出される関数は、プロセッサの安定状態を格納できるスタックフレームを有することができない。一部の呼び出し規約によって不揮発性レジスタの値をスタックに格納することはできるが、呼び出し規約違反によって、この格納がスタック構造を変更する可能性がある。
【００２９】
プログラムへプローブを挿入する際の呼び出し規約違反によって生じる問題は、「ラッパー関数」を使用することで、説明されている実施形態では回避される。本明細書で使用されているように、「ラッパー関数」という用語は、別の関数を呼び出す関数を指す。ラッパー関数は特に上記目的のために別個追加される場合もあるし、または他の関数に役立つ場合もある。実行可能ファイルへのラッパー関数の呼び出しの挿入が呼び出し規約に違反しないように、ラッパー関数は組み立てられる。ラッパー関数は、プラットフォームの呼び出し規約に従ってプローブ関数を呼び出すことができるように構成される。以下で説明される実施形態では、ラッパー関数は、プローブ関数を実行すべきインストルメントされるプログラム内の所定の位置で対象となるラッパー関数に制御が移動する制御移動命令を介して、実行可能ファイル内に挿入される。さらに、インストルメントされるプログラム用の実行可能ファイル内の関数テーブルは、ラッパー関数への参照を含むように増大する。
【００３０】
１つの実施形態では、ラッパー関数の実行によって、プローブ関数が適切に動作するように格納されなければならない任意のパラメータ用の記憶領域を含むスタックフレームが生成される。プローブの実行中、呼び出しプログラム、ラッパー関数およびプローブ用のスタックフレームはプラットフォームの呼び出し規約に従うことになる。
【００３１】
具体的な実施形態は、プローブ関数が挿入される呼び出しプログラム内の位置に基づいて使用することができるものである。図２Ａは、プローブ関数が呼び出される関数の最初に挿入される本発明の１つの実施形態を例示している。呼び出しプログラム２１０は図１中に表示された呼び出しプログラム１１０と同一の部分を示している。しかし、関数呼び出し１１２（図１）は「ＮｅｗＦｕｎｃｔｉｏｎ」と名付けられた関数を対象とする関数呼び出し２１２を生成するように修正されている。
【００３２】
このような修正は、例えば、自動、半自動または手動で実行可能コードの編集を可能にする従来の開発ツールを使用してなされ得る。ＮｅｗＦｕｎｃｔｉｏｎは、ラッパー関数２２０として実装される。これはプローブ関数の関数呼び出し２２６を含む。関数呼び出し２２６で呼び出されるプローブ関数は、呼び出されるプログラムの最初で実行されるプローブ関数が当技術分野では周知のように、実行時間を記憶する、レジスタ値を記憶する、呼び出しスタックを記憶する、などの動作を実行する。
【００３３】
ラッパー関数２２０は、プラットフォームの状態を保持し、かつラッパー関数２２０用に確保されるスタックフレームの下端を示すスタックポインタを設定する導入部２２２を含む。ラッパー関数２２０は、プラットフォームの状態を元に戻し、かつスタックポインタを調節することでラッパー関数２２０用に確保されたスタックフレームを解放する、導入部２２２と対応する終結部２２４を含む。プラットフォームの状態はプロセッサのレジスタ値によって示すことができる。プラットフォームの状態を保持するために記憶されなければならない特定のレジスタは、呼び出し規約に依存し、ラッパー関数２２０またはラッパー関数２２０が呼び出す可能性のある他の関数の動作に依存することがある。本明細書で一例として使用されている呼び出し規約では、導入部２２２は、ラッパー関数２２０により変更される揮発性および不揮発性レジスタの値ならびにラッパー関数２２０により呼び出されるプローブ関数内で変更されるが保持されない任意の揮発性レジスタの値を記憶する。図２Ａに示す具体例では、レジスタＲＣＸおよびＲＤＸが記憶される。
【００３４】
インストルメントされるプログラムのコンパイル後にラッパー関数２２０の呼び出しが追加されることにもかかわらず、ラッパー関数２２０はプラットフォームの呼び出し規約に従う。したがって、命令２２６で呼び出されるプローブ関数またはラッパー関数２２０のいずれかの実行中に例外が発生しても、例外ハンドラの動作は呼び出し規約からの逸脱によって妨げられることはない。
【００３５】
ラッパー関数２２０は、本明細書ではジャンプ命令２３０として例示されている制御移動命令で終了する。ジャンプ命令２３０の対象はＯｒｉｇｉｎａｌＦｕｎｃｔｉｏｎであり、この例では図１に示された呼び出されるプログラム１５０である。結果として、関数呼び出し２１２を実行することの正味の効果は、関数呼び出し２２６内に示されるプローブ関数が元の呼び出されるプログラム１５０の前に実行されることを除いて、インストルメントされるプログラム内で関数呼び出し１１２を実行することと等しい。
【００３６】
図２Ｂは、プローブ関数が呼び出されるプログラムの最後に挿入される１つの実施形態を例示している。この実施形態では、呼び出されるプログラム２５０は呼び出されるプログラム１５０の修正版である。呼び出されるプログラム２５０はリターン命令１５６（図１）が変更されていることを除いて、呼び出しプログラム１５０のすべての命令を含む。リターン命令１５６はジャンプ命令２５６に置き換えられる。
【００３７】
図２Ａに示された実施形態のように、図２Ｂに示された実施形態はインストルメントされるプログラム内の望ましい位置でプローブ関数を呼び出すラッパー関数の実行で終了する。この実施形態では、呼び出されるプログラムは、制御を「ＮｅｗＦｕｎｃｔｉｏｎ２」と名付けられたラッパー関数２６０に移動する制御移動命令、すなわち図２Ｂに示されるジャンプ命令２５６で終了する。
【００３８】
ラッパー関数２６０の実行は新たなスタックフレームの確保で終了する。このスタックフレームは、ラッパー関数２６０が呼び出されるときにプログラムの状態を保持するのに必要とされる情報を格納する十分な領域を含む。例示された実施形態では、ラッパー関数２６０は、スタックフレームを確立し、かつ呼び出し規約に従って状態を保持する導入部２６４を含む。ラッパー関数２６０はさらに、状態を元に戻し、かつスタックフレームを巻き戻す終結部２６６を含む。ラッパー関数２６０はまた、関数呼び出し２６２で呼び出されるプローブ関数を初期化するために使用することができる呼び出し前の命令２６８を含む。この例では、呼び出し前の命令２６８は、呼び出し規約に従って引数を関数に渡すために使用されるレジスタ内のプローブ関数に渡されるパラメータを記憶する。
【００３９】
ラッパー関数２６０はリターン命令２７０で終了する。ラッパー関数２６０は呼び出しではなくジャンプ命令２５６により実行されるので、ラッパー関数２６０の最後に実行されるリターン命令２７０は、先行技術と同様に、呼び出されるプログラム１５０の最後に実行されるリターン命令と同一の効果を有する。しかし、図２Ｂに示された命令を実行することの正味の効果は、命令２６２で呼び出されるプローブ関数が呼び出されるプログラム２５０からのリターンに先立って実行されることである。
【００４０】
次に図３を参照すると、別の例示的な実施形態が提供されている。図３は、呼び出しプログラム３１０の一部を例示している。この実施形態では、呼び出しプログラム３１０は、関数呼び出し３１２の直前および直後にあるプローブによってインストルメントされる。前述の例のように、各プローブは、ラッパー関数の関数呼び出しを追加することによって挿入される。関数呼び出し３１７は関数呼び出し３１２に先立ってプローブを追加するという効果を有する。関数呼び出し３１９は関数呼び出しによって呼び出される関数の実行に続いてプローブを追加するという効果を有する。この例では、呼び出される関数は修正されず、例えば、図１に示された関数１５０とすることができる。
【００４１】
関数呼び出し３１７はラッパー関数３２０を呼び出す。ラッパー関数３２０は導入部３２２および終結部３２４を含む。導入部３２２はスタックフレームを確立し、かつラッパー関数３２０またはラッパー関数３２０により呼び出されるプローブ関数によって変更された揮発性レジスタの状態を記憶する。説明されている実施形態では、不揮発性レジスタの状態はプローブ関数により記憶されるので、ラッパー関数３２０が直接的に変更しないこれらのレジスタの状態を記憶する必要はない。終結部３２４はスタックフレームを巻き戻し、かつ導入部３２２で記憶された揮発性レジスタの値を元に戻す。関数呼び出し３２６はプローブ関数を呼び出すが、このプローブ関数は先行技術と同様のプローブとすることができる。呼び出し前の命令３２８はプラットフォームの関数呼び出し規約に従ってパラメータをプローブ関数に渡す。
【００４２】
ラッパー関数３２０は制御移動命令、すなわち図３に示されたリターン命令３３０で終了する。リターン命令３３０は、関数呼び出し３１２が実行される呼び出し関数３１０に制御を返す。関数呼び出し３１７を実行することの正味の効果は、関数呼び出し３１２に先立ってプローブ関数が実行されることであり、呼び出し規約が満たされることではない。
【００４３】
関数呼び出し３１９はラッパー関数３６０を呼び出す。ラッパー関数３６０が実行されると、ラッパー関数３６０またはラッパー関数３６０により呼び出されるプローブ関数いずれかにより変更される可能性のある揮発性レジスタ用の記憶領域を提供するスタックフレームを生成する。ラッパー関数３６０は、スタックフレームを確立し、かつラッパー関数３６０またはその中に含まれるプローブ関数の結果として変更される可能性のある任意の揮発性レジスタの状態を記憶する導入部３６２を含む。呼び出し前の命令３６８は、関数呼び出し３６６で呼び出されるプローブ関数に渡されるパラメータの値を設定する。終結部３６４はスタックフレームを巻き戻し、かつ導入部３６２で記憶された揮発性レジスタの状態を元に戻す。
【００４４】
ラッパー関数３６０は、プログラムの実行を呼び出しプログラム３１０に返すリターン命令で終了する。呼び出しプログラム３１０で実行される次の命令は、呼び出し後の命令１１６である。図３に示された呼び出しプログラム３１０の一部を実行することの正味の効果は、プローブ関数が「ＯｒｉｇｉｎａｌＦｕｎｃｔｉｏｎ」と表された関数の呼び出し前および呼び出し後に呼び出されることを除いて、図１に示された呼び出しプログラム１１０の一部を実行することと等しい。
【００４５】
次に図４を参照すると、プログラムをインストルメントするプロセスの一例が示されている。図４は、プログラムをインストルメントするプロセス４１０のフローチャートである。この実施形態では、プログラムはすでにコンパイルされ、あるいは「バイナリ」またはＤＬＬモジュールといった実行可能ファイルに変換されている。実行可能ファイルは、プログラムを動かすプロセッサが実行することのできる個々の命令を示すバイナリコードを含む。図４は、例えば、ソフトウェア開発環境内のパフォーマンスアナライザツールを使用する人間の開発者に起因するプロセスを示している。このプロセスは、コンピュータ実行可能命令として、または人間の入力行為とコンピュータ実行可能命令の組合せにより符号化することができる。
【００４６】
実行可能ファイルはまた、関数テーブルを含むが、この関数テーブルはファイル内の各関数がどこに位置するかを示すものである。関数テーブルは、例外を処理するために、あるいはプログラムの動作を実行するために必要な情報を含む。この情報は、例えば、関数用に生成されるスタックフレームの大きさを含むことができる。
【００４７】
プロセス４１０は処理ブロック４１２で開始する。処理ブロック４１２では、バイナリファイルが逆アセンブルされる。そのファイルは完全に逆アセンブルされる場合もあるし、あるいは選択された部分が逆アセンブルされる場合もある。説明されている実施形態では、プローブを挿入する位置が特定されるように、バイナリの十分な部分が逆アセンブルされる。
【００４８】
バイナリファイルが生成された後、プログラム開発者がプログラムを分析または操作できるように、既存のプログラム開発環境にはしばしば逆アセンブルツールが含まれる。従来の逆アセンブラを使用することができる。人間の利用者のためにコードが表示される実施形態では、バイナリ全体を逆アセンブルすることができ、利用者は各命令を認識することができるようになる。プローブの位置が自動的に特定される状況では、プローブを挿入すべき位置に先立つ命令とプローブを挿入すべき位置に続く命令の少なくともどちらか一方の最初または最後を認識することが可能な程度のみ、コードを逆アセンブルすることで十分である。
【００４９】
プロセスは処理ブロック４１４に進む。処理ブロック４１４では、プローブを挿入すべき位置が特定される。説明されている実施形態では、開発環境により提供されるユーザインターフェースを介して人間の利用者が指し示すことによりプローブの位置が特定される。
【００５０】
人間の利用者は１つまたは複数のプローブの位置を指し示すことができる。図４の例では、１プローブによるプロセスが説明されている。利用者は、例えば、ユーザインターフェースに表示されるコード中の位置を指し示すことによってプローブの位置を指し示すことができる。あるいは、利用者はプローブが挿入される位置の特性を指定することにより、１つまたは複数のプローブの位置を示すことができる。例えば、人間の利用者は、ユーザインターフェースによってプログラムの指定部分にある各関数呼び出しの前および後に、または特定のモジュールから呼び出される各関数の最初および最後にプローブを挿入することを指定することができる。本発明では、プローブの位置を指定する具体的な方法に制限はない。
【００５１】
例示した実施形態において、プローブを挿入する具体的な処理ステップはプローブが挿入される位置に依存する。関数の最初に挿入されるプローブは、図２Ａに示されるように処理することができる。関数の最後に挿入されるプローブは、図２Ｂに示されるように処理することができる。呼び出しプログラム内の関数呼び出しの前または後などの他の位置に挿入されるプローブは、図３に示されるように処理することができる。判断ブロック４１６は、指定されるプローブ位置が関数の最初に配置することを要するかどうかを判定する。プローブを関数の最初に配置する必要がある場合、プロセスはブロック４２０に進む。
【００５２】
処理ブロック４２０では、追加されるプローブおよびラッパー関数を示す関数がバイナリファイルに追加される。これらの関数は、バイナリファイルの最後に実行可能コードを付加することにより、または他の都合のよい方法により追加することができる。プローブは、コードをインストルメントするために従来用いられたようなプローブ関数とすることができる。ラッパー関数は、図２Ａに示されるように、実行可能コンピュータ命令を示すバイナリコードに変換することができる。
【００５３】
処理ブロック４２２では、追加された関数を示すために関数テーブルが更新される。特に、プローブおよびラッパー関数が関数テーブルに追加される。例外を処理するために必要とされる関数についての情報を保持する程度まで、その情報が関数テーブルに含まれる。例えば、関数テーブル内の登録情報によって、関数用に確保されるスタックフレームの大きさを特定することができる。
【００５４】
処理ブロック４２４では、インストルメントされる関数の任意の呼び出しが新たに追加されたラッパー関数にリダイレクトされるように、バイナリコードが修正される。図２Ａに示された実施形態では、この修正は、インストルメントされる関数の関数呼び出しの対象をラッパー関数に置き換えることによってなされる。対象となる関数を示し、したがって変更される必要があるバイナリファイル内の特定のバイトを明確にするために、逆アセンブルされたコードは使用される。この置き換えは、逆アセンブルされたプログラム内でなされる場合もあるし、あるいはバイナリファイルで直接的になされる場合もある。コードに追加されるラッパー関数は、インストルメントされる関数の最初に制御を移す制御移動命令で終了する。
【００５５】
判断ブロック４１６で、プローブ位置は関数の最初ではないと判定した場合、プロセスは判断ブロック４３０に進む。判断ブロック４３０は、プローブが関数の最後に挿入されるかどうかを判定する。
【００５６】
プローブが関数の最後に挿入される場合、プロセスは処理ブロック４４０に進む。処理ブロック４４０では、ラッパー関数およびプローブ関数がバイナリに追加される。処理ブロック４２０のように、これらの関数はバイナリファイルの最後に実行可能コードを付加することにより、または他の都合のよい方法により追加することができる。プローブ関数は先行技術と同様のプローブとすることができる。ラッパー関数は、図２Ｂに示されるように、実行可能コンピュータ命令を示すバイナリコードに変換することができる。
【００５７】
ブロック４４２では、コードに追加されるラッパー関数およびプローブ関数を反映するために、バイナリファイル内の関数テーブルは更新される。ブロック４２２のように、関数テーブルを更新することは追加される関数を識別することに加えて、関数用に確保されるスタックフレームの大きさなど、例外を処理するために必要とされる他の情報も含む。
【００５８】
処理ブロック４４４では、インストルメントされる関数の終了命令がラッパー関数にリダイレクトされる。図２Ｂに示すように、このリダイレクションはインストルメントされる関数の最後のリターン命令をラッパー関数へのジャンプに置き換えることによってなされ得る。この実施形態では、ステップ４４０に追加されるラッパー関数は、呼び出しプログラムへの適切なリターンを提供するリターン命令で終了する。
【００５９】
判断ブロック４３０で、プローブ位置は関数の最後ではないと判定した場合、プロセスは処理ブロック４５０に進む。説明されている実施形態では、プローブ位置が関数の最初、関数の最後または関数呼び出しの直前もしくは関数呼び出しの直後に配置するよう強いられる。プロセスが処理ブロック４５０に進むと、プローブ位置は関数の最初または関数の最後ではなく、したがって、関数呼び出しの直前または直後にあるものとして扱われる。
【００６０】
処理ブロック４５０では、ラッパー関数およびプローブ関数はバイナリファイルに追加される。処理ブロック４２０のように、これらの関数はバイナリファイルの最後に実行可能コードを付加することにより、または他の都合のよい方法により追加することができる。
【００６１】
ブロック４５２では、コードに追加されるラッパー関数とプローブ関数を反映するために、バイナリファイル内の関数テーブルは更新される。ブロック４２２のように、関数テーブルを更新することは追加される関数を識別することに加えて、関数用に確保されるスタックフレームの大きさなど、例外を処理するために必要とされる他の情報も含む。
【００６２】
処理ブロック４５４では、ラッパー関数の呼び出しがインストルメントされるコード内の適切な位置に挿入される。呼び出し命令の追加によって、インストルメントされる関数を示すバイナリファイルの一部の長さが変更される。インストルメントされる関数の長さが変更されることで、バイナリファイル内に格納されたインストルメントされる関数または他の関数についての任意の記憶情報に影響がある場合は、その情報もまた更新される。このようにして、プローブが追加された後でさえも、バイナリファイルをなお適切に実行することができる。
【００６３】
図４に示されたプロセスは、１つのプローブをプログラムに追加するために必要とされるステップを示している。１つのプログラムをテストするために、多数のプローブが通常追加される。図４に示されたプロセスは、挿入される各プローブごとに繰り返すことができる。処理ステップを繰り返す場合、一部の動作を組み合わせることができる。例えば、追加される関数すべてを同時に反映するように関数テーブルを更新することができる。あるいは、関数テーブルに追加されなければならない、またはバイナリファイルに付加されなければならない関数の総数を減らすため、同一のプローブまたはラッパー関数を複数のプローブ挿入に使用することができる。
【００６４】
望ましいプローブすべてを追加するプロセスが終了すると、インストルメントされるプログラムを実行することができる。プローブ関数は、呼び出されると、ログファイルに書き出すことなどにより、インストルメントされるプログラムについての動作情報を取得することができる。この情報は、その後マシンにより分析される場合もあるし、または人間の操作者に表示するよう処理される場合もある。このような情報は、次いでデバッグするため、またはインストルメントされるプログラムのパフォーマンスを分析するために使用することができる。
【００６５】
したがって、本発明の少なくとも１つの実施形態についての上述した様々な態様を有していれば、当業者であれば様々な変更形態、修正形態および改良形態が着想されることは理解されよう。
【００６６】
例えば、動作が実行される具体的な順序は本発明にとって重要ではない。バイナリファイルが逆アセンブルされ、プローブを順に呼び出す新たな関数呼び出しによって置き換えられる元の関数の呼び出し命令を特定することが説明されている。その置き換えが、新たな関数を呼び出すためにバイナリコードをバイナリファイルに挿入すること、または逆アセンブルされたコードを修正し、次いで再度実行可能コードに変換することによってなされるかどうかは重要ではない。
【００６７】
また、本発明は、バイナリファイルとして記憶される実行可能コードに関連して説明されている。その情報を記憶するのに使用されるファイル構造は、本発明では制限がない。実行可能プログラムとしてコンピュータで処理することのできる任意の情報の組合せは、実行可能ファイルであると考えることができる。さらに、実行可能プログラムを含むファイルは命令や関数テーブルに制限される必要はない。実行可能プログラムは他の情報も含むことができる。さらに、実行可能プログラムは関数テーブルを含む必要はない。例外を処理したり、またはコードを実行したりするのに必要とされる情報は、任意の方法によって記憶することができる。この情報は特に記憶することができ、またはプラットフォームのために確立された規約に従ってファイルを処理することによって確認することができる。
【００６８】
本発明の上記で説明した実施形態は、任意の様々な方法により実装することができる。例えば、ハードウェア、ソフトウェアまたはこれらの組合せにより、実施形態を実装することができる。ソフトウェアで実装する場合、１つのコンピュータまたは多数のコンピュータ中で割り当てられたコンピュータであろうと、そのソフトウェアコードは任意の最適なプロセッサやプロセッサ群上で実行することができる。上記で説明された関数を実行する任意の構成要素または構成要素群が、一般に、上記で説明された関数を制御する１つまたは複数のコントローラであると考えられことが理解されよう。１つまたは複数のコントローラは様々な方法により、例えば、上記に列挙した関数を実行するためにマイクロコードまたはソフトウェアを使用してプログラムされている専用ハードウェアまたは汎用ハードウェア（例えば、１つまたは複数のプロセッサ）により実装することができる。
【００６９】
また、様々なオペレーティングシステムまたはプラットフォームの任意の１つを必要とする１つまたは複数のプロセッサ上で実行可能なソフトウェアとして、本明細書に概説した様々な方法またはプロセスを符号化することができる。さらに、そのようなソフトウェアは任意の様々な好適なプログラミング言語および／または従来のプログラミングツールまたはスクリプティングツールを用いて記述することができるし、または実行可能マシン言語コードとしてコンパイルすることができる。
【００７０】
この点、本発明の１つの実施形態は、１つまたは複数のコンピュータもしくは他のプロセッサ上で実行されるときに、上記で説明された様々な本発明の実施形態を実装する方法を実行する１つまたは複数のプログラムを有する符号化された１つまたは複数のコンピュータ可読媒体（例えば、コンピュータメモリ、１つまたは複数のフロッピー（登録商標）ディスク、コンパクトディスク、光学ディスク、磁気テープなど）に関するものでもある。コンピュータ可読媒体は可搬可能なため、そこに格納されたプログラムは、上記で説明された本発明の様々な態様を実装するために１つまたは複数の異なるコンピュータもしくは他のプロセッサ上にロードすることができる。
【００７１】
「プログラム」という用語は本明細書では、上記で説明された本発明の様々な態様を実装するためにコンピュータやプロセッサにプログラムを供給するよう使用される任意の種類のコンピュータコードや命令の集合を指すために、包括的な意味で用いられている。さらに、この実施形態の１つの態様にしたがえば、本発明の方法を実行する１つまたは複数のコンピュータプログラムは、実行されるときに１つのコンピュータまたは１つのプロセッサに属する必要はないが、本発明の様々な態様を実装するためには、多数の異なるコンピュータやプロセッサにモジュール単位で割り当てられることが認識されよう。同様に、「関数」という用語は本明細書では、制御が移動される可能性のあるプログラムの一部分を指すために、包括的な意味で用いられている。一部のプログラミング言語は、関数と呼ばれる特定の構成物を提供する。本明細書における用語「関数」の使用は制限的なものではない。用語「関数」は、サブプログラム、メソッド、プロシージャまたは他の名前で表されるプログラムの部品を包含するよう意図されている。
【００７２】
本発明の様々な態様は、単独で、組み合わされ、または上記で説明された実施形態には記載されていない様々な組合せで用いられることがあり、したがって本発明の適用は、前述の説明または図面に例示された細部や構成要素の組合せに制限されない。例えば、１つの実施形態の中で説明された態様は、他の実施形態の中で説明された態様と任意の方法で結合することができる。
【００７３】
特許請求の範囲の構成要素を修飾する、特許請求の範囲中の「第１の」、「第２の」、「第３の」などの順序を示す用語の使用は、それ自体、いかなる優先順位、先行性または他の特許請求の範囲の構成要素に対する従属性、または方法が実行される計時的な順序を伴うものではなく、特許請求の範囲の構成要素を識別するために、別の構成要素と（順序を示す用語を使用しなければ）同一の名前を有する１つの特許請求の範囲の構成要素を識別する符号として単に用いられているにすぎない。
【００７４】
また、本明細書に用いた表現および用語は説明を目的とするものであって、制限的なものとして扱うべきではない。本明細書での「含む」、「備える」、「有する」、および、これらの変化形の用語の使用は、従来のアイテムのみならず、今後挙げられるアイテムやこれらの均等物を包含することが意図されている。
【００７５】
そのような変更形態、修正形態および改良形態は、この開示の一部分であることが意図され、かつ本発明の精神および範囲内にあるものと意図されている。したがって、前述の説明および図面は例にすぎない。
【図面の簡単な説明】
【００７６】
【図１】インストルメントされるプログラムの一部を示す図である。
【図２Ａ】本発明の１つの実施形態によるプローブ関数を組み込んだ修正プログラムを示す図である。
【図２Ｂ】本発明の第２の実施形態によるプローブ関数を組み込んだ修正プログラムを示す図である。
【図３】本発明のさらなる実施形態によるプローブ関数を組み込んだ修正プログラムを示す図である。
【図４】本発明によるプログラム実装プロセスのフローチャートである。
【符号の説明】
【００７７】
２２０、２６０、３２０、３６０  ラッパー関数
２３０、２５６  ジャンプ命令
２７０、３３０  リターン命令
【図１】
2006268833.tif 000003
【図２Ａ】
2006268833.tif 000004
【図２Ｂ】
2006268833.tif 000005
【図３】
2006268833.tif 000006
【図４】
2006268833.tif 000007