命令は、命令発行グループと呼ばれるグループ単位で読み込まれ、発行されます。グループに含まれる命令は、ハードウェア、命令の種類、すでに実行された命令、およびほかの命令またはレジスタの依存関係によって異なります。その結果、ある命令が常に前の命令と同じクロックで実行され、次に実行される命令として現れない場合、その命令の出現回数は実際よりも少なくなることを意味します。また、呼び出しスタックが記録されるときに、「次」に実行する命令が複数存在する可能性もあります。
命令発行規則はプロセッサの種類ごとに異なり、キャッシュ行内の命令位置合わせに依存します。リンカーはキャッシュ行よりも高い精度による命令位置合わせを強制的に行うので、関連性がないと思える関数を変更すると、異なる命令の位置合わせが生じる可能性があります。位置合わせが異なると、パフォーマンスの向上や劣化が発生することがあります。
次の例では、同じ関数をわずかに異なる状況でコンパイルしてリンクしています。2 つの出力例は、er_print ユーティリティーからの注釈付き逆アセンブリリストを示しています。2 つの例の命令は同じですが、位置合わせが異なっています。
この例の命令位置合わせでは、cmp と bl,a の 2 つの命令を別々のキャッシュ行にマップし、この 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. } |
この例の命令位置合わせでは、cmp と bl,a の 2 つの命令を 1 つのキャッシュ行にマップし、この 2 つの命令の内 1 つの命令のみの実行待ちに多大な時間が消費されます。
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. } |