注釈付き逆アセンブリを解釈するのは簡単ではありません。 リーフ PC とは、次に実行する命令のアドレスです。このため、命令の属性メトリックは、命令の実行待ちに費やされた時間とみなされます。ただし、命令が必ずしも順番に実行されるとは限らないため、呼び出しスタックの記録で遅延が発生することもあります。注釈付き逆アセンブリコードを利用するには、実験の記録先であるハードウェアと、そのハードウェアが命令を読み込み、実行する方法を理解しておいてください。
次では、注釈付き逆アセンブリコードを解釈する上での問題点をいくつか説明します。
命令は、命令発行グループと呼ばれるグループ単位でロードおよび発行されます。 グループに含まれる命令は、ハードウェア、命令の種類、すでに実行された命令、およびほかの命令またはレジスタの依存関係によって異なります。その結果、ある命令が常に前の命令と同じクロックサイクルで実行され、次に実行される命令として現れない場合、その命令の出現回数は実際よりも少なくなることを意味します。呼び出しスタックが記録されるときに、次に実行するとみなされる命令が複数存在する可能性もあります。
命令発行規則はプロセッサの種類ごとに異なり、キャッシュ行内の命令位置合わせに依存します。リンカーはキャッシュ行より高い精度で命令位置合わせを強制的に行うため、関連がないように見える関数を変更すると、異なる命令位置合わせが生じることがあります。位置合わせが異なると、パフォーマンスの向上や劣化が発生することがあります。
次の例では、同じ関数をわずかに異なる状況でコンパイルしてリンクしています。2 つの出力例は、er_print ユーティリティーからの注釈付き逆アセンブリリストを示しています。2 つの例の命令は同じですが、位置合わせが異なっています。
次の出力例では、命令位置合わせによって、2 つの命令 cmp と bl,a が異なるキャッシュ行にマップされています。これらの 2 つの命令の実行待ちに長い時間がかかっています。
Excl. Incl. User CPU User CPU sec. sec. 1. static int 2. ifunc() 3. { 4. int i; 5. 6. for (i=0; i<10000; i++) <function: ifunc> 0.010 0.010 [ 6] 1066c: clr %o0 0. 0. [ 6] 10670: sethi %hi(0x2400), %o5 0. 0. [ 6] 10674: inc 784, %o5 7. i++; 0. 0. [ 7] 10678: inc 2, %o0 ## 1.360 1.360 [ 7] 1067c: cmp %o0, %o5 ## 1.510 1.510 [ 7] 10680: bl,a 0x1067c 0. 0. [ 7] 10684: inc 2, %o0 0. 0. [ 7] 10688: retl 0. 0. [ 7] 1068c: nop 8. return i; 9. }
次の出力例では、命令位置合わせによって、2 つの命令 cmp と bl,a が同じキャッシュ行にマップされています。これらの命令のどちらかのみ、実行待ちに長い時間がかかっています。
Excl. Incl. User CPU User CPU sec. sec. 1. static int 2. ifunc() 3. { 4. int i; 5. 6. for (i=0; i<10000; i++) <function: ifunc> 0. 0. [ 6] 10684: clr %o0 0. 0. [ 6] 10688: sethi %hi(0x2400), %o5 0. 0. [ 6] 1068c: inc 784, %o5 7. i++; 0. 0. [ 7] 10690: inc 2, %o0 ## 1.440 1.440 [ 7] 10694: cmp %o0, %o5 0. 0. [ 7] 10698: bl,a 0x10694 0. 0. [ 7] 1069c: inc 2, %o0 0. 0. [ 7] 106a0: retl 0. 0. [ 7] 106a4: nop 8. return i; 9. }
特定のリーフ PC の示す命令の発行前に遅延があると、そのリーフ PC の出現回数が多くなることがあります。これは、次のケースを初めとして、さまざまな多くの理由で発生する可能性があります。
命令がカーネルにトラップされたときのように、前の命令の実行に時間がかかり、割り込みが不可能な場合。
算術演算命令が必要とするレジスタの内容が前の命令によって設定されていて、その命令がまだ完了していない場合。このような遅延の例としては、たとえば、データキャッシュミスが発生したロード命令があります。
浮動小数点演算命令が、別の浮動小数点演算命令の終了待ちになっている場合。このような状況は、平方根や浮動小数点除算などのパイプライン化が不可能な命令で発生します。
命令を含むメモリーワードが命令キャッシュに含まれていない場合 (I キャッシュミス)。
一部のプラットフォームおよび precise カウンタでの TLB ミスを除き、ハードウェアカウンタオーバーフローイベントの呼び出しスタックは、オーバーフローが発生した時点よりあとの命令シーケンス内のある時点で記録されます。この遅延は、オーバーフローによって生成された割り込みの処理にかかった時間など、さまざまな原因によって発生します。 サイクルおよび発行された命令などの一部のカウンタの場合、この遅延は問題になりません。しかし、キャッシュミスや浮動小数点演算をカウントするようなカウンタの場合は、そのオーバーフローの原因となっているものとは別の命令がメトリックの原因とされます。
多くの場合、イベントを発生させた PC は記録された PC の数命令前でしかなく、その命令は逆アセンブリリスト内で正確に特定できます。ただし、この命令範囲内に分岐先がある場合、イベントを引き起こした PC に対応する命令を特定することは困難であるか、または不可能です。
precise キーワードでラベル付けされたカウンタを持つプロセッサを備えたシステムでは、バイナリの特殊コンパイルなしでメモリー領域プロファイリングを行うことができます。たとえば、SPARC T2、SPARC T3、および SPARC T4 プロセッサには、いくつかの precise カウンタがあります。システムでメモリー領域プロファイリングが可能かどうかを調べるには、collect -h コマンドを実行し、precise キーワードを探します。
たとえば、SPARC T4 プロセッサを備えたシステムで次のコマンドを実行すると、使用可能な高精度 raw カウンタが表示されます。
% collect -h | & grep -i precise | grep -v alias Instr_ld[/{0|1|2|3}],1000003 (precise load-store events) Instr_st[/{0|1|2|3}],1000003 (precise load-store events) SW_prefetch[/{0|1|2|3}],1000003 (precise load-store events) Block_ld_st[/{0|1|2|3}],1000003 (precise load-store events) DC_miss_L2_L3_hit_nospec[/{0|1|2|3}],1000003 (precise load-store events) DC_miss_local_hit_nospec[/{0|1|2|3}],1000003 (precise load-store events) DC_miss_remote_L3_hit_nospec[/{0|1|2|3}],1000003 (precise load-store events) DC_miss_nospec[/{0|1|2|3}],1000003 (precise load-store events)