指令按组装入和发送(称为指令发送组)。组中包括哪些指令取决于硬件、指令类型、已执行的指令以及与其他指令或寄存器的各种相关性。因此,可能不会单独发送某些指令,因为它们始终与前一条指令在同一个时钟周期内发送,所以它们从不单独表示下一条要执行的指令。而且,在记录调用栈时,可能有多条指令被视为是下一条要执行的指令。
指令发送规则因处理器类型的不同而不同,并且还取决于高速缓存行内的指令对齐。由于链接程序比高速缓存行要求执行更精确的指令对齐,因此在看上去不相关的函数中进行的更改可能会导致指令的对齐方式不同。不同的对齐方式会引起性能的改进或降级。
下面列举了一种假设情况,即同一个函数在略微不同的环境下进行编译和链接的情况。以下两个输出示例均为 er_print 实用程序的带注释的反汇编代码列表。两个示例中的指令是相同的,但指令的对齐方式不同。
在以下示例中,指令的对齐方式是将 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.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 两条指令映射到相同的高速缓存行,并且大量的时间都用于等待执行其中一条指令。
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. } |