Commit 4e6b529c authored by Damian Gryski's avatar Damian Gryski

Remove binary.{Read,Write} in favour of doing it by hand

The encoding/binary.{Read,Write} methods use reflection which is slow.
This is ok for prototyping but has a serious performance impact.  In
each case, we know exactly what we're trying to write out, so we'll
allocate our own buffer and do the explicit conversion ourselves.

As an example of the performance improvement this makes, here are the
results from an (internal) benchmark:

benchmark          old ns/op    new ns/op    delta
BenchmarkDecode       427190       318845  -25.36%
parent 28ab321f
...@@ -114,7 +114,9 @@ func (e *Encoder) encodeBytes(byt []byte) { ...@@ -114,7 +114,9 @@ func (e *Encoder) encodeBytes(byt []byte) {
e.w.Write([]byte{opShortBinstring, byte(l)}) e.w.Write([]byte{opShortBinstring, byte(l)})
} else { } else {
e.w.Write([]byte{opBinstring}) e.w.Write([]byte{opBinstring})
binary.Write(e.w, binary.LittleEndian, int32(l)) var b [4]byte
binary.LittleEndian.PutUint32(b[:], uint32(l))
e.w.Write(b[:])
} }
e.w.Write(byt) e.w.Write(byt)
...@@ -124,7 +126,9 @@ func (e *Encoder) encodeFloat(f float64) { ...@@ -124,7 +126,9 @@ func (e *Encoder) encodeFloat(f float64) {
var u uint64 var u uint64
u = math.Float64bits(f) u = math.Float64bits(f)
e.w.Write([]byte{opBinfloat}) e.w.Write([]byte{opBinfloat})
binary.Write(e.w, binary.BigEndian, u) var b [8]byte
binary.BigEndian.PutUint64(b[:], uint64(u))
e.w.Write(b[:])
} }
func (e *Encoder) encodeInt(k reflect.Kind, i int64) { func (e *Encoder) encodeInt(k reflect.Kind, i int64) {
...@@ -138,7 +142,9 @@ func (e *Encoder) encodeInt(k reflect.Kind, i int64) { ...@@ -138,7 +142,9 @@ func (e *Encoder) encodeInt(k reflect.Kind, i int64) {
e.w.Write([]byte{opBinint2, byte(i), byte(i >> 8)}) e.w.Write([]byte{opBinint2, byte(i), byte(i >> 8)})
case i >= math.MinInt32 && i <= math.MaxInt32: case i >= math.MinInt32 && i <= math.MaxInt32:
e.w.Write([]byte{opBinint}) e.w.Write([]byte{opBinint})
binary.Write(e.w, binary.LittleEndian, int32(i)) var b [4]byte
binary.LittleEndian.PutUint32(b[:], uint32(i))
e.w.Write(b[:])
default: // int64, but as a string :/ default: // int64, but as a string :/
e.w.Write([]byte{opInt}) e.w.Write([]byte{opInt})
fmt.Fprintf(e.w, "%d\n", i) fmt.Fprintf(e.w, "%d\n", i)
......
...@@ -307,8 +307,12 @@ func (d *Decoder) loadInt() error { ...@@ -307,8 +307,12 @@ func (d *Decoder) loadInt() error {
// Push a four-byte signed int // Push a four-byte signed int
func (d *Decoder) loadBinInt() error { func (d *Decoder) loadBinInt() error {
var v int32 var b [4]byte
binary.Read(d.r, binary.LittleEndian, &v) _, err := io.ReadFull(d.r, b[:])
if err != nil {
return err
}
v := binary.LittleEndian.Uint32(b[:])
d.push(int64(v)) d.push(int64(v))
return nil return nil
} }
...@@ -334,12 +338,13 @@ func (d *Decoder) loadLong() error { ...@@ -334,12 +338,13 @@ func (d *Decoder) loadLong() error {
// Push a 2-byte unsigned int // Push a 2-byte unsigned int
func (d *Decoder) loadBinInt2() error { func (d *Decoder) loadBinInt2() error {
var u uint16 var b [2]byte
err := binary.Read(d.r, binary.LittleEndian, &u) _, err := io.ReadFull(d.r, b[:])
if err != nil { if err != nil {
return err return err
} }
d.push(int64(u)) v := binary.LittleEndian.Uint16(b[:])
d.push(int64(v))
return nil return nil
} }
...@@ -394,11 +399,12 @@ func (d *Decoder) loadString() error { ...@@ -394,11 +399,12 @@ func (d *Decoder) loadString() error {
} }
func (d *Decoder) loadBinString() error { func (d *Decoder) loadBinString() error {
var v int32 var b [4]byte
err := binary.Read(d.r, binary.LittleEndian, &v) _, err := io.ReadFull(d.r, b[:])
if err != nil { if err != nil {
return err return err
} }
v := binary.LittleEndian.Uint32(b[:])
s := make([]byte, v) s := make([]byte, v)
_, err = io.ReadFull(d.r, s) _, err = io.ReadFull(d.r, s)
if err != nil { if err != nil {
...@@ -526,8 +532,12 @@ func (d *Decoder) inst() error { ...@@ -526,8 +532,12 @@ func (d *Decoder) inst() error {
} }
func (d *Decoder) longBinGet() error { func (d *Decoder) longBinGet() error {
var v int32 var b [4]byte
binary.Read(d.r, binary.LittleEndian, &v) _, err := io.ReadFull(d.r, b[:])
if err != nil {
return err
}
v := binary.LittleEndian.Uint32(b[:])
d.push(d.memo[strconv.Itoa(int(v))]) d.push(d.memo[strconv.Itoa(int(v))])
return nil return nil
} }
...@@ -599,8 +609,12 @@ func (d *Decoder) loadSetItems() error { ...@@ -599,8 +609,12 @@ func (d *Decoder) loadSetItems() error {
} }
func (d *Decoder) binFloat() error { func (d *Decoder) binFloat() error {
var u uint64 var b [8]byte
binary.Read(d.r, binary.BigEndian, &u) _, err := io.ReadFull(d.r, b[:])
if err != nil {
return err
}
u := binary.BigEndian.Uint64(b[:])
d.stack = append(d.stack, math.Float64frombits(u)) d.stack = append(d.stack, math.Float64frombits(u))
return nil return nil
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment