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) {
e.w.Write([]byte{opShortBinstring, byte(l)})
} else {
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)
......@@ -124,7 +126,9 @@ func (e *Encoder) encodeFloat(f float64) {
var u uint64
u = math.Float64bits(f)
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) {
......@@ -138,7 +142,9 @@ func (e *Encoder) encodeInt(k reflect.Kind, i int64) {
e.w.Write([]byte{opBinint2, byte(i), byte(i >> 8)})
case i >= math.MinInt32 && i <= math.MaxInt32:
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 :/
e.w.Write([]byte{opInt})
fmt.Fprintf(e.w, "%d\n", i)
......
......@@ -307,8 +307,12 @@ func (d *Decoder) loadInt() error {
// Push a four-byte signed int
func (d *Decoder) loadBinInt() error {
var v int32
binary.Read(d.r, binary.LittleEndian, &v)
var b [4]byte
_, err := io.ReadFull(d.r, b[:])
if err != nil {
return err
}
v := binary.LittleEndian.Uint32(b[:])
d.push(int64(v))
return nil
}
......@@ -334,12 +338,13 @@ func (d *Decoder) loadLong() error {
// Push a 2-byte unsigned int
func (d *Decoder) loadBinInt2() error {
var u uint16
err := binary.Read(d.r, binary.LittleEndian, &u)
var b [2]byte
_, err := io.ReadFull(d.r, b[:])
if err != nil {
return err
}
d.push(int64(u))
v := binary.LittleEndian.Uint16(b[:])
d.push(int64(v))
return nil
}
......@@ -394,11 +399,12 @@ func (d *Decoder) loadString() error {
}
func (d *Decoder) loadBinString() error {
var v int32
err := binary.Read(d.r, binary.LittleEndian, &v)
var b [4]byte
_, err := io.ReadFull(d.r, b[:])
if err != nil {
return err
}
v := binary.LittleEndian.Uint32(b[:])
s := make([]byte, v)
_, err = io.ReadFull(d.r, s)
if err != nil {
......@@ -526,8 +532,12 @@ func (d *Decoder) inst() error {
}
func (d *Decoder) longBinGet() error {
var v int32
binary.Read(d.r, binary.LittleEndian, &v)
var b [4]byte
_, err := io.ReadFull(d.r, b[:])
if err != nil {
return err
}
v := binary.LittleEndian.Uint32(b[:])
d.push(d.memo[strconv.Itoa(int(v))])
return nil
}
......@@ -599,8 +609,12 @@ func (d *Decoder) loadSetItems() error {
}
func (d *Decoder) binFloat() error {
var u uint64
binary.Read(d.r, binary.BigEndian, &u)
var b [8]byte
_, err := io.ReadFull(d.r, b[:])
if err != nil {
return err
}
u := binary.BigEndian.Uint64(b[:])
d.stack = append(d.stack, math.Float64frombits(u))
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