javascript、ruby和C效能一瞥(3) :上彙編

來源:互聯網
上載者:User

標籤:素數篩法   linux64   nasm   彙編   

在博文(1)和(2)裡分別用了4中方式寫一個素數篩選的演算法,分別是javascript in browser、node.js、ruby和c;最終的結果是c最快,node.js其次,js in b雖然也不慢,但極不穩定,所以排在第三,ruby最慢。

現在我們在linux64中用組合語言重寫sieve演算法,看看動用最終的武器:組合語言,我們能不能進一步最佳化素數篩選演算法。

如果忘了演算法邏輯,不要緊,下面分別再次貼出node.js、ruby以及c的sieve代碼:

首先是node.js:

function sieve(n){    var a = new Int8Array(n+1);    var max = Math.floor(Math.sqrt(n));    var p = 2;    while(p <= max){        for(var i=2*p;i<=n;i+=p)            a[i] = 1;        while(a[++p]); /* empty */    }    while(a[n]) n--;    return n;}

然後是ruby:

def sieve(n)    a = Array.new(n+1);    max = Math.sqrt(n).to_i;    p = 2;    while p<=max  do        i = 2*p        while i<=n do            a[i] = 1            i+=p        end        while a[p+=1] == 1 do end    end    while a[n] do n-=1 end    n end

最後是c的代碼:

ULL sieve(ULL n){    char *a = malloc(n+1);    if(!a) return 0;    memset(a,0,n+1);    ULL max = sqrtl(n);    ULL p = 2;    while(p <= max){        for(ULL i=2*p;i<=n;i+=p)            a[i] = 1;        while(a[++p]); /* empty */    }    while(a[n]) n--;    return n;}

下面嘗試用彙編重寫sieve函數,需要注意的幾點是:

  1. 可以不調用C庫中的sqrtx標準函數,直接使用浮點fsqrt指令;
  2. 可以將絕大部分記憶體變數放到寄存器中以加速存取;
  3. 只關心sieve函數的演算法,而用c代碼調用彙編的sieve,這樣可以發揮各自的長處;否則我還得寫個讀取輸入參數的前置代碼,不值當的;
  4. 注意彙編和c的調用介面:在linux64中,參數並不壓棧傳遞;因為sieve只有一個參數,所以放在rdi中傳遞,傳回值還是放在rax中。
  5. 需要調用mmap申請足夠的記憶體以便做篩表。注意這裡沒有寫足夠詳細的錯誤處理,更詳細的操作請參考本貓的【linux下64位彙編的系統調用】系列博文。
  6. 最後要注意的是,代碼最佳化和代碼編寫一定不要同時進行!這在所有程式設計語言中都適用,彙編中尤為重要!否則必成一鍋粥鳥!因為誰都不可能上來就寫最佳化後的代碼,一定是先功能邏輯正常後在著手考慮最佳化的問題。本貓第一遍寫的是最保守代碼,全部變數放在記憶體中,隨用隨取,用完儲存。在代碼邏輯正確後(這時計算sieve 100000000所花時間為4xxx ms),在逐步將記憶體變數轉放到寄存器中。

要說明的是該段代碼肯定還可以進一步最佳化,但本貓就到這裡為止了,希望能夠拋磚引玉。先把結果說一下吧:用彙編寫的sieve版本是最快的,超過了c代碼,在本貓 Intel(R) Core(TM)2 Duo CPU T7100 @ 1.80GHz上跑出了最快的37xx毫秒,比c版的平均要快100-200毫秒,而且非常穩定。

最後貼出C的main.c和彙編的sieve.s代碼:
main.c:

#include <stdio.h>#include <stdlib.h>#include <stdbool.h>#include <string.h>#include <time.h>#include <unistd.h>typedef unsigned long long ULL;ULL sieve(ULL n);int main(int argc,char **argv){    ULL n = 0;    if(argc < 2){        printf("usage %s n\n",argv[0]);        return 1;    }    sscanf(argv[1],"%llu",&n);    if(n == 0){        puts("wrong number format");        return 2;    }    else if(n < 0){        puts("must + number");        return 3;    }    int start = clock();    ULL result = sieve(n);    if(result == -1){        puts("sieve calc failed!");        return 4;    }    double end = ((1.0 * (clock() - start)) / CLOCKS_PER_SEC) * 1000.0;    printf("max p is %llu (take %f ms)\n",result,end);    return 0;}

彙編的sieve.s:

section .data    n:dq 0    len:dq 0    addr: dq 0    p:dq 2    max:dq 0    i:dq 2              section .text    global sievesieve:    push rbp    push rbx    push rcx    mov rbp,rsp    mov [n],rdi         ;save 1st arg to n    inc rdi    mov [len],rdi           ;mmap len = n + 1    mov eax,9           ;call syscall mmap    mov rdi,0    mov rsi,[len]    mov rdx,3    mov r10,33    mov r8,-1    mov r9,0    syscall    cmp rax,0xfffffffffffff001      ;mmap error    jb next    mov rax,-1          ;return -1    jmp quitnext:   ;save mmap return addr                    ;FIXME:mmap space always 0 ???    fild qword [n]          ;calc sqrt(n) and save result to max    fsqrt    fistp qword [max]    mov r15,[p]         ;r15 = p    mov r14,[max]           ;r14 = max    mov r13,[n]         ;r13 = n    mov r12,[i]         ;r12 = ienter_while:    cmp r15,r14         ;if p<=max    ja quit_while    mov rbx,r15    shl rbx,1    mov r12,rbxenter_for:                  cmp r12,r13    ja quit_for    mov byte [rax + r12],1    add r12,r15    jmp enter_forquit_for:    inc r15    mov cl,byte [rax + r15]    test cl,cl    jnz quit_for    jmp enter_whilequit_while:    mov cl,byte [rax + r13]    test cl,cl    jz pre_quit    dec r13    jmp quit_whilepre_quit:    mov rax,r13quit:    mov rsp,rbp    pop rcx    pop rbx    pop rbp    ret

javascript、ruby和C效能一瞥(3) :上彙編

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.