フィードバック最適化コンパイルで、アウトライン関数が作成されることがあります。これらは、「ソース」タブと「逆アセンブリ」タブで、特別なインデックス行として表示されます。「ソース」タブでは、注釈は、アウトライン関数に変換されたコードブロックに表示されます。
Function binsearchmod inlined from source file ptralias2.c into the 0. 0 . 58. if( binsearchmod( asize, &element ) ) { 0.240 0.240 59. if( key != (element << 1) ) { 0. 0. 60. error |= BINSEARCHMODPOSTESTFAILED; <関数: main -- 行 60 [_$o1B60.main] からのアウトラインコード> 0.040 0.040 [ 61] break; 0. 0. 62. } 0. 0. 63. } |
「逆アセンブリ」タブでは、アウトライン関数は通常、ファイルの末尾に表示されます。
<関数: main -- 行 85 [_$o1D85.main] からのアウトラインコード> 0. 0. [ 85] 100001034: sethi %hi(0x100000), %i5 0. 0. [ 86] 100001038: bset 4, %i3 0. 0. [ 85] 10000103c: or %i5, 1, %l7 0. 0. [ 85] 100001040: sllx %l7, 12, %l5 0. 0. [ 85] 100001044: call printf ! 0x100101300 0. 0. [ 85] 100001048: add %l5, 336, %o0 0. 0. [ 90] 10000104c: cmp %i3, 0 0. 0. [ 20] 100001050: ba,a 0x1000010b4 <関数: main -- 行 46 [_$o1A46.main] からのアウトラインコード> 0. 0. [ 46] 100001054: mov 1, %i3 0. 0. [ 47] 100001058: ba 0x100001090 0. 0. [ 56] 10000105c: clr [%i2] <関数: main -- 行 60 [_$o1B60.main] からのアウトラインコード> 0. 0. [ 60] 100001060: bset 2, %i3 0. 0. [ 61] 100001064: ba 0x10000109c 0. 0. [ 74] 100001068: mov 1, %o3 |
アウトライン関数の名前は角括弧内に表示され、コードの取り出し元関数の名前や、ソースコード内のセクションの先頭の行番号を含む、アウトライン化したコードのセクションに関する情報をエンコードします。これらの符号化された名前は、リリースごとに異なります。アナライザは、読みやすい関数名を表示します。詳細は、「アウトライン関数」を参照してください。
アプリケーションのパフォーマンスデータの収集中にアウトライン関数が呼び出されると、アナライザは注釈付き逆アセンブリに特別な行を表示して、その関数の包括的メトリックを示します。詳細は、「包括的メトリック」を参照してください。
コンパイラは、関数内のループまたは並列化指令のある領域を並列化する場合、元のソースコードに含まれていない新しい本体関数を作成します。こうした関数については、「OpenMP ソフトウェアの実行の概要」で説明しています。
コンパイラは、並列構造の種類、構造の取り出し元関数の名前、元のソースにおける構造の先頭の行番号、並列構造のシーケンス番号などをエンコードする本体関数に、符号化名を割り当てます。これらの符号化された名前は、マイクロタスクライブラリのリリースごとに異なりますが、より分かりやすい名前に復号化されて表示されます。
次に、関数リストに表示されるような一般的なコンパイラ生成の本体関数を示します。
7.415 14.860 psec_ -- 行 9 [_$s1A9.psec_] からの OMP 領域 3.873 3.903 craydo_ -- 行 10 [_$d1A10.craydo_] からの MP doall |
この例で分かるように、構造が抽出された関数の名前が最初に示され、次に並列構造の種類、並列構造の行番号、コンパイラ生成の本体関数の符号化名が角括弧に表示されます。同様に、逆アセンブリコードには、特別なインデックス行が生成されます。
0. 0. <関数: psec_ -- 行 9 [_$s1A9.psec_] からの OMP 領域> 0. 7.445 [24] 1d8cc: save %sp, -168, %sp 0. 0. [24] 1d8d0: ld [%i0], %g1 0. 0. [24] 1d8d4: tst %i1 |
0. 0. <関数: craydo_ -- 行 10 [_$d1A10.craydo_] からの OMP doall> 0. 0.030 [ ?] 197e8: save %sp, -128, %sp 0. 0. [ ?] 197ec: ld [%i0 + 20], %i5 0. 0. [ ?] 197f0: st %i1, [%sp + 112] 0. 0. [ ?] 197f4: ld [%i5], %i3 |
Cray の指令では、関数はソースコード行番号に関連付けされていない可能性があります。このような場合は、行番号の代わりに [ ?] が表示されます。注釈付きソースコードにインデックス行が表示される場合は、次のようにインデックス行は行番号なしで命令を示します。
9. c$mic doall shared(a,b,c,n) private(i,j,k) 以下のループは 23 行目のループと融合しました 以下のループは自動並列化処理が有効でないため並列化されていません 以下のループは自動並列化されました 以下のループは 12 行目のループと交換されました 以下のループは 12 行目のループと交換されました 3.873 3.903 <関数: craydo_ -- 行 10 [_$d1A10.craydo_] からの MP doall, 行番号なしの命令> 0. 3.903 10. do i = 2, n-1 |
インデックス行やコンパイラのコメント行は、実際の表示では折り返されません。
動的にコンパイルされる関数は、プログラムの実行中にコンパイルされてリンクされる関数です。コレクタ API 関数 collector_func_load() を使用して必要な情報をユーザーが提供しないかぎり、コレクタは C や C++ で記述された動的にコンパイルされる関数に関する情報を持っていません。「関数」タブ、「ソース」タブ、「逆アセンブリ」タブに表示される情報は、次のように、collector_func_load() に渡される情報によって異なります。
情報が提供されていない場合、つまり collector_func_load() が呼び出され ていない場合は、動的にコンパイルされて読み込まれた関数が、関数リストに <Unknown> として表示されます。関数ソースも逆アセンブリコードも、アナライザには表示されません。
ソースファイル名と行番号のテーブルが提供されていない場合に、関数の名前、サイズ、およびアドレスが指定されている場合は、動的にコンパイルされて読み込まれる関数の名前とそのメトリックが関数リストに表示されます。注釈付きソースは利用可能で、逆アセンブリ命令は表示できます。ただし、行番号は、未知であることを示すために [?] で示されます。
ソースファイル名を指定して、行番号テーブルを提供しないと、アナライザによって表示される情報は、ソースファイル名を指定しない場合と似ています。ただし、注釈付きソースの先頭には、関数が行番号のない命令で構成されていることを示す特別なインデックス行が表示されます。次に例を示します。
1.121 1.121 <関数 func0, 行番号なしの命令> 1. #include <stdio.h> |
ソースファイル名と行番号のテーブルが提供されている場合、関数とそのメトリックは、従来の方法でコンパイルされた関数と同じように、「関数」タブ、「ソース」タブ、および「逆アセンブリ」タブに表示されます。
コレクタ API 関数の詳細については、「動的な関数とモジュール」を参照してください。
Java プログラムでは、ほとんどのメソッドが JVM ソフトウェアによってインタプリタされます。別個のスレッドで動作する Java HotSpot 仮想マシンは、インタプリタの実行中にパフォーマンスを監視します。監視プロセス中仮想マシンは、1 つ以上のインタプリタを行なっているメソッドを取り出し、それらのメソッド用のマシンコードを生成し、元のマシンコードをインタプリタするのではなくさらに効率の良いマシンコードバージョンを実行することを決定する場合があります。
次の例に示すように、Java プログラムの場合は、コレクタ API 関数を使用する必要はありません。アナライザは、メソッドのインデックス行の下の特別な行を使って、注釈付き逆アセンブリリストでの Java HotSpot がコンパイルしたコードの存在を示します。
11. public int add_int () { 12. int x = 0; <関数: Routine.add_int()> 2.832 2.832 Routine.add_int() <HotSpot コンパイル済みリーフ命令> 0. 0. [ 12] 00000000: iconst_0 0. 0. [ 12] 00000001: istore_1 |
逆アセンブリリストには、コンパイルされた命令ではなく、インタプリタされたバイトコードのみが示されます。デフォルトでは、コンパイルされたコードのメトリックは、特別な行の隣りに表示されます。排他的および包括的 CPU 時間は、インタプリタされたバイトコードの各行に示されているすべての包括的および排他的 CPU 時間の合計とは異なります。通常は、何回かメソッドが呼び出されると、コンパイルされた命令の CPU 時間は、インタプリタされたバイトコードの CPU 時間の合計より多くなります。なぜなら、インタプリタされたコードは、メソッドが最初に呼び出されたときに一度だけ実行されるのに対し、コンパイルされたコードはその後も実行されるからです。
注釈付きソースには、Java HotSpot でコンパイルされた関数は表示されません。その代わりに、行番号なしで命令を示す特別なインデックス行が表示されます。たとえば、前述の逆アセンブリの抜粋に対応する注釈付きソースは、次のようになります。
11. public int add_int () { 2.832 2.832 <関数: Routine.add_int(), 行番号なしの命令> 0. 0. 12. int x = 0; <関数: Routine.add_int()> |
ネイティブコードは、Java コードにより Java Native Interface (JNI) を介して呼び出される、元は C、C++、または Fortran で記述されたコンパイル済みコードです。次の例は、デモプログラム jsynprog に関連付けられたファイル jsynprog.java の注釈付き逆アセンブリからの抜粋です。
5. class jsynprog <関数: jsynprog.<init>()> 0. 5.504 jsynprog.JavaCC() <Java ネイティブメソッド> 0. 1.431 jsynprog.JavaCJava(int) <Java ネイティブメソッド> 0. 5.684 jsynprog.JavaJavaC(int) <Java ネイティブメソッド> 0. 0. [ 5] 00000000: aload_0 0. 0. [ 5] 00000001: invokespecial <init>() 0. 0. [ 5] 00000004: return |
ネイティブメソッドは Java ソースに含まれていないため、jsynprog.java の注釈付きソースの先頭には、行番号なしで命令を示す特別なインデックス行を使って各 Java ネイティブメソッドが表示されます。
0. 5.504 <関数: jsynprog.JavaCC(), 行番号なしの命令> 0. 1.431 <関数: jsynprog.JavaCJava(int), 行番号なしの命令> 0. 5.684 <関数: jsynprog.JavaJavaC(int), 行番号なしの命令> |
実際の注釈付きソースの表示では、インデックス行は折り返されません。
コンパイラは、通常以上の最適化が可能な関数への呼び出しを見分けることができます。このような呼び出しの一例として、渡される引数の一部が定数である関数への呼び出しがあります。コンパイラは、最適化できる特定の呼び出しを見つけると、クローンと呼ばれるこの関数のコピーを作成して、最適化コードを生成します。
注釈付きソースでは、コンパイラのコメントは、クローン生成関数が作成されたかどうかを示します。
0. 0. ソースファイル clone.c の関数 foo がクローン関数 _$c1A.foo を 作成しました。定義パラメータはクローンに伝達されました 0. 0.570 27. foo(100, 50, a, a+50, b); |
実際の注釈付きソースの表示では、コンパイラのコメント行は折り返されません。
クローン関数名は、特定の呼び出しを識別する、符号化された名前です。前述の例では、コンパイラのコメントは、クローン生成関数の名前が _$c1A.foo であることを示しています。次に示すように、この関数は関数リストに表示されます。
0.350 0.550 foo 0.340 0.570 _$c1A.foo |
クローン生成関数はそれぞれ別の命令セットを持っているので、注釈付き逆アセンブリリストには、クローン生成関数が別々に表示されます。これらはソースファイルに関連付けられていないため、命令はいずれのソース行番号とも関連付けられていません。次に、クローン生成関数の注釈付き逆アセンブリの最初の数行を示します。
0. 0. <関数: _$c1A.foo> 0. 0. [?] 10e98: save %sp, -120, %sp 0. 0. [?] 10e9c: sethi %hi(0x10c00), %i4 0. 0. [?] 10ea0: mov 100, %i3 0. 0. [?] 10ea4: st %i3, [%i0] 0. 0. [?] 10ea8: ldd [%i4 + 640], %f8 |
静的関数は、ライブラリ内でよく使用されます。これは、ライブラリ内部で使用される関数名が、ユーザーが使用する可能性のある関数名と衝突しないようにするためです。ライブラリをストリップすると、静的関数の名前はシンボルテーブルから削除されます。このような場合、アナライザは、ストリップ済み静的関数を含むライブラリ内のすべてのテキスト領域ごとに擬似的な名前を生成します。この名前は <static>@0x12345 という形式で、@ 記号に続く文字列は、ライブラリ内のテキスト領域のオフセット位置を表します。アナライザは、連続する複数のストリップ済み静的関数と単一のストリップ済み静的関数を区別できないため、複数のストリップ済み静的関数のメトリックがまとめて表示されることがあります。静的関数の例は、次に示す jsynprog デモの関数リストで参照できます。
0. 0. <static>@0x18780 0. 0. <static>@0x20cc 0. 0. <static>@0xc9f0 0. 0. <static>@0xd1d8 0. 0. <static>@0xe204 |
「PC」タブでは、前述の関数は、次のようにオフセットとともに示されます。
0. 0. <static>@0x18780 + 0x00000818 0. 0. <static>@0x20cc + 0x0000032C 0. 0. <static>@0xc9f0 + 0x00000060 0. 0. <static>@0xd1d8 + 0x00000040 0. 0. <static>@0xe204 + 0x00000170 |
ストリップ済みライブラリ内で呼び出された関数は、「PC」タブで次のように表示される場合もあります。
<library.so> -- 関数が見つかりません + 0x0000F870 |
注釈付き逆アセンブリでは、アウトライン関数が要した時間にタグを付けるための特別な行が存在します。
次に、アウトライン関数が呼び出されたときに表示される注釈付き逆アセンブリの例を示します。
0. 0. 43. else 0. 0. 44. { 0. 0. 45. printf("else reached\n"); 0. 2.522 <アウトライン関数の包括的メトリック> |
注釈付き逆アセンブリリストに示される擬似行の <branch target> (分岐先) は、バックトラッキングアルゴリズムが分岐先内で実行するため、その有効アドレスを見つけるためのバックトラッキングに失敗した命令の PC に対応します。