(57)【特許請求の範囲】
【請求項１】
ユーザ関数インスタンスを推測することによってユーザとカーネル情報とを含む統合コールスタックトレースに基づいて内部アプリケーションステータスを推測することと、
関数呼び出しパスに関する情報を含む呼び出しコンテキスト符号化を生成することと、
前記符号化された呼び出しコンテキストに基づいてアプリケーションパフォーマンスを分析することであって、
トップダウンのレイテンシー分解を実行することと、
各関数呼び出しパスのコストがどれほど大きいかに従って呼び出しコンテキストをランク付けすることとを備える、パフォーマンス推測のための方法。
【請求項２】
内部アプリケーションステータスを推測することは、個々の関数呼び出しのレイテンシーを推測することを含む請求項１に記載の方法。
【請求項３】
前記呼び出しコンテキスト符号化に推測されたパフォーマンス情報で注釈を付けることをさらに含む請求項２に記載の方法。
【請求項４】
トップダウンのレイテンシー分解を実行することは、
スタックトレース内の各関数の合計実行時間を推定することと、
各関数に起因するレイテンシーを判定するために、後に開始した、並行して実行している関数に起因する実行時間を取り除くことと、を含む請求項１に記載の方法。
【請求項５】
合計実行時間を推定することは、関数が出現する第１のスタックトレースと、前記関数がもはや出現しない第１のスタックトレースとの差を見出すことを含む請求項４に記載の方法。
【請求項６】
合計実行時間を推定することは、関数が出現する第１のスタックトレースと、前記関数が出現する最後の連続するスタックトレースとの差を見出すことを含む請求項４に記載の方法。
【請求項７】
呼び出しコンテキストをランク付けすることは、各関数呼び出しパスごとの総コストに従ってランク付けすることを含む請求項１に記載の方法。
【請求項８】
呼び出しコンテキストをランク付けすることは、２つの入力ワークロード間のレイテンシーの差に従ってランク付けすることを含む請求項１に記載の方法。
【請求項９】
ユーザ関数インスタンスを推測することによってユーザとカーネル情報とを含む統合コールスタックトレースに基づいて内部アプリケーションステータスを推測するように、および関数呼び出しパスに関する情報を含む呼び出しコンテキスト符号化を生成するように構成されているプロセッサを備える推測モジュールと、
トップダウンのレイテンシー分解を実行すること、および各関数呼び出しパスのコストがどれほど大きいかに従って呼び出しコンテキストをランク付けすることにより、前記符号化された呼び出しコンテキストに基づいてアプリケーションパフォーマンスを分析するように構成されているパフォーマンス分析モジュールと、を備えるパフォーマンス推測のためのシステム。
【請求項１０】
前記推測モジュールは、個々の関数呼び出しのレイテンシーを推測するようにさらに構成される請求項９に記載のシステム。
【請求項１１】
前記呼び出しコンテキスト符号化に推測されたパフォーマンス情報で注釈を付けることをさらに備える請求項１０に記載のシステム。
【請求項１２】
トップダウンのレイテンシー分解を実行することは、
スタックトレース内の各関数の合計実行時間を推定することと、
各関数に起因するレイテンシーを判定するために、後に開始した、並行して実行している関数に起因する実行時間を取り除くことと、を含む請求項９に記載のシステム。
【請求項１３】
合計実行時間を推定することは、関数が出現する第１のスタックトレースと、前記関数がもはや出現しない第１のスタックトレースとの差を見出すことを含む請求項１２に記載のシステム。
【請求項１４】
合計実行時間を推定することは、関数が出現する第１のスタックトレースと、前記関数が出現する最後の連続するスタックトレースとの差を見出すことを含む請求項１２に記載のシステム。
【請求項１５】
呼び出しコンテキストをランク付けすることは、各関数呼び出しパスごとの総コストに従ってランク付けすることを含む請求項９に記載のシステム。
【請求項１６】
呼び出しコンテキストをランク付けすることは、２つの入力ワークロード間のレイテンシーの差に従ってランク付けすることを含む請求項９に記載のシステム。
【発明の詳細な説明】
【背景技術】
【０００１】
関連出願情報
【０００２】
本出願は、本明細書において参照することで内容を援用する、２０１３年１０月１４日に出願した仮特許出願第６１／８９０，３９８号明細書の優先権を主張するものである。
【０００３】
ソフトウェアプロジェクトにおいては、パフォーマンスの問題が生じがちである。プロファイリングは、ソフトウェアの動作特性を測定するソフトウェア分析の形式である。従来のプロファイラは、デバッギング段階の明確に定義されたテスト環境においては効果的なツールであったが、このレビュープロセスを多くのパフォーマンスバグがくぐり抜けて残存し、エンドユーザには不便と苛立ちが生じている。導入において統合されて別個に更新されているさまざまな相互依存型のソフトウェアレイヤは複雑であるため、完全なテストとパフォーマンスバグの抑制は難しい課題となっている。
【０００４】
ほとんどのプロファイラは、プロファイリングコードを、テスト中のソフトウェアプロジェクトのソースコードに組み込む。ソースコードがデバッギング段階の間使用できる場合もあるが、多くのソフトウェアはバイナリ形式で配布されているため、デバッギング後にそのようなツールを使用することは難しい。動的トランスレータは、装備の便宜上、研究界において広く使用されており、中にはこうしたトランスレータに基づくプロファイリングツールもある。これらのツールは、ソースコードを必要とすることなく、プロファイリング命令を、ソフトウェアに透過的に挿入することができる。しかし、そのようなツールのオーバーヘッドは高いので、やはり同様に、こうしたツールが適しているのはデバッギング段階に限られている。
【発明の概要】
【０００５】
パフォーマンス推測のための方法は、ユーザ関数インスタンスを推測することによってユーザとカーネル情報とを含む統合コールスタックトレース（ｕｎｉｆｉｅｄ  ｃａｌｌ  ｓｔａｃｋ  ｔｒａｃｅ）に基づいて内部アプリケーションステータスを推測することを含む。関数呼び出しパスに関する情報を含む呼び出しコンテキスト符号化が生成される。アプリケーションパフォーマンスは、符号化された呼び出しコンテキストに基づいて分析される。分析は、トップダウンのレイテンシー分解を実行すること、および各関数呼び出しパスのコストがどれほど大きいかに従って呼び出しコンテキストをランク付けすることを含む。
【０００６】
パフォーマンス推測のためのシステムは、ユーザ関数インスタンスを推測することによってユーザとカーネル情報とを含む統合コールスタックトレースに基づいて内部アプリケーションステータスを推測するように、および関数呼び出しパスに関する情報を含む呼び出しコンテキスト符号化を生成するように構成されているプロセッサを含む推測モジュールを含む。パフォーマンス分析モジュールは、トップダウンのレイテンシー分解を実行すること、および各関数呼び出しパスのコストがどれほど大きいかに従って呼び出しコンテキストをランク付けすることにより、呼び出しコンテキスト符号化に基づいてアプリケーションパフォーマンスを分析するように構成されている。
【図面の簡単な説明】
【０００７】
【図１】本発明の原理を用いてアプリケーションパフォーマンスを推測するための方法を示すブロック／流れ図である。
【図２】本発明の原理を用いた動的呼び出しコンテキスト符号化のための方法を示すブロック／流れ図である。
【図３】本発明の原理を用いた動的呼び出しコンテキストコーディングの一例を示す図である。
【図４】本発明の原理を用いたコールスタック符号化の擬似コードである。
【図５】本発明の原理を用いた関数インスタンス推測のための方法を示すブロック／流れ図である。
【図６】本発明の原理を用いた関数レイテンシー推測の擬似コードである。
【図７】本発明の原理を用いたパフォーマンス注釈付き呼び出しコンテキストツリー（ｐｅｒｆｏｒｍａｎｃｅ−ａｎｎｏｔａｔｅｄ  ｃａｌｌｉｎｇ  ｃｏｎｔｅｘｔ  ｔｒｅｅ）を示す図である。
【図８】本発明の原理を用いた抽出された関数レイテンシーを示す図である。
【図９】本発明の原理を用いたトップダウンのレイテンシー分解の擬似コードである。
【図１０】本発明の原理を用いた総コストに基づくランク付けを示す図である。
【図１１】本発明の原理を用いたパフォーマンス推測のためのシステムを示すブロック図である。
【発明を実施するための形態】
【０００８】
本発明の原理の実施形態は、プロダクショントレーサからの（ユーザおよびカーネル情報を共に含む）統合コールスタックトレースを入力として使用して、プログラムのパフォーマンスを推測し、パフォーマンスバグを分析する。それにより、本発明の実施形態は、軽量かつ詳細なコンテキスト上のパフォーマンス分析を達成する。
【０００９】
第１に、本発明の実施形態は、複数のプログラムレイヤ内のソフトウェアのレイテンシーを、きめの細かいコンテキスト依存の方法で推測する。本発明の実施形態は、プログラムを直接監視するのではなく、効率的なプロダクションイベントトレーサによって提供される統合スタックトレースを入力として使用する。そうすることで、本発明の原理は、ランタイムオーバーヘッドを伴うことなくオフライン分析段階としてプロダクションシステムに容易に採用されるようになる。
【００１０】
第２に、本発明の実施形態は、コストの大きな呼び出しパスのランク付けメカニズムを使用して、パフォーマンスバグの根本的原因を容易に局在化できるようにする。多くのソフトウェアレイヤのきめの細かい詳細は、膨大量の情報を生成する。ランク付け呼び出しパスは、プログラムの実行中に最もコストの大きい関数呼び出しパスを強調表示することによって、分析プロセスを簡略化する。これらの分析は、ソースコードへのアクセス、またはプログラムの再コンパイルを必要としない。その結果、本発明の実施形態は、ポストデバッグの段階において使用することで利便性が高まる。
【００１１】
次に、図１を参照して、パフォーマンス推測のための方法を説明する。ブロック１０２は、ユーザプログラムとカーネルコード情報との双方を含むスタックトレースイベントである、統合コールスタックトレースを入力として受け入れる。１つの例示的な実施形態は、イベントトレーサのスタックウォークイベントを使用する。ユーザとカーネルスペースとの双方をカバーするこのイベントストリームは、カーネルによって生成される。したがって、イベントのタイムスタンプはカーネルイベントのものであるが、本発明の分析は、ユーザプログラム関数呼び出しにおけるレイテンシーに最も配慮している。
【００１２】
したがって、ブロック１０４は、内部アプリケーションステータスに関する情報を推測する。ブロック１０６は、特に、ユーザ関数インスタンスを推測する。次いで、ブロック１０６は、呼び出しコンテキストを推測する。呼び出しコンテキストは、関数呼び出しの特定のシーケンスを表すスタック内のアクティブな関数のリストである。ブロック１０６は、パフォーマンスデバッギングのために呼び出しコンテキストを使用するが、ここでトレース内のスタックイベントは呼び出しコンテキストを表す。呼び出しコンテキストの処理を効率的にするため、ブロック１０８は、関数のリストを整数として表すことによって、呼び出しコンテキストを符号化する。次いで、呼び出しコンテキストは、計算およびメモリにおいて極めて低いオーバーヘッドで処理することができる。
【００１３】
コンテキスト認識のパフォーマンス分析は、ブロック１１２のトップダウンのレイテンシー分解、およびブロック１１４のパフォーマンス注釈付き呼び出しコンテキストのランク付けを含むブロック１１０によって実行される。ブロック１０４において推測された関数レイテンシーは、すべてのソフトウェアレイヤに対するものである。コールスタック内の複数の関数にわたって重なり合っている期間があるので、ブロック１１２は、遅延に寄与している実際の時間を抽出する。
【００１４】
ブロック１１４は、分析すべき情報のスケールに対処する。プログラムの動的コンテキストは、膨大量の情報を表すことができる。ブロック１１４のランク付け方式は、上位Ｎの最もコストの大きな関数呼び出しパスを表す呼び出しコンテキストをランク付けする。次いで、分析の最終出力は、ブロック１１６において生成される。
【００１５】
次に、図２を参照して、動的呼び出しコンテキスト符号化ブロック１０８のさらなる詳細を説明する。ブロック２０２は、統合コールスタックトレース１０２に基づいてコールスタック符号化を実行し、ブロック２０６のような符号化ＩＤのトレースを生成する。このプロセス中に、トレースに出現するすべてのコンテキストは、ブロック２０４において、符号化動的呼び出しコンテキストツリーおよび符号化テーブルという２つのデータ構造に編成される。重複するコンテキストは、これらのデータ構造を使用して同じＩＤとして符号化される。
【００１６】
次に、図３を参照して、符号化動的呼び出しコンテキストツリー３０２を、対応する符号化テーブル３０４と共に説明する。スタックトレース１０２のイベントは、符号化テーブル３０４によって説明されている動的呼び出しコンテキストツリー３０２を形成するために使用される。各トレースは、エンドノード、ツリー３０２のエンドノードを指すポインタ、およびツリー３０２をトラバースするパスの記述に対応するＥｎｃｏｄｅｄ  ＩＤとして符号化される。
【００１７】
次に、図４を参照して、コールスタック符号化の擬似コードを説明する。図３の例を使用すると、スタックイベントは、異なるタイムスタンプｔ１、ｔ２、ｔ３、およびｔ４において発生する。第１のイベントＳについて、ｔ１において、ＥｎｃｏｄｅＩＤ関数は、ノードＡ、Ｂ、およびＤを作成するために、スタックイベントの各関数に対してｇｅｔＣｈｉｌｄを呼び出すことによって、ｍａｉｎ関数から呼び出される。ｇｅｔＣｈｉｌｄ関数は、ツリー３０２のノードを作成するためのユーティリティ関数である。
【００１８】
したがって、本発明の実施形態は、呼び出しコンテキストパスの最終ノードに符号化ＩＤを格納し、ＩＤとノードとのマッピングを保持する。ｇｅｔＬｅａｆＩＤ関数は、このノードへのＩＤの事前の割り当てがあるかどうかを、最初に判定する。これが新しいノードである場合、一意のＩＤが割り当てられ、ＩＤとノードを指すポインタとのペアは、符号化テーブル３０４に格納される。ｔ１における第１のスタックトレースの例において、最終ノードはＤ１である。図３の下部の符号化テーブルは、符号化ＩＤ１が、ノードＤ１を指すそのポインタと共に、このパスに割り当てられていることを示す。呼び出しコンテキストツリー３０２が、異なる関数のシーケンスを通じてそこに到達する場合、所与の関数に対して異なるノードを使用することに留意されたい。たとえば、Ｄ１は、図３において、Ｄ２とは異なるノードを占有していることを示す。
【００１９】
同じ関数パターンについて、ＥｎｃｏｄｅＩＤは、既存のノードを再使用してスタックイベントを符号化する。たとえば、Ｔ２における次のイベントは、同一のパスを有する。したがって、この関数は、この場合も同様に追加のノードを作成することなく、１の符号化ＩＤを返す。第３および第４のイベントが処理された後、符号化呼び出しコンテキストツリーおよび符号化テーブルは、図３の下部に示されるように構築される。
【００２０】
符号化ＩＤは、図４において説明するＤｅｃｏｄｅＩＤ関数を使用して、一連の関数に変換し戻すことができる。この関数は、入力ＩＤに対応するノードポインタを見出す。符号化パスは、ルートノードに到達するまで親ポインタを上方向にトラバースすることによって回復する。たとえば、図３は、ＩＤ１がノードＤ１を指していることを示す。親ノードは、復号パスを見つけるために上方向にトラバースする。
【００２１】
次に、図５を参照して、ユーザ関数インスタンス推測ブロック１０６のさらなる詳細を説明する。ブロック５０２は、符号化コールスタックイベントのトレース、動的呼び出しコンテキストツリーおよび符号化テーブル２０４から関数レイテンシーを推測する。パフォーマンス情報５０４が抽出されると、それは符号化動的呼び出しコンテキストツリー２０４に累積されて、パフォーマンス注釈付き呼び出しコンテキストツリー５０６を作成する。
【００２２】
ブロック５０２は、時間順にタイムライン内のイベントをスキャンし（たとえば、Ｔ１−＞Ｔ２−＞Ｔ３−＞Ｔ４）、スタック内の関数の出現および消失に基づいて関数呼び出しおよび戻りを推測する。図３の例示のトレースを考慮すると、関数Ｂが時間Ｔ１において出現し、Ｔ３において消失する場合、Ｂの実行時間は、タイムスタンプＴ３とＴ１との差であると見なすことができる。この推定に取り組む方法は複数ある。アグレッシブ推定（ａｇｇｒｅｓｓｉｖｅ  ｅｓｔｉｍａｔｉｏｎ）では、戻りを新しいイベントの出現と見なす。したがって、Ｔ１−Ｔ３は、関数Ｂに対して推定された時間となる。コンサバティブ推定（ｃｏｎｓｅｒｖａｔｉｖｅ  ｅｓｔｉｍａｔｅ）では、スタック内の実際の出現に基づいてライフタイムを考慮する。上記の例に続いて、Ｔ２とＴ３の間に時間のギャップが存在し、関数Ｂは、Ｔ２の直後に完了する。したがって、Ｂの期間に対するコンサバティブ推定は、Ｔ１−Ｔ２となる。
【００２３】
次に、図６を参照して、関数レイテンシー推測ブロック５０２の擬似コードを説明する。ｅｘｔｒａｃｔＩｎｓｔａｎｃｅｓ関数は、各スタックイベントを処理するためにｎｅｗＥｖｅｎｔ関数を呼び出す。関数がスタックに出現すると、アルゴリズムは、この関数を、Ｒｅｇｉｓｔｅｒデータ構造に入れることによって追跡する。この関数が消失すると、戻されたものと見なされる。次いで、これまでの追跡された時間は、行３５で関数名およびその固有の呼び出しコンテキストと共に格納される。
【００２４】
トレースの最後に、すべての関数は、戻ったものと見なされる。この操作に対して、すべての登録された関数をクローズして対応する関数インスタンスを記録するｃｌｏｓｅＲｅｇｉｓｔｅｒＡＬＬ関数が呼び出される。
【００２５】
次に、図７を参照して、パフォーマンス注釈付き呼び出しコンテキストツリー５０６の一例を説明する。パフォーマンス異常がなぜ生じるのかを理解するために、抽出された関数情報を、そのコンテキスト情報と共に記録することが重要である。そのために、拡張表現が、コンテキスト情報と個々の関数の推定されたパフォーマンスレイテンシーとを組み合わせるパフォーマンス注釈付き呼び出しコンテキストツリー５０６の形式で使用される。示されるツリーは、図３からのトレースに基づいている。コンサバティブ推定は、簡潔にするために後段において使用される。
【００２６】
次に、図８を参照して、抽出された関数レイテンシーの例を説明する。関数Ａは、実行期間全体を通じて稼働する。これは、たとえば、最初の関数として実行され、次いでプログラムの全実行時にスタック内にあるｍａｉｎ関数であってもよい。Ａは、関数がそれぞれのレイテンシーに期間の重複があるように、その他の関数Ｂ、Ｃ、および間接的にＤをさらに呼び出す。矢印の色の濃い部分は、関数が本当にレイテンシーに寄与する実際の時間を表す。関数レイテンシーの根本的原因を正しく局在化するため、重複する（白色の）期間は差し引かれる。
【００２７】
次に、図９を参照して、それぞれブロック１１２および１１４におけるトップダウンレイテンシー分解とコンテキストランク付けの擬似コードを説明する。パフォーマンス注釈付き呼び出しコンテキストツリーの入力により、ブロック１１２は、自身のレイテンシーを計算し、各ノードを再帰的に訪れて、子ノードのレイテンシーを差し引くことによって、重複する期間を取り除く。成果は、自身のレイテンシーを伴うパフォーマンス注釈付き呼び出しコンテキストツリーである。
【００２８】
コンテキスト呼び出しツリーは、極めて複雑なものになりうる。この問題を解決するため、本発明の実施形態は、ブロック１１４において、呼び出しコンテキストのランク付けを行って、コストの大きな呼び出しコンテンツの局在化を自動化する。ブロック１１４は、ランク付けされたコストの大きな呼び出しコンテキストを生成する。パフォーマンスコストを使用してコンテキストをランク付けする１つの手法は、パスの総コスト（すなわち、コンテキスト）に基づくランク付けを含む。
【００２９】
次に、図１０を参照して、総コストに基づくランク付けを説明する。個々の呼び出しパスは、呼び出しコンテキストツリーから抽出され、各パスの総コストが判定される。この例は、各ノードの累積され推測されたレイテンシーを使用する単純な方式を示す。たとえば、上部のパス（ＩＤ１）において、関数Ｄ、Ｂ、およびＡはそれぞれ、Ａについて（Ｔ４−Ｔ１）−（Ｔ２−Ｔ１）−Ｔ４−Ｔ３）、Ｂについて（Ｔ２−Ｔ１）−（Ｔ２−Ｔ１）、およびＤについて（Ｔ２−Ｔ１）のレイテンシーを有する。３つのレイテンシーを合計した後、パスに対する総計はＴ３−Ｔ１となる。
【００３０】
各パスごとの総コストが計算された後、パスはコストに従ってランク付けされる。たとえば、第１、第２、および第３のパスがそれぞれ１０、９、および９のコストを有する場合、パスは、図１０のマトリクスに従ってランク付けされる。パスは、それぞれの総コストの順序で下からリストされる。たとえばパスＩＤ１のような、最高コストを伴うパスは、最高ランク付けを有するマトリクスの下部に配置される。
【００３１】
多くのパフォーマンスバグの症状は、たとえば大きな入力サイズなど、特定のワークロードのシナリオで引き起こされる。プログラムの実行中には、ワークロードのサイズまたは入力には関わりなく高いレイテンシーを要する関数もありうる。そのような場合、実行のその部分を下方にランク付けして、代わりにワークロード変更によるワークロード拡大をより重要視することがさらに望ましい。そのような事例に対処するため、ランク付けは、２つの入力ワークロードの差を使用して形成してもよい。各パスのコストは、コンテキスト依存性をワークロード変更に優先して、２つのパスの各関数の差の合計として計算される。図９のＲａｎｋＰａｔｈｓ関数は、この計算の詳細を示す。
【００３２】
行１１は、２つの呼び出しコンテキストツリーからパスを生成する。これは、大きい入力のパスを列挙し、各パスごとに、図９では小さな入力のパスにおいて同じパスを見出す。第２の入力Ｐ２にしか存在しないパスの場合、小さな入力のコストは、Ｐ２からのパスのみを使用することによってゼロであると見なされる。パスが、パスセットＰ１とＰ２との両方に共通である場合、コストは、各関数ノードの差の合計として計算される。
【００３３】
計算された値および関数情報は、リストデータ構造に格納される。繰り返しが終了した後、リストはアグレッシブモードおよびコンサバティブモードで計算されたパスの差を使用する２つの方法でソートされる。ユーザは、総数Ｎの結果を指定し、これらの結果は、ブロック１１６においてレポートとして提示される。これにより、各パスのコストがどの程度入力に依存しているかが明らかになる。
【００３４】
プロファイリングコードを監視対象のプログラムに採用して統計を収集するのではなく、本発明の実施形態は、ＯＳトレーサによって生成される全システムレイヤの統合スタックトレースを使用する。そうすることで、本発明の実施形態は、プログラムへのフックを回避し、ソースコードにアクセスする必要性をなくすことができる。入力はきめの粗いものであるが、本発明の実施形態は、スタックトレースから推測される関数レイテンシーに関する詳細な情報をもたらす。さらに、コストの大きな呼び出しコンテキストのランク付けは、パフォーマンス異常の根本的原因の候補を局在化する。
【００３５】
次に、図１１を参照して、パフォーマンス推測のためのシステム１１００を説明する。システム１１００は、プログラムを実行するプロセッサ１１０２と、プログラムのスタックトレース１１０６を格納するメモリ１１０４とを含む。推測モジュール１１０８は、スタックトレースにアクセスして、アプリケーションのステータスを推測し、動的呼び出しコンテキスト符号化を構築する。パフォーマンス分析モジュール１１１０は、アプリケーション内の関数のレイテンシーを分析し、どれが最もコストが大きいかに従って呼び出しコンテキストをランク付けする。
【００３６】
上記は、限定的ではなく、あらゆる点において説明的および例示的なものと理解すべきであり、本明細書において開示される本発明の範囲は、詳細な説明から判定されるべきではなく、特許法により認められている全範囲に従って解釈される特許請求の範囲から判定されるものとする。追加の情報は、本明細書の付属書Ａに掲載されている。本明細書において示され説明されている実施形態は、本発明の原理を説明するものに過ぎず、当業者であれば本発明の範囲および精神を逸脱することなくさまざまな変更を実施することができることを理解されたい。当業者であれば、本発明の範囲および精神を逸脱することなく、さまざまな他の特徴の組合せを実施することができよう。
【図１】
0006401786.tif 000002
【図２】
0006401786.tif 000003
【図３】
0006401786.tif 000004
【図４】
0006401786.tif 000005
【図５】
0006401786.tif 000006
【図６】
0006401786.tif 000007
【図７】
0006401786.tif 000008
【図８】
0006401786.tif 000009
【図９】
0006401786.tif 000010
【図１０】
0006401786.tif 000011
【図１１】
0006401786.tif 000012