2016/08/04


記事中に間違いがありました。数倍も速くはなりませんでした。確か 1.0X ~ 1.1 倍程度の高速化は得られましたがびっくりするほどの物ではありませんでした。すみません。

 Go1.7 Go mattn (

Go1.7 


var t [256]byte

func f(b *[16]byte) {
    for i, v := range b {
        b[i] = t[v]
    }
}

issue tLEAQ LEAQ  x64 TLS 

 go tool compile -S foo.go 
package main

var t [256]byte

func f(b []byte) {
    for i := 0; i < 100000000; i++ {
        b[i%len(b)] = t[i%len(t)]
    }
}

func main() {
}


0x002f 00047 (s1.go:7)  TESTQ   CX, CX
0x0032 00050 (s1.go:7)  JEQ $0, 149
0x0034 00052 (s1.go:7)  MOVQ    BX, AX
0x0037 00055 (s1.go:7)  CMPQ    CX, $-1
0x003b 00059 (s1.go:7)  JEQ 144
0x003d 00061 (s1.go:7)  CQO
0x003f 00063 (s1.go:7)  IDIVQ   CX
0x0042 00066 (s1.go:7)  MOVQ    BX, SI
0x0045 00069 (s1.go:7)  SARQ    $63, BX
0x0049 00073 (s1.go:7)  MOVBQZX BL, BX
0x004c 00076 (s1.go:7)  LEAQ    (SI)(BX*1), DI
0x0050 00080 (s1.go:7)  MOVBQZX DIB, DI
0x0054 00084 (s1.go:7)  SUBQ    BX, DI
0x0057 00087 (s1.go:7)  CMPQ    DI, $256
0x005e 00094 (s1.go:7)  JCC $0, 137
0x0060 00096 (s1.go:7)  LEAQ    "".t(SB), BX
0x0067 00103 (s1.go:7)  MOVBLZX (BX)(DI*1), BX
0x006b 00107 (s1.go:7)  CMPQ    DX, CX
0x006e 00110 (s1.go:7)  JCC $0, 137
0x0070 00112 (s1.go:7)  MOVQ    "".b+8(FP), DI
0x0075 00117 (s1.go:7)  MOVB    BL, (DI)(DX*1)
0x0078 00120 (s1.go:6)  LEAQ    1(SI), BX
0x007c 00124 (s1.go:7)  MOVQ    DI, DX
0x007f 00127 (s1.go:6)  CMPQ    BX, $100000000
0x0086 00134 (s1.go:6)  JLT $0, 47

 LEAQ golang goroutine tt nil t nil  LEAQ 使t

 TLS 1
var t [256]byte

func f(b []byte) {
    t := t // 
    for i := 0; i < 100000000; i++ {
        b[i%len(b)] = t[i%len(t)]
    }
}

t TLS 使
0x0057 00087 (s2.go:7)  MOVQ    "".b+272(FP), AX
0x005f 00095 (s2.go:7)  MOVQ    $0, CX
0x0061 00097 (s2.go:7)  CMPQ    CX, $100000000
0x0068 00104 (s2.go:7)  JGE $0, 181
0x006a 00106 (s2.go:8)  MOVQ    CX, DX
0x006d 00109 (s2.go:8)  SARQ    $63, CX
0x0071 00113 (s2.go:8)  MOVQ    CX, BX
0x0074 00116 (s2.go:8)  ANDQ    $15, CX
0x0078 00120 (s2.go:8)  LEAQ    (DX)(CX*1), SI
0x007c 00124 (s2.go:8)  ANDQ    $15, SI
0x0080 00128 (s2.go:8)  SUBQ    CX, SI
0x0083 00131 (s2.go:8)  MOVBQZX BL, CX
0x0086 00134 (s2.go:8)  LEAQ    (DX)(CX*1), BX
0x008a 00138 (s2.go:8)  MOVBQZX BL, BX
0x008d 00141 (s2.go:8)  SUBQ    CX, BX
0x0090 00144 (s2.go:8)  CMPQ    BX, $256
0x0097 00151 (s2.go:8)  JCC $0, 197
0x0099 00153 (s2.go:8)  MOVBLZX "".t(SP)(BX*1), CX
0x009d 00157 (s2.go:8)  TESTB   AL, (AX)
0x009f 00159 (s2.go:8)  CMPQ    SI, $16
0x00a3 00163 (s2.go:8)  JCC $0, 197
0x00a5 00165 (s2.go:8)  MOVB    CL, (AX)(SI*1)
0x00a8 00168 (s2.go:7)  LEAQ    1(DX), CX
0x00ac 00172 (s2.go:7)  CMPQ    CX, $100000000
0x00b3 00179 (s2.go:7)  JLT $0, 106

t LEAQ 
package main

import "testing"

var t [256]byte

func f1(b []byte) {
    for i := 0; i < 100000000; i++ {
        b[i%len(b)] = t[i%len(t)]
    }
}

func f2(b []byte) {
    t := t
    for i := 0; i < 100000000; i++ {
        b[i%len(b)] = t[i%len(t)]
    }
}

func BenchmarkWithLEAQ(b *testing.B) {
    var m [16]byte
    f1(m[:])
}

func BenchmarkWithoutLEAQ(b *testing.B) {
    var m [16]byte
    f2(m[:])
}

 go test -bench . 
BenchmarkWithLEAQ-4                    1        1035500000 ns/op
BenchmarkWithoutLEAQ-4                 3         334666666 ns/op
PASS
ok      github.com/mattn/leaq   4.722s

131.0X1.1 LEAQ  f1/f2  f1 
変数のアトミック性を TLS を使って同期して実現してるのだと思ってましたが間違っていましたので記事を修正しました。
Posted at by | Edit