Benchmarking converting types to binary

I’ve been working on saving types such as int/float etc. in dgraph as binary instead of the string representation that we now have. I was investigating the various ways of converting these types to the corresponding byte arrays in Go. Go offers many solutions for this. There is encoding/binary, encoding/gob, saving as the string representation, or writing bytes directly.

I decided to run benchmarks on the different methods to see which works well. The results were pretty surprising to me, which is why I’m sharing them.

I compared 4 ways of encoding/decoding ints:

Using encoding/binary

func binaryWriteInt(value int) ([]byte, error) {
    bs := make([]byte, 0, 8)
    buf := bytes.NewBuffer(bs)
    err := binary.Write(buf, binary.LittleEndian, int64(value))
    return buf.Bytes(), err
}

Using ByteOrder in encoding/binary

func encodingWriteInt(value int) []byte {
    bs := make([]byte, 8)
    binary.LittleEndian.PutUint64(bs, uint64(value))
    return bs
}

Using strings

func strWriteInt(value int) []byte {
    s := strconv.Itoa(value)
    return []byte(s)
}

Using encoding/gob

func gobWriteInt(value int) ([]byte, error) {
    var buf bytes.Buffer
    enc := gob.NewEncoder(&buf)
    err := enc.Encode(value)
    return buf.Bytes(), err
}

The read functions are similar. The benchmarks on these functions (including both encoding & decoding) show:

BenchmarkEncodeIntBinary-4               5000000               391 ns/op
BenchmarkEncodeIntEncoding             500000000                3.05 ns/op
BenchmarkEncodeIntGob-4                   300000              5235 ns/op
BenchmarkEncodeIntStr-4                 10000000               191 ns/op

It turns out encoding/binary is really slow, even slower than encoding/decoding it as a string. Directly writing the bytes is 100 times faster. Both encoding/gob and encoding/binary use reflection, which makes it much slower.

Using this information, I updated the library that parses WKB (it was using encoding/binary). The old benchmark was:

BenchmarkParseWKBPayne-4                 100          11519626 ns/op

after my changes, the benchmark is:

BenchmarkParseWKBPayne-4                 200           6085073 ns/op

which is a 45% improvement

4 Likes

That’s a pretty nice analysis @kostub. Thanks for sharing this.

1 Like