diff --git a/.gitignore b/.gitignore index aa14b64..555f01c 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ *.dll *.so *.dylib +*.gob # Test binary, build with `go test -c` *.test diff --git a/bench/go.mod b/bench/go.mod new file mode 100644 index 0000000..902dd8c --- /dev/null +++ b/bench/go.mod @@ -0,0 +1,12 @@ +module github.com/kelindar/binary/bench + +go 1.24.0 + +require ( + github.com/kelindar/bench v0.3.2 + github.com/kelindar/binary v0.0.0 +) + +require gonum.org/v1/gonum v0.17.0 // indirect + +replace github.com/kelindar/binary => ../ diff --git a/bench/go.sum b/bench/go.sum new file mode 100644 index 0000000..8ba0209 --- /dev/null +++ b/bench/go.sum @@ -0,0 +1,12 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/kelindar/bench v0.3.2 h1:FfpiHMW3JLqn8mqY3fWbJ2jebe3AvKMU7asTmtb8zhs= +github.com/kelindar/bench v0.3.2/go.mod h1:GawbXTnuxXM2DOGHllromLgWIU9vqWc0eXoKGkY6tZc= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= +gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/bench/main.go b/bench/main.go new file mode 100644 index 0000000..d05d71f --- /dev/null +++ b/bench/main.go @@ -0,0 +1,541 @@ +// Copyright (c) Roman Atachiants and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +package main + +import ( + "bytes" + "encoding/json" + "fmt" + "time" + + "github.com/kelindar/bench" + "github.com/kelindar/binary" + "github.com/kelindar/binary/nocopy" + "github.com/kelindar/binary/sorted" + binunsafe "github.com/kelindar/binary/unsafe" +) + +func main() { + bench.Run(func(b *bench.B) { + runBinary(b) + runNocopy(b) + runSorted(b) + runUnsafe(b) + }, + bench.WithSamples(100), + bench.WithDuration(10*time.Millisecond), + bench.WithReference(), + ) +} + +// ------------------------------------------------------------------------------ +// Core binary package +// ------------------------------------------------------------------------------ + +type msg struct { + Name string + Timestamp int64 + Payload []byte + Ssid []uint32 +} + +type nested struct { + Meta msg + Tags map[string]string + Items []msg +} + +func runBinary(b *bench.B) { + runBinaryMsg(b) + runBinaryMap(b) + runBinarySlice(b) + runBinaryNested(b) + runBinaryBytes(b) + runBinaryUint64s(b) + runBinaryReuse(b) +} + +func runBinaryMsg(b *bench.B) { + v := msg{ + Name: "Roman", + Timestamp: 1242345235, + Payload: []byte("hi"), + Ssid: []uint32{1, 2, 3}, + } + enc, _ := binary.Marshal(&v) + jsonEnc, _ := json.Marshal(&v) + + var buffer bytes.Buffer + var out msg + var jsonOut msg + + b.Run("binary/enc", + func(int) { binary.Marshal(&v) }, + func(int) { json.Marshal(&v) }, + ) + b.Run("binary/enc-to", func(int) { + buffer.Reset() + binary.MarshalTo(&v, &buffer) + }) + b.Run("binary/dec", + func(int) { binary.Unmarshal(enc, &out) }, + func(int) { json.Unmarshal(jsonEnc, &jsonOut) }, + ) +} + +func runBinaryMap(b *bench.B) { + v := make(map[string][]byte, 100) + for i := 0; i < 100; i++ { + v[fmt.Sprintf("key-%d", i)] = makeBytes(64) + } + enc, _ := binary.Marshal(&v) + jsonEnc, _ := json.Marshal(&v) + + var out map[string][]byte + var jsonOut map[string][]byte + + b.Run("binary/map-enc", + func(int) { binary.Marshal(&v) }, + func(int) { json.Marshal(&v) }, + ) + b.Run("binary/map-dec", + func(int) { binary.Unmarshal(enc, &out) }, + func(int) { json.Unmarshal(jsonEnc, &jsonOut) }, + ) +} + +func runBinarySlice(b *bench.B) { + v := make([]msg, 100) + for i := range v { + v[i] = msg{ + Name: fmt.Sprintf("msg-%d", i), + Timestamp: int64(1500000000 + i), + Payload: makeBytes(32), + Ssid: []uint32{uint32(i), uint32(i + 1), uint32(i + 2)}, + } + } + enc, _ := binary.Marshal(&v) + jsonEnc, _ := json.Marshal(&v) + + var out []msg + var jsonOut []msg + + b.Run("binary/slice-enc", + func(int) { binary.Marshal(&v) }, + func(int) { json.Marshal(&v) }, + ) + b.Run("binary/slice-dec", + func(int) { binary.Unmarshal(enc, &out) }, + func(int) { json.Unmarshal(jsonEnc, &jsonOut) }, + ) +} + +func runBinaryNested(b *bench.B) { + items := make([]msg, 50) + for i := range items { + items[i] = msg{ + Name: fmt.Sprintf("item-%d", i), + Timestamp: int64(1500000000 + i), + Payload: makeBytes(16), + Ssid: []uint32{uint32(i), 1, 2}, + } + } + v := nested{ + Meta: msg{ + Name: "root", + Timestamp: 1500000000, + Payload: []byte("meta"), + Ssid: []uint32{1, 2, 3}, + }, + Tags: map[string]string{ + "env": "prod", + "region": "us-east", + "service": "broker", + }, + Items: items, + } + enc, _ := binary.Marshal(&v) + jsonEnc, _ := json.Marshal(&v) + + var out nested + var jsonOut nested + + b.Run("binary/nest-enc", + func(int) { binary.Marshal(&v) }, + func(int) { json.Marshal(&v) }, + ) + b.Run("binary/nest-dec", + func(int) { binary.Unmarshal(enc, &out) }, + func(int) { json.Unmarshal(jsonEnc, &jsonOut) }, + ) +} + +func runBinaryBytes(b *bench.B) { + v := makeBytes(defaultSize) + enc, _ := binary.Marshal(&v) + var out []byte + + b.Run("binary/bytes-enc", func(int) { binary.Marshal(&v) }) + b.Run("binary/bytes-dec", func(int) { binary.Unmarshal(enc, &out) }) +} + +func runBinaryUint64s(b *bench.B) { + v := makeUint64s(defaultSize) + enc, _ := binary.Marshal(&v) + var out []uint64 + + b.Run("binary/u64-enc", func(int) { binary.Marshal(&v) }) + b.Run("binary/u64-dec", func(int) { binary.Unmarshal(enc, &out) }) +} + +func runBinaryReuse(b *bench.B) { + v := msg{ + Name: "Roman", + Timestamp: 1242345235, + Payload: makeBytes(256), + Ssid: []uint32{1, 2, 3, 4, 5}, + } + enc, _ := binary.Marshal(&v) + + var buf bytes.Buffer + encoder := binary.NewEncoder(&buf) + _ = encoder.Encode(&v) // warm schema cache + + var out msg + reader := bytes.NewReader(enc) + decoder := binary.NewDecoder(reader) + _ = decoder.Decode(&out) // warm schema cache + + b.Run("binary/reuse-enc", + func(int) { + buf.Reset() + encoder.Reset(&buf) + _ = encoder.Encode(&v) + }, + func(int) { binary.Marshal(&v) }, + ) + b.Run("binary/stream-dec", + func(int) { + reader.Reset(enc) + _ = decoder.Decode(&out) + }, + func(int) { binary.Unmarshal(enc, &out) }, + ) +} + +// ------------------------------------------------------------------------------ +// nocopy package +// ------------------------------------------------------------------------------ + +const ( + testString = "Donec egestas enim vitae turpis imperdiet ultricies. Vivamus sollicitudin in felis quis euismod. Nunc at tellus lectus." + defaultSize = 10000 +) + +type nocopyComposite map[string]nocopyColumn + +type nocopyColumn struct { + Varchar nocopyColumnVarchar + Float64 nocopyColumnFloat64 +} + +type nocopyColumnVarchar struct { + Nulls nocopy.Bools + Sizes nocopy.Uint32s + Bytes nocopy.Bytes +} + +type nocopyColumnFloat64 struct { + Nulls nocopy.Bools + Floats nocopy.Float64s +} + +type nocopyMessage struct { + A nocopy.Bytes + B nocopy.Bytes + C nocopy.Bytes + D nocopy.Bytes +} + +func runNocopy(b *bench.B) { + runNocopyString(b) + runNocopyDictionary(b) + runNocopyByteMap(b) + runNocopyHashMap(b) + runNocopyBytes(b) + runNocopyUint64s(b) + runNocopyColumnar(b) + runNocopyStruct(b) +} + +func runNocopyString(b *bench.B) { + safe := testString + unsafe := nocopy.String(testString) + safeEnc, _ := binary.Marshal(&safe) + unsafeEnc, _ := binary.Marshal(&unsafe) + + var safeOut []byte + var unsafeOut nocopy.String + + b.Run("nocopy/str-enc", + func(int) { binary.Marshal(&unsafe) }, + func(int) { binary.Marshal(&safe) }, + ) + b.Run("nocopy/str-dec", + func(int) { binary.Unmarshal(unsafeEnc, &unsafeOut) }, + func(int) { binary.Unmarshal(safeEnc, &safeOut) }, + ) +} + +func runNocopyDictionary(b *bench.B) { + v := nocopy.Dictionary{ + "name": "Roman", + "race": "human", + "status": "happy", + } + enc, _ := binary.Marshal(&v) + var out nocopy.Dictionary + + b.Run("nocopy/dict-enc", func(int) { binary.Marshal(&v) }) + b.Run("nocopy/dict-dec", func(int) { binary.Unmarshal(enc, &out) }) +} + +func runNocopyByteMap(b *bench.B) { + v := nocopy.ByteMap{ + "name": []byte(testString), + "race": []byte(testString), + "status": []byte(testString), + } + enc, _ := binary.Marshal(&v) + var out nocopy.ByteMap + + b.Run("nocopy/bmap-enc", func(int) { binary.Marshal(&v) }) + b.Run("nocopy/bmap-dec", func(int) { binary.Unmarshal(enc, &out) }) +} + +func runNocopyHashMap(b *bench.B) { + v := nocopy.HashMap{ + 1: []byte(testString), + 2: []byte(testString), + 3: []byte(testString), + } + enc, _ := binary.Marshal(&v) + var out nocopy.HashMap + + b.Run("nocopy/hmap-enc", func(int) { binary.Marshal(&v) }) + b.Run("nocopy/hmap-dec", func(int) { binary.Unmarshal(enc, &out) }) +} + +func runNocopyBytes(b *bench.B) { + safe := makeBytes(defaultSize) + unsafe := nocopy.Bytes(makeBytes(defaultSize)) + safeEnc, _ := binary.Marshal(&safe) + unsafeEnc, _ := binary.Marshal(&unsafe) + + var safeOut []byte + var unsafeOut nocopy.Bytes + + b.Run("nocopy/bytes-enc", + func(int) { binary.Marshal(&unsafe) }, + func(int) { binary.Marshal(&safe) }, + ) + b.Run("nocopy/bytes-dec", + func(int) { binary.Unmarshal(unsafeEnc, &unsafeOut) }, + func(int) { binary.Unmarshal(safeEnc, &safeOut) }, + ) +} + +func runNocopyUint64s(b *bench.B) { + safe := makeUint64s(defaultSize) + unsafe := nocopy.Uint64s(makeUint64s(defaultSize)) + safeEnc, _ := binary.Marshal(&safe) + unsafeEnc, _ := binary.Marshal(&unsafe) + + var safeOut []uint64 + var unsafeOut nocopy.Uint64s + + b.Run("nocopy/u64-enc", + func(int) { binary.Marshal(&unsafe) }, + func(int) { binary.Marshal(&safe) }, + ) + b.Run("nocopy/u64-dec", + func(int) { binary.Unmarshal(unsafeEnc, &unsafeOut) }, + func(int) { binary.Unmarshal(safeEnc, &safeOut) }, + ) +} + +func runNocopyColumnar(b *bench.B) { + v := nocopyComposite{} + v["a"] = nocopyColumn{ + Varchar: nocopyColumnVarchar{ + Nulls: nocopy.Bools{false, false, false, true, false, false, false, false, true, false, false, false, false, true, false}, + Sizes: nocopy.Uint32s{2, 2, 2, 0, 2, 2, 2, 2, 0, 2, 2, 2, 2, 0, 2, 2, 2, 2, 0, 2, 2, 2, 2, 0, 2, 2, 2, 2, 0, 2}, + Bytes: nocopy.Bytes{10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, + }, + } + v["b"] = nocopyColumn{ + Float64: nocopyColumnFloat64{ + Nulls: nocopy.Bools{false, false, false, true, false}, + Floats: nocopy.Float64s{1.1, 2.2, 3.3, 0, 4.4}, + }, + } + enc, _ := binary.Marshal(&v) + var out nocopyComposite + + b.Run("nocopy/col-enc", func(int) { binary.Marshal(&v) }) + b.Run("nocopy/col-dec", func(int) { binary.Unmarshal(enc, &out) }) +} + +func runNocopyStruct(b *bench.B) { + v := nocopyMessage{ + A: nocopy.Bytes{10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, + B: nocopy.Bytes{10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, + C: nocopy.Bytes{10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, + D: nocopy.Bytes{10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, + } + enc, _ := binary.Marshal(&v) + var out nocopyMessage + + b.Run("nocopy/struct-enc", func(int) { binary.Marshal(&v) }) + b.Run("nocopy/struct-dec", func(int) { binary.Unmarshal(enc, &out) }) +} + +func makeUint64s(n int) (arr []uint64) { + for i := 0; i < n; i++ { + arr = append(arr, uint64(i)) + } + return +} + +func makeBytes(n int) (arr []byte) { + for i := 0; i < n; i++ { + arr = append(arr, byte(i%255)) + } + return +} + +// ------------------------------------------------------------------------------ +// sorted package +// ------------------------------------------------------------------------------ + +func runSorted(b *bench.B) { + runSortedSlice(b) + runSortedTimestamps(b) + runSortedTimeSeries(b) + runSortedTimeCounters(b) +} + +func runSortedSlice(b *bench.B) { + ints := makeSortedInt32s(defaultSize) + intsEnc, _ := binary.Marshal(&ints) + uints := makeSortedUint32s(defaultSize) + uintsEnc, _ := binary.Marshal(&uints) + + var intsOut sorted.Int32s + var uintsOut sorted.Uint32s + + b.Run("sorted/i32-enc", func(int) { binary.Marshal(&ints) }) + b.Run("sorted/i32-dec", func(int) { binary.Unmarshal(intsEnc, &intsOut) }) + b.Run("sorted/u32-enc", func(int) { binary.Marshal(&uints) }) + b.Run("sorted/u32-dec", func(int) { binary.Unmarshal(uintsEnc, &uintsOut) }) +} + +func makeSortedInt32s(n int) sorted.Int32s { + out := make(sorted.Int32s, n) + for i := 0; i < n; i++ { + out[i] = int32((i * 37) % n) // unsorted; codec sorts on encode + } + return out +} + +func makeSortedUint32s(n int) sorted.Uint32s { + out := make(sorted.Uint32s, n) + for i := 0; i < n; i++ { + out[i] = uint32((i * 37) % n) + } + return out +} + +func runSortedTimestamps(b *bench.B) { + var times sorted.Timestamps + for i := uint64(0); i < 10000; i++ { + times = append(times, uint64(time.Now().Unix())+i) + } + enc, _ := binary.Marshal(×) + var out sorted.Timestamps + + b.Run("sorted/ts-enc", func(int) { binary.Marshal(×) }) + b.Run("sorted/ts-dec", func(int) { binary.Unmarshal(enc, &out) }) +} + +func runSortedTimeSeries(b *bench.B) { + series := makeTimeSeries(20000) + enc, _ := binary.Marshal(series) + var out sorted.TimeSeries + + b.Run("sorted/tsz-enc", func(int) { binary.Marshal(series) }) + b.Run("sorted/tsz-dec", func(int) { binary.Unmarshal(enc, &out) }) +} + +func runSortedTimeCounters(b *bench.B) { + series := makeTimeCounters(20000) + enc, _ := binary.Marshal(series) + var out sorted.TimeCounters + + b.Run("sorted/tcz-enc", func(int) { binary.Marshal(series) }) + b.Run("sorted/tcz-dec", func(int) { binary.Unmarshal(enc, &out) }) +} + +func makeTimeSeries(count int) *sorted.TimeSeries { + var ts sorted.TimeSeries + for i := count - 1; i >= 0; i-- { + ts.Append(uint64(1500000000+i), float64(i)) + } + return &ts +} + +func makeTimeCounters(count int) *sorted.TimeCounters { + var ts sorted.TimeCounters + for i := count - 1; i >= 0; i-- { + ts.Append(uint64(1500000000+i), uint64(i)) + } + return &ts +} + +// ------------------------------------------------------------------------------ +// unsafe package +// ------------------------------------------------------------------------------ + +var uint64Arr = []uint64{4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, + 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, + 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, + 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, + 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, + 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, + 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, + 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, + 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, + 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, + 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, + 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, + 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6} + +func runUnsafe(b *bench.B) { + safe := uint64Arr + unsafe := binunsafe.Uint64s(uint64Arr) + safeEnc, _ := binary.Marshal(&safe) + unsafeEnc, _ := binary.Marshal(&unsafe) + + var safeOut []uint64 + var unsafeOut binunsafe.Uint64s + + b.Run("unsafe/u64-enc", + func(int) { binary.Marshal(&unsafe) }, + func(int) { binary.Marshal(&safe) }, + ) + b.Run("unsafe/u64-dec", + func(int) { binary.Unmarshal(unsafeEnc, &unsafeOut) }, + func(int) { binary.Unmarshal(safeEnc, &safeOut) }, + ) +} diff --git a/encoder_test.go b/encoder_test.go index bfdc5d7..2c70451 100644 --- a/encoder_test.go +++ b/encoder_test.go @@ -4,21 +4,12 @@ package binary import ( - "bytes" - "encoding/json" "testing" "unsafe" "github.com/stretchr/testify/assert" ) -var testMsg = msg{ - Name: "Roman", - Timestamp: 1242345235, - Payload: []byte("hi"), - Ssid: []uint32{1, 2, 3}, -} - type composite map[string]column type column struct { @@ -87,66 +78,6 @@ func newComposite() composite { return v } -/* -cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz -Benchmark_Binary/marshal-12 5074890 227.4 ns/op 112 B/op 2 allocs/op -Benchmark_Binary/marshal-to-12 7011523 162.3 ns/op 30 B/op 0 allocs/op -Benchmark_Binary/unmarshal-12 4224048 283.0 ns/op 72 B/op 5 allocs/op -*/ -func BenchmarkBinary(b *testing.B) { - v := testMsg - enc, _ := Marshal(&v) - - b.Run("marshal", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - Marshal(&v) - } - }) - - var buffer bytes.Buffer - b.Run("marshal-to", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - buffer.Reset() - MarshalTo(&v, &buffer) - } - }) - - b.Run("unmarshal", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - var out msg - for n := 0; n < b.N; n++ { - Unmarshal(enc, &out) - } - }) -} - -func BenchmarkJSON(b *testing.B) { - v := testMsg - enc, _ := json.Marshal(&v) - - b.Run("marshal", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - json.Marshal(&v) - } - }) - - b.Run("unmarshal", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - var out msg - for n := 0; n < b.N; n++ { - json.Unmarshal(enc, &out) - } - }) -} - func TestBinaryEncodeStruct(t *testing.T) { b, err := Marshal(s0v) assert.NoError(t, err) diff --git a/nocopy/codecs_test.go b/nocopy/codecs_test.go deleted file mode 100644 index 9111963..0000000 --- a/nocopy/codecs_test.go +++ /dev/null @@ -1,339 +0,0 @@ -// Copyright (c) Roman Atachiants and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for details. - -package nocopy - -import ( - "testing" - - "github.com/kelindar/binary" -) - -const testString = "Donec egestas enim vitae turpis imperdiet ultricies. Vivamus sollicitudin in felis quis euismod. Nunc at tellus lectus." -const defaultSize = 10000 - -func makeUint64s(n int) (arr []uint64) { - for i := 0; i < n; i++ { - arr = append(arr, uint64(i)) - } - return -} - -func makeBytes(n int) (arr []byte) { - for i := 0; i < n; i++ { - arr = append(arr, byte(i%255)) - } - return -} - -// BenchmarkString_Safe/marshal-8 5000000 368 ns/op 368 B/op 3 allocs/op -// BenchmarkString_Safe/unmarshal-8 5000000 227 ns/op 160 B/op 2 allocs/op -func BenchmarkString_Safe(b *testing.B) { - v := testString - enc, _ := binary.Marshal(&v) - - b.Run("marshal", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - binary.Marshal(&v) - } - }) - - b.Run("unmarshal", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - var out []byte - for n := 0; n < b.N; n++ { - binary.Unmarshal(enc, &out) - } - }) -} - -// BenchmarkDictionary_Unsafe/marshal-8 4282570 283.8 ns/op 112 B/op 2 allocs/op -// BenchmarkDictionary_Unsafe/unmarshal-8 3678001 329.1 ns/op 336 B/op 2 allocs/op -func BenchmarkDictionary_Unsafe(b *testing.B) { - v := Dictionary{ - "name": "Roman", - "race": "human", - "status": "happy", - } - - enc, _ := binary.Marshal(&v) - - b.Run("marshal", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - binary.Marshal(&v) - } - }) - - b.Run("unmarshal", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - var out Dictionary - for n := 0; n < b.N; n++ { - binary.Unmarshal(enc, &out) - } - }) -} - -// BenchmarkByteMap_Unsafe/marshal-8 2362354 501.8 ns/op 1008 B/op 4 allocs/op -// BenchmarkByteMap_Unsafe/unmarshal-8 3651502 355.3 ns/op 400 B/op 2 allocs/op -func BenchmarkByteMap_Unsafe(b *testing.B) { - v := ByteMap{ - "name": []byte(testString), - "race": []byte(testString), - "status": []byte(testString), - } - - enc, _ := binary.Marshal(&v) - - b.Run("marshal", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - binary.Marshal(&v) - } - }) - - b.Run("unmarshal", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - var out ByteMap - for n := 0; n < b.N; n++ { - binary.Unmarshal(enc, &out) - } - }) -} - -// BenchmarkHashMap_Unsafe/marshal-8 2542200 478.5 ns/op 1008 B/op 4 allocs/op -// BenchmarkHashMap_Unsafe/unmarshal-8 4157452 291.8 ns/op 336 B/op 2 allocs/op -func BenchmarkHashMap_Unsafe(b *testing.B) { - v := HashMap{ - 1: []byte(testString), - 2: []byte(testString), - 3: []byte(testString), - } - - enc, _ := binary.Marshal(&v) - - b.Run("marshal", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - binary.Marshal(&v) - } - }) - - b.Run("unmarshal", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - var out HashMap - for n := 0; n < b.N; n++ { - binary.Unmarshal(enc, &out) - } - }) -} - -// BenchmarkString_Unsafe/marshal-8 5000000 348 ns/op 368 B/op 3 allocs/op -// BenchmarkString_Unsafe/unmarshal-8 20000000 108 ns/op 0 B/op 0 allocs/op -func BenchmarkString_Unsafe(b *testing.B) { - v := String(testString) - enc, _ := binary.Marshal(&v) - - b.Run("marshal", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - binary.Marshal(&v) - } - }) - - b.Run("unmarshal", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - var out String - for n := 0; n < b.N; n++ { - binary.Unmarshal(enc, &out) - } - }) -} - -func asBytes(v []uint64) (o []byte) { - for i := range v { - o = append(o, byte(v[i])) - } - return -} - -// BenchmarkBytes_Safe/marshal-8 1000000 1616 ns/op 10354 B/op 3 allocs/op -// BenchmarkBytes_Safe/unmarshal-8 1000000 1547 ns/op 10274 B/op 2 allocs/op -func BenchmarkBytes_Safe(b *testing.B) { - v := makeBytes(defaultSize) - enc, _ := binary.Marshal(&v) - - b.Run("marshal", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - binary.Marshal(&v) - } - }) - - b.Run("unmarshal", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - var out []byte - for n := 0; n < b.N; n++ { - binary.Unmarshal(enc, &out) - } - }) -} - -// BenchmarkBytes_Unsafe/marshal-8 1000000 1676 ns/op 10354 B/op 3 allocs/op -// BenchmarkBytes_Unsafe/unmarshal-8 20000000 116 ns/op 0 B/op 0 allocs/op -func BenchmarkBytes_Unsafe(b *testing.B) { - v := Bytes(makeBytes(defaultSize)) - enc, _ := binary.Marshal(&v) - - b.Run("marshal", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - binary.Marshal(&v) - } - }) - - b.Run("unmarshal", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - var out Bytes - for n := 0; n < b.N; n++ { - binary.Unmarshal(enc, &out) - } - }) -} - -// BenchmarkUint64s_Safe/marshal-8 10000 167612 ns/op 78325 B/op 11 allocs/op -// BenchmarkUint64s_Safe/unmarshal-8 5000 286769 ns/op 81975 B/op 2 allocs/op -func BenchmarkUint64s_Safe(b *testing.B) { - v := makeUint64s(defaultSize) - enc, _ := binary.Marshal(&v) - - b.Run("marshal", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - binary.Marshal(&v) - } - }) - - b.Run("unmarshal", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - var out []uint64 - for n := 0; n < b.N; n++ { - binary.Unmarshal(enc, &out) - } - }) -} - -// BenchmarkUint64s_Unsafe/marshal-8 100000 10711 ns/op 82055 B/op 3 allocs/op -// BenchmarkUint64s_Unsafe/unmarshal-8 20000000 109 ns/op 0 B/op 0 allocs/op -func BenchmarkUint64s_Unsafe(b *testing.B) { - v := Uint64s(makeUint64s(defaultSize)) - enc, _ := binary.Marshal(&v) - - b.Run("marshal", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - binary.Marshal(&v) - } - }) - - b.Run("unmarshal", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - var out Uint64s - for n := 0; n < b.N; n++ { - binary.Unmarshal(enc, &out) - } - }) -} - -// BenchmarkColumnar_Unsafe/marshal-8 1000000 1712 ns/op 1450 B/op 10 allocs/op -// BenchmarkColumnar_Unsafe/unmarshal-8 1000000 1519 ns/op 1056 B/op 10 allocs/op -func BenchmarkColumnar_Unsafe(b *testing.B) { - v := composite{} - v["a"] = column{ - Varchar: columnVarchar{ - Nulls: Bools{false, false, false, true, false, false, false, false, true, false, false, false, false, true, false}, - Sizes: Uint32s{2, 2, 2, 0, 2, 2, 2, 2, 0, 2, 2, 2, 2, 0, 2, 2, 2, 2, 0, 2, 2, 2, 2, 0, 2, 2, 2, 2, 0, 2}, - Bytes: Bytes{10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, - }, - } - v["b"] = column{ - Float64: columnFloat64{ - Nulls: Bools{false, false, false, true, false}, - Floats: Float64s{1.1, 2.2, 3.3, 0, 4.4}, - }, - } - - enc, _ := binary.Marshal(&v) - - b.Run("marshal", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - binary.Marshal(&v) - } - }) - - b.Run("unmarshal", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - var out composite - for n := 0; n < b.N; n++ { - binary.Unmarshal(enc, &out) - } - }) -} - -type message struct { - A Bytes - B Bytes - C Bytes - D Bytes -} - -// BenchmarkStruct_Unsafe/marshal-8 3000000 459 ns/op 272 B/op 3 allocs/op -// BenchmarkStruct_Unsafe/unmarshal-8 10000000 221 ns/op 0 B/op 0 allocs/op -func BenchmarkStruct_Unsafe(b *testing.B) { - v := message{ - A: Bytes{10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, - B: Bytes{10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, - C: Bytes{10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, - D: Bytes{10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, - } - enc, _ := binary.Marshal(&v) - - b.Run("marshal", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - binary.Marshal(&v) - } - }) - - b.Run("unmarshal", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - var out message - for n := 0; n < b.N; n++ { - binary.Unmarshal(enc, &out) - } - }) -} diff --git a/sorted/codecs_test.go b/sorted/codecs_test.go index 18fe7ec..aceab9b 100644 --- a/sorted/codecs_test.go +++ b/sorted/codecs_test.go @@ -5,91 +5,11 @@ package sorted import ( "testing" - "time" "github.com/kelindar/binary" "github.com/stretchr/testify/assert" ) -/* -cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz -BenchmarkSortedSlice/encode-int-12 1875320 614.1 ns/op 216 B/op 4 allocs/op -BenchmarkSortedSlice/decode-int-12 544180 2187 ns/op 1080 B/op 36 allocs/op -BenchmarkSortedSlice/encode-uint-12 2051314 581.3 ns/op 216 B/op 4 allocs/op -BenchmarkSortedSlice/decode-uint-12 571098 2170 ns/op 1080 B/op 36 allocs/op -*/ -func BenchmarkSortedSlice(b *testing.B) { - ints := Int32s{4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6} - intsEnc, _ := binary.Marshal(&ints) - - b.Run("encode-int", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - binary.Marshal(&ints) - } - }) - - b.Run("decode-int", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - var out Int64s - for n := 0; n < b.N; n++ { - binary.Unmarshal(intsEnc, &out) - } - }) - - uints := Uint32s{4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6} - uintsEnc, _ := binary.Marshal(&uints) - - b.Run("encode-uint", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - binary.Marshal(&uints) - } - }) - - b.Run("decode-uint", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - var out Uint64s - for n := 0; n < b.N; n++ { - binary.Unmarshal(uintsEnc, &out) - } - }) -} - -/* -cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz -BenchmarkTimes/encode-12 17698 76181 ns/op 30893 B/op 6 allocs/op -BenchmarkTimes/decode-12 22126 54699 ns/op 81977 B/op 2 allocs/op -*/ -func BenchmarkTimestamps(b *testing.B) { - var times Timestamps - for i := uint64(0); i < 10000; i++ { - times = append(times, uint64(time.Now().Unix())+i) - } - enc, _ := binary.Marshal(×) - - b.Run("encode", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - binary.Marshal(×) - } - }) - - b.Run("decode", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - var out Timestamps - for n := 0; n < b.N; n++ { - binary.Unmarshal(enc, &out) - } - }) -} - func TestPayload(t *testing.T) { encoded := []byte{0x8, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2} diff --git a/sorted/counters_test.go b/sorted/counters_test.go index f1549f3..8955d52 100644 --- a/sorted/counters_test.go +++ b/sorted/counters_test.go @@ -7,32 +7,6 @@ import ( "github.com/stretchr/testify/assert" ) -/* -BenchmarkTimeCounters/encode-10 10000 105358 ns/op 123137 B/op 6 allocs/op -BenchmarkTimeCounters/decode-10 14527 83441 ns/op 661026 B/op 22 allocs/op -*/ -func BenchmarkTimeCounters(b *testing.B) { - series := makeTimeCounters(20000) - enc, _ := binary.Marshal(&series) - - b.Run("encode", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - binary.Marshal(&series) - } - }) - - b.Run("decode", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - var out Timestamps - for n := 0; n < b.N; n++ { - binary.Unmarshal(enc, &out) - } - }) -} - func TestTimeCounters(t *testing.T) { // Marshal diff --git a/sorted/timeseries_test.go b/sorted/timeseries_test.go index b7298d0..e756c62 100644 --- a/sorted/timeseries_test.go +++ b/sorted/timeseries_test.go @@ -10,32 +10,6 @@ import ( "github.com/stretchr/testify/assert" ) -/* -BenchmarkTimeSeries/encode-10 10000 103506 ns/op 123136 B/op 6 allocs/op -BenchmarkTimeSeries/decode-10 13610 85692 ns/op 661022 B/op 22 allocs/op -*/ -func BenchmarkTimeSeries(b *testing.B) { - series := makeTimeCounters(20000) - enc, _ := binary.Marshal(&series) - - b.Run("encode", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - binary.Marshal(&series) - } - }) - - b.Run("decode", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - var out Timestamps - for n := 0; n < b.N; n++ { - binary.Unmarshal(enc, &out) - } - }) -} - func TestTimeSeries(t *testing.T) { // Marshal diff --git a/unsafe/codecs_test.go b/unsafe/codecs_test.go deleted file mode 100644 index 67605d4..0000000 --- a/unsafe/codecs_test.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) Roman Atachiants and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for details. - -package unsafe - -import ( - "testing" - - "github.com/kelindar/binary" -) - -var arr = []uint64{4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, - 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, - 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, - 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, - 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, - 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, - 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, - 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, - 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, - 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, - 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, - 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, - 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6, 4, 5, 6, 1, 2, 3, 5, 3, 2, 6, 1, 6, 7, 6, 1, 2, 6} - -func BenchmarkUint64s_Safe(b *testing.B) { - v := arr - enc, _ := binary.Marshal(&v) - - b.Run("marshal", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - binary.Marshal(&v) - } - }) - - b.Run("unmarshal", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - var out []uint64 - for n := 0; n < b.N; n++ { - binary.Unmarshal(enc, &out) - } - }) -} - -func BenchmarkUint64s_Unsafe(b *testing.B) { - v := Uint64s(arr) - enc, _ := binary.Marshal(&v) - - b.Run("marshal", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - binary.Marshal(&v) - } - }) - - b.Run("unmarshal", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - var out Uint64s - for n := 0; n < b.N; n++ { - binary.Unmarshal(enc, &out) - } - }) -}