我正在使用以下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]。我已经尝试了例程,它编译并成功运行,但我不确定它是否有效。
答案 0 :(得分:3)
您可以采取以下措施来加快汇编代码:
不要执行ja label_1 ; jmp label_2
之类的操作。只需改为jbe label_2
。
loop
是一个非常慢的指令。 dec ebx; jnz loopstart
更快
使用所有寄存器而不是重复推送/弹出ecx和esi。也可以使用ebx
和edi
。
jmp-targets应该很好地对齐。在两个循环开始之前和align 4
jbe
从英特尔获取自己的cpu手册(可以将其下载为pdf),它有操作码的时间,也许还有其他提示。
答案 1 :(得分:2)
几个简单的提示:
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编译器生成的代码更快的汇编代码是非常困难的,因为您应该考虑很多因素:数据大小和指令缓存,对齐,流水线,指令时序。你可以找到一些关于这个here的好文档。我特别推荐第一本书:用C ++优化软件
答案 2 :(得分:0)
如果我们不需要该指令的标志,则替换为“add esi,4”:
_continueLoop:
lea esi,[esi+4]