2011-10-09 147 views
2

我正在使用以下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]。我已经尝试过例程,它编译并运行成功,但我不确定它是否有效。

+2

你知不知道冒泡排序是在效率方面可怕的排序算法?如果您要采用二次排序算法,那么挖掘汇编程序级别的意义是什么(除了要提供一个不做**的例子)? –

+3

任何其他效率低*旁*简单的事实,你使用的bubblesort。在汇编中实现一个泡泡是(完全正确的)做完全错误的事情的典型例子,并且浪费你的时间来微观地优化错误的算法。 –

+1

当我读到你在程序集中实现了一个冒泡排序时,我从字面上放弃了LOL。 –

回答

2

几个简单的技巧:

1)尽量减少有条件跳跃的数量,因为他们是非常昂贵的。如果可能,展开。 2)重新排列指令,以尽量减少因数据depencency的档位:

cmp DWORD PTR [esi],edx ;// takes some time to compute, 
mov edx,DWORD PTR [esi+4] ; 
ja _swap ;// waits for results of cmp 

3)避免老复合指令(decjnz对比loop更快,未绑定到ecx寄存器)

这将是编写比通过优化C编译器生成的代码更快的汇编代码非常困难,因为您应该考虑很多因素:数据和指令高速缓存的大小,对齐方式,流水线,指令时序。你可以找到关于这个here的一些很好的文档。我特别推荐的第一本书:在C++ 优化软件

3

有几件事情可以做,以加快你的汇编代码:

  • ja label_1 ; jmp label_2不做的事情。改为jbe label_2

  • loop是一个非常缓慢的指令。 dec ebx; jnz loopstart要快得多

  • 使用所有的寄存器,而不是反复推/弹出ecx和esi。同样使用ebxedi

  • jmp-targets应该很好地对齐。两个循环开始之前使用align 4jbe

后让自己手动为你的CPU来自英特尔(你可以下载PDF格式),它有操作码的时机,也许还有其他的提示太。

0

替换为“增加ESI,4”如果我们不需要一个标志指令:

_continueLoop: 
      lea esi,[esi+4]