我正在使用以下ASM例程对数组进行冒泡排序。我想知道我的代码效率低下:
.386
.model flat, c
option casemap:none
.code
public sample
sample PROC
;[ebp+0Ch]Length
;[ebp+08h]Array
push ebp
mov ebp, esp
push ecx
push edx
push esi
push eax
mov ecx,[ebp+0Ch]
mov esi,[ebp+08h]
_bubbleSort:
push ecx
push esi
cmp ecx,1
je _exitLoop
sub ecx,01h
_miniLoop:
push ecx
mov edx,DWORD PTR [esi+4]
cmp DWORD PTR [esi],edx
ja _swap
jmp _continueLoop
_swap:
lodsd
mov DWORD PTR [esi-4],edx
xchg DWORD PTR [esi],eax
jmp _skipIncrementESI
_continueLoop:
add esi,4
_skipIncrementESI:
pop ecx
loop _miniLoop
_exitLoop:
pop esi
pop ecx
loop _bubbleSort
pop eax
pop esi
pop edx
pop ecx
pop ebp
ret
sample ENDP
END
基本上,我有两个循环,就像气泡排序算法一样。外循环的ecx值为10,内循环为[ecx-1]。我尝试过这个例程,它编译并运行成功,但我不确定它是否有效。
有几种方法可以加快汇编代码的速度:
-
不要做类似
ja label_1 ; jmp label_2
的事情。只需执行jbe label_2
即可。 -
loop
是一个非常慢的指令。dec ebx; jnz loopstart
是更快的 -
使用所有寄存器,而不是重复推送/弹出ecx和esi。同时使用
ebx
和edi
。 -
jmp的目标应该保持一致。在两个循环开始之前和
jbe
之后使用align 4
从英特尔为自己获取一份cpu手册(你可以以pdf格式下载(,它有操作码的时间,也许还有其他提示。
几个简单提示:
1( 尽量减少条件跳转的数量,因为它们非常昂贵。如果可能,展开。2( 重新排序指令以最大限度地减少因数据依赖而导致的暂停:
cmp DWORD PTR [esi],edx ;// takes some time to compute,
mov edx,DWORD PTR [esi+4] ;
ja _swap ;// waits for results of cmp
3( 避免使用旧的复合指令(dec
、jnz
对比loop
快,并且不绑定到ecx
寄存器(
编写比优化C编译器生成的代码更快的汇编代码是非常困难的,因为您应该考虑很多因素:数据和指令缓存的大小、对齐、管道、指令计时。你可以在这里找到一些好的文档。我特别推荐第一本书:在C++中优化软件
如果我们不需要此指令的标志,请替换"add esi,4":
_continueLoop:
lea esi,[esi+4]