Oracle® Solaris Studio 12.4: パフォーマンスアナライザ

印刷ビューの終了

更新: 2015 年 1 月
 
 

パフォーマンスアナライザの「ソース」ビューのレイアウト

「ソース」ビューは、いくつかの列に分かれています。左側には個々のメトリックの固定幅の列が表示され、右側には注釈付きソースが残りの幅で表示されます。

元のソース行の識別

注釈付きソースで黒字で表示されるすべての行は、元のソースファイルから取得されたものです。注釈付きソース列の各行の先頭の番号は、元のソースファイルの行番号に対応します。別の色で文字が表示されている行は、インデックス行かコンパイラのコメント行です。

「ソース」ビュー内のインデックス行

ソースファイルとは、オブジェクトファイルを生成するためにコンパイルされるか、またはバイトコードに解釈されるファイルのことです。オブジェクトファイルには通常、ソースコード内の関数、サブルーチン、またはメソッドに対応する実行可能コードの領域が 1 つ以上含まれています。パフォーマンスアナライザはオブジェクトファイルを解析して、それぞれの実行可能領域を関数として識別します。そして、オブジェクトコード内で見つけた関数を、オブジェクトコードに関連付けられたソースファイル内の関数、ルーチン、サブルーチン、またはメソッドにマップしようとします。パフォーマンスアナライザは、解析が成功すると、オブジェクトコードで検出された関数の最初の命令に対応する注釈付きソースファイル内の場所に、インデックス行を追加します。

注釈付きソースは、「関数」ビューに表示されるリストにインライン関数が表示されていない場合でも、インライン関数を含むすべての関数のインデックス行を表示します。「ソース」ビューには、インデックス行が赤いイタリック体で、テキストが山括弧内に示されます。もっとも単純な種類のインデックス行は、関数のデフォルトコンテキストに対応しています。関数のデフォルトソースコンテキストは、その関数の最初の命令が帰するソースファイルとして定義されます。次の例は、C 関数 icputime のインデックス行を示しています。

                    578. int
                    579. icputime(int k)
0.       0.         580. {
                         <Function: icputime>

この例が示すように、インデックス行は、最初の命令に続く行に表示されます。C ソースの場合は、最初の命令は、関数本体の先頭が開く括弧に対応します。Fortran ソースの場合は、各サブルーチンのインデックス行が、subroutine キーワードを含む行に続きます。また、次の例に示すように、main 関数のインデックス行が、アプリケーションの起動時に実行される最初の Fortran ソース命令に続きます。

    	     	     	     	1. ! Copyright (c) 2006, 2010, Oracle and/or its affiliates. All Rights Reserved.
    	     	     	     	2. ! @(#)omptest.f 1.11 10/03/24 SMI
    	     	     	     	3. ! Synthetic f90 program, used for testing openmp directives and the
    	     	     	     	4. !       analyzer
    	     	     	     	5. 
0.   	0.   	0.   	0.  	6.        program omptest
                                      <Function: MAIN>  
                                   7.
                                   8. !$PRAGMA C (gethrtime, gethrvtime)

場合によっては、パフォーマンスアナライザがオブジェクトコード内で見つけた関数を、そのオブジェクトコードに関連付けられたソースファイル内のどのプログラミング命令でもマップできないことがあります。たとえば、そのコードが #include されているか、またはヘッダーファイルなどの別のファイルからインライン化されている場合があります。

また、特別なインデックス行やコンパイラのコメントではない特殊な行は、赤で示されます。たとえば、コンパイラの最適化の結果、ソースファイルに記述されているコードに対応しないオブジェクトコード内の関数について、特別なインデックス行が作成される場合があります。詳細は、「ソース」タブ、「逆アセンブリ」タブ、「PC」タブの特別な行を参照してください。

コンパイラ解説

コンパイラのコメントは、コンパイラによって最適化されたコードがどのように生成されたかを示します。コンパイラ解説の行は、インデックス行や元のソース行と区別するために、青色で表示されます。 コンパイラのさまざまな部分で、実行可能ファイルに解説が組み込まれる可能性があります。各コメントは、ソースの特定の行に関連付けられます。注釈付きソースの書き込み時には、ソース行に対してコンパイラが生成するコメントが、ソース行の直前に挿入されます。

コンパイラのコメントは、最適化するためにソースコードに対して行われた変換の大部分に関する情報を提供します。こうした変換には、ループの最適化、並列化、インライン化、パイプライン化などがあります。次の例は、コンパイラ解説を示しています。

0.   	0.   	0.   	0.   	 28.       SUBROUTINE dgemv_g2 (transa, m, n, alpha, b, ldb,   &
     	     	     	     	 29.      &                   c, incc, beta, a, inca)
     	     	     	     	 30.       CHARACTER (KIND=1) :: transa
                                	 31.       INTEGER   (KIND=4) :: m, n, incc, inca, ldb
                                	 32.       REAL      (KIND=8) :: alpha, beta
                                	 33.       REAL      (KIND=8) :: a(1:m), b(1:ldb,1:n), c(1:n)
                                	 34.       INTEGER            :: i, j
                                	 35.       REAL      (KIND=8) :: tmr, wtime, tmrend
                                	 36.       COMMON/timer/ tmr
                                	 37. 
                             Function wtime_ not inlined because the compiler has not seen 
                             the body of the routine
0.   	0.   	0.   	0.   	 38.       tmrend = tmr + wtime()


                             Function wtime_ not inlined because the compiler has not seen 
                             the body of the routine
                             Discovered loop below has tag L16
0.   	0.   	0.   	0.   	 39.       DO WHILE(wtime() < tmrend)
                          	
                         	Array statement below generated loop L4
0.   	0.   	0.   	0.   	 40.       a(1:m) = 0.0
                                	 41. 
     	     	     	     	
                         	Source loop below has tag L6
0.   	0.   	0.   	0.   	 42.       DO j = 1, n       ! <=-----\ swapped loop indices
   	
                         	Source loop below has tag L5
                             L5 cloned for unrolling-epilog.  Clone is L19
                             All 8 copies of L19 are fused together as part of unroll and jam
                             L19 scheduled with steady-state cycle count = 9
                             L19 unrolled 4 times
                             L19 has 9 loads, 1 stores, 8 prefetches, 8 FPadds, 
                             8 FPmuls, and 0 FPdivs per iteration
                             L19 has 0 int-loads, 0 int-stores, 11 alu-ops, 0 muls, 
                             0 int-divs and 0 shifts per iteration
                             L5 scheduled with steady-state cycle count = 2
                             L5 unrolled 4 times
                             L5 has 2 loads, 1 stores, 1 prefetches, 1 FPadds, 1 FPmuls,
                             and 0 FPdivs per iteration
                             L5 has 0 int-loads, 0 int-stores, 4 alu-ops, 0 muls, 
                             0 int-divs and 0 shifts per iteration
0.210	0.210	0.210	0.   	 43.          DO i = 1, m    
4.003	4.003	4.003	0.050	 44.             a(i) = a(i) + b(i,j) * c(j)
0.240	0.240	0.240	0.   	 45.          END DO  
0.   	0.   	0.   	0.   	 46.       END DO  
                              	   47.       END DO
                         	        48. 
0.   	0.   	0.   	0.   	 49.       RETURN
0.   	0.   	0.   	0.   	 50.       END

「ソース」ビューに表示されるコンパイラ解説の種類は、「設定」ダイアログボックスの「ソース/逆アセンブリ」タブを使用して設定できます。詳細は、構成設定を参照してください。

共通部分式の削除

非常に一般的な最適化の 1 つとして、同じ式が複数の場所に存在するときに、この式のコードを 1 つの場所にまとめることによってパフォーマンスを向上させることができます。たとえば、コードブロックの ifelse の分岐の両方で同じ演算が記述されている場合、コンパイラはその演算を if 文の直前に移動することができます。実際にそのようにした場合、コンパイラは以前出現した一方の式に基づいて、命令に行番号を割り当てます。共通のコードに割り当てられた行番号が if 構造の 1 つの分岐に対応しており、かつそのコードが実際には常にほかの分岐を実行する場合、注釈付きソースは、実行されない分岐内の行に関するメトリックを表示します。

ループの最適化

コンパイラは、数種類のループの最適化を実行できます。一般的なものを次に示します。

  • ループの展開

  • ループのピーリング

  • ループの交換

  • ループの分散

  • ループの融合

ループの展開では、ループ本体内でループを数回反復し、それに応じてループインデックスを調整します。ループの本体が大きくなるほど、コンパイラはより効率的に命令をスケジュールできます。また、ループインデックスの増分や条件検査操作によるオーバーヘッドが減少します。残りのループは、ループのピーリングを使って処理されます。

ループのピーリングでは、ループから多数のループの反復を取り除き、これらをループの前か後ろに適宜移動します。

ループの交換では、キャッシュラインヒット率を最大化するために、入れ子のループの順序を変更してメモリーのストライドを最小限に抑えます。

ループの融合は、隣り合ったループや近接したループを 1 つのループにまとめます。ループの融合からは、ループの展開と同じような利点がもたらされます。さらに、最適化済みの 2 つのループで共通のデータにアクセスする場合は、ループの融合によってループのキャッシュの局所性が改善されて、コンパイラは命令レベルの並列化機能をさらに活用することが可能になります。

ループの分散はループの融合の反対で、ループは複数のループに分割されます。この最適化は、ループ内の計算回数が過度に多くなり、パフォーマンス低下の原因となるレジスタのスピルが発生する場合に適しています。また、ループの分裂は、ループに条件文が含まれている場合にも有効です。場合によっては、条件文を含むものと含まないものの 2 つにループを分割できます。この方法により、条件文を含まないループでのソフトウェアのパイプライン化の機会を増やすことができます。

場合によって、入れ子のループでは、コンパイラはループの分裂を適用してループを分割し、次にループの融合を実行して異なる方法でループをまとめ直すことでパフォーマンスを改善します。この場合は、次の例のようなコンパイラ解説が表示されます。

    Loop below fissioned into 2 loops
    Loop below fused with loop on line 116
    [116]    for (i=0;i<nvtxs;i++) {
関数のインライン化

インライン関数では、コンパイラは実際の関数呼び出しを行う代わりに、その関数が呼び出されている場所に関数の命令を直接挿入します。つまり、C/C++ マクロと同様に、それぞれの呼び出し場所でインライン関数の命令の複製が作成されます。コンパイラは、高レベルの最適化 (4 および 5) で明示的または自動的なインライン化を実行します。

インライン化によって関数呼び出しの負荷が減り、レジスタの使用や命令のスケジュールを最適化するための命令がさらに提供されますが、その代わりに、コードのメモリー使用量が多くなります。次の例は、コンパイラ解説のインライン化を示しています。

                Function initgraph inlined from source file ptralias.c 
                    into the code for the following line
0.       0.         44.       initgraph(rows);

注 -  コンパイラ解説は、パフォーマンスアナライザの「ソース」ビューで 2 行にまたがって折り返されることはありません。
並列化

Sun、Cray、または OpenMP の並列化ディレクティブを含むコードは、複数のプロセッサ上での並列実行用にコンパイルできます。コンパイラのコメントは、並列化が実行されている場所と実行されていない場所、およびその理由を示します。 次の例は、並列化コンピュータの解説を示します。

0.       6.324       9. c$omp  parallel do shared(a,b,c,n) private(i,j,k)
                   Loop below parallelized by explicit user directive
                   Loop below interchanged with loop on line 12
0.010    0.010     [10]            do i = 2, n-1

                   Loop below not parallelized because it was nested in a parallel loop
                   Loop below interchanged with loop on line 12
0.170    0.170      11.               do j = 2, i

並列実行とコンパイラ生成の本体関数の詳細は、OpenMP実行の概要 を参照してください。

注釈付きソースの特別な行

「ソース」ビューでは、特殊なケースのためのその他の注釈を表示できます。これらの注釈は、コンパイラ解説の形式で、またはインデックス行と同じ色で特別な行に表示できます。詳細は、「ソース」タブ、「逆アセンブリ」タブ、「PC」タブの特別な行を参照してください。

ソース行メトリック

実行可能コードの各行のソースコードメトリックは、固定幅の列に表示されます。メトリックは、関数リストのものと同じです。実験のデフォルト値は、.er.rc ファイルを使用して変更できます。詳細は、.er.rc ファイル内のデフォルトの設定を参照してください。また、パフォーマンスアナライザで「設定」ダイアログボックスを使用して、表示されるメトリックや強調表示するしきい値を変更することもできます。詳細は、構成設定を参照してください。

注釈付きソースコードは、ソース行レベルでのアプリケーションのメトリックスを示します。注釈付きソースは、アプリケーションの呼び出しスタックに記録された PC (プログラムカウント) を読み取り、各 PC をソース行にマッピングすることによって作成されます。注釈付きソースファイルを生成するために、パフォーマンスアナライザは、最初に特定のオブジェクトモジュール (.o ファイル) またはロードオブジェクト内に生成されたすべての関数を特定し、次に各関数のすべての PC のデータをスキャンします。

注釈付きソースを生成するには、パフォーマンスアナライザがオブジェクトモジュールまたはロードオブジェクトを検索して読み取り、PC からソース行へのマッピングを特定できる必要があります。また、ソースファイルを読み取って、表示される注釈付きコピーを生成できる必要もあります。実験のソースコードを検索するために使用されるプロセスについては、ツールがソースコードを見つけるしくみを参照してください。

コンパイル処理では、要求される最適化レベルに応じて多くの段階があり、変換によって命令とソース行のマッピングに混乱が生じることがあります。最適化によっては、ソース行の情報が完全に失われたり、混乱が生じたりすることがあります。コンパイラは、さまざまな発見手法によって命令のソース行を追跡しますが、こうした手法は絶対ではありません。

ソース行メトリックの解釈

命令のメトリックは、命令の実行待ちの間に得られたメトリックとして解釈する必要があります。イベントが記録されるときに実行中である命令がリーフ PC と同じソース行に存在している場合、メトリックはこのソース行を実行した結果であると解釈できます。ただし、実行中の命令とリーフ PC が存在しているソース行がそれぞれ異なる場合、リーフ PC が存在しているソース行のメトリックの少なくとも一部は、実行中命令のソース行が実行待ちしていた間に集計されたメトリックであると解釈する必要があります。この一例としては、1 つのソース行で計算された値が次のソース行で使用される場合が挙げられます。

正確なハードウェアカウンタを使用したハードウェアカウンタオーバーフロープロファイリング (collect -h からの出力で示されます) の場合、リーフ PC は実行される次の命令ではなく、カウンタオーバーフローの原因となっている命令の PC です。正確でないハードウェアカウンタの場合は、報告されるリーフ PC が、オーバーフローの原因となっている命令の数個あとになる可能性があります。これは、オーバーフローがいつ発生したかを認識するためのカーネルメカニズムのスキッドが可変量であるためです。

メトリックを解釈する方法の問題がもっとも重要になるのは、キャッシュミスやリソースキューストールなどのように実行に大幅な遅延が発生する場合や、命令が前の命令の結果を待っている場合です。このような場合は、ソース行のメトリックが異常に高く見えることがあります。コード内で近くにあるほかの行を調べて、メトリック値が高くなる原因になる行を見つけてください。

メトリックの形式

Table 7–1 に、注釈付きソースコードの行に表示可能な 4 つのメトリックの形式を示します。

表 7-1  注釈付きソースコードのメトリック
メトリック
重要度
(空白)
プログラムに、このコード行に対応する PC が存在しません。コメント行は常にこの空白になります。また、次の場合の見かけ上のコード行も空白になります。
  • 最適化中に、見かけ上のコード部分のすべての命令が削除されている。

  • コードが別の場所で繰り返されていて、コンパイラによって共通する部分式が認識され、その行のすべての命令に繰り返し部分の行番号が付けられている。

  • コンパイラによって、その行の命令に不正な行番号が付けられている。

0.
プログラム内のいくつかの PC がこの行から派生したものとしてタグ付けされていますが、それらの PC を参照しているデータがありません。統計的にサンプリングされたかトレースされた呼び出しスタックに、そのような PC は存在しません。0. メトリックは、その行が実行されなかったことを意味するのではなく、プロファイリングデータパケットや記録されたトレースデータパケットに統計として表示されなかったことだけを意味します。
0.000
この行の少なくとも 1 つの PC がデータに表れていますが、メトリック値の計算でゼロに丸められました。
1.234
この行に属するすべての PC のメトリックの合計が、表示されているゼロ以外の数値になりました。