go 如何使用 SIMD 指令

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

Java SIMD Lucene Elasticsearch

我們首先來看一下 JAVA 如何使用 CPU 的 SIMD 指令。這是一個ru的哥們嘗試在lucene裡使用SIMD指令加速lucene的postings list(也就是指定term對應的文檔id列表)的解碼:

http://blog.griddynamics.com/2015/02/proposing-simd-codec-for-lucene.h...
https://www.youtube.com/watch?v=2HQdbpgHfnQ&index=15&list=PLq-...

最重要的結論就是 java 自身還不支援JIT(運行時產生的機器碼)出SIMD指令。如果用 c/asm 編寫 SIMD 的代碼,在 java 裡調用的話 JNI 本身的開銷抵消了 SIMD 帶來的好處。所以最終需要使

用一種更底層的方式訪問 native 代碼:

http://stackoverflow.com/questions/24746776/what-does-a-jvm-have-to-do...

值得一提的是 elasticsearch 從 2.0 大幅加強了 aggregation,現在已經開始支援 pipeline 了。可以寫出類似 select sum(money) / sum(users_count) from payment 之類的代碼了。自然 SIMD 的最佳化也可以做到 aggregation 階段裡去。

https://www.elastic.co/guide/en/elasticsearch/reference/master/search-...

Go CGO

CGO 慢,顯而易見。

https://github.com/golang/go/blob/master/src/runtime/cgocall.go

具體來說就是這幾行

    /*     * Announce we are entering a system call     * so that the scheduler knows to create another     * M to run goroutines while we are in the     * foreign code.     *     * The call to asmcgocall is guaranteed not to     * split the stack and does not allocate memory,     * so it is safe to call while "in a system call", outside     * the $GOMAXPROCS accounting.     */    entersyscall(0)    errno := asmcgocall(fn, arg)    exitsyscall(0)

每次調用 c 的函數都假設了這個函數是阻塞的。entersyscall 會儲存當前協程的堆棧資訊。所以Go的策略和Java一樣,通過讓JNI很慢,迫使使用者把儘可能多的代碼都寫到Go裡。

Go Plan9 Assembly

Go有兩個編譯器,一個是gc(go compiler),一個是gccgo(用的是gcc的後端)。gc編譯器是把代碼從go編譯成plan 9的彙編。plan 9的彙編不是平台無關的,而是每個平台有一個版本,然後和這

個平台本身的彙編文法又有不同。
首先我們可以來看一下 gc 編譯器是不是會產生 SIMD 指令:

https://github.com/golang/go/blob/master/src/cmd/compile/internal/amd6...

可以看到,在這個列表裡是沒有 ADDPD 這樣的 SIMD 指令的。說明 gc 編譯器目前還不支援把普通的加法編譯成向量加法。用 Intel 的編譯器,如果把代碼協程 struct of array 的形式而不是

array of struct 形式的話,編譯器可以自動做向量化最佳化。顯然 gc 編譯器還沒有把這個做為一個最佳化方向。

https://software.intel.com/sites/default/files/8c/a9/CompilerAutovecto...

雖然gc編譯器不支援 SIMD,但是其 plan9 的 assembler 是支援在 amd64 的 SIMD 指令的。

https://github.com/golang/go/blob/master/src/cmd/internal/obj/x86/asm6...

其中有 AADDPD (也就是 ADDPD)。而 Go 是支援在代碼裡混用 go 和 plan9 彙編的。所以 gonum 這個項目就寫了一些 plan9 彙編來最佳化效能:

https://github.com/gonum/internal/blob/master/asm/ddot_amd64.s

簡單做了一個benchmark:

package mainimport "fmt"import "simd/asm"import "testing"func BenchmarkFunction(b *testing.B) {    x := make([]float64, 10000)    for i := 0; i < len(x); i++ {        x[i] = float64(i)    }    y := make([]float64, 10000)    for i := 0; i < len(y); i++ {        y[i] = float64(i)    }    for i := 0; i < b.N; i++ {        _ = asm.DdotUnitary(x, y)    }}func main() {    br := testing.Benchmark(BenchmarkFunction)    fmt.Println(br)}

使用 SIMD 版本的點乘,速度為 4616 ns/op。使用非 SIMD 版本的點乘,速度為 12340 ns/op。目前 Go 並不支援 inline plan9 的彙編代碼。也就是彙編寫的函數每次調用都要付出一個函數call

的成本,也就是沒法當成 SIMD intrinsics 那樣來用。不過仍然比 java 強多了……

GCCGO

Go還有另外一個編譯器。它提供了另外一種Cgo的方式,extern。

https://golang.org/doc/install/gccgo

使用 extern 可以把任意的 c 的代碼連結到 go 代碼裡來。至於 scheduler 和 garbage collector 這些就自己好自為之了。甚至類型互相轉換的細節都還是 subject to change 的。可以把它理解

為去掉了安全保護的 cgo。

利用這條路也可以把 SIMD 指令連結到 go 代碼裡來使用:

http://stackoverflow.com/questions/2951028/is-it-possible-to-include-i...

使用 gccgo 可能還可以把這些 SIMD 調用在link時做inline:

https://groups.google.com/forum/#!topic/golang-nuts/kGgkcOFCBtc
https://groups.google.com/forum/#!topic/golang-nuts/TqMTWdYGKOk

引用一段

Answering specifically about gccgo.  Gccgo is of course just a frontend to GCC.  GCC can not inline functions written in pure assembly.  However, GCC provides CPU-specific builtin functions usable in C/C++ for many things that people want to do (e.g., vector instructions) and it also provides a sophisticated asm expression as a C/C++ extension.  This means that you can write your assembly code in extended C/C++ instead, and a function written that way can be inlined.  It can even be inlined into Go code if you use LTO (link-time optimization, see GCC's -flto options). 

總結

Go有三種調用native的代碼的方式:

  • cgo
  • plan9 assembly
  • gccgo extern

相比Java的JNI來說,可選項更多。不遠的將來 go 可以在 spark/lucene 這兩個領域從速度上超過 Java。
go 1.5 的編譯器已經是用 go 寫的。也許將來 go 的編譯器可以和 Intel 的編譯器一樣,自動產生向量化的代碼。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.