Skip to content

Commit

Permalink
go: header build performance and tests (smfrpc#273)
Browse files Browse the repository at this point in the history
Just because we have some trickery with allocating more bytes and trimming
first 4 bytes it's better to test it continously if go flatbuffers
library would decide to change implementation and break it.

I benchmarked few sizes and here are the results and they're pretty
consistent, works best on 32 bytes buffer.

BenchmarkBuildHeader_20-12       5000000     277 ns/op   176 B/op    4 allocs/op
BenchmarkBuildHeader_24-12       5000000     276 ns/op   176 B/op    4 allocs/op
BenchmarkBuildHeader_25-12      10000000     196 ns/op   96 B/op     2 allocs/op
BenchmarkBuildHeader_26-12      10000000     196 ns/op   96 B/op     2 allocs/op
BenchmarkBuildHeader_28-12      10000000     194 ns/op   96 B/op     2 allocs/op
BenchmarkBuildHeader_32-12      10000000     194 ns/op   96 B/op     2 allocs/op
BenchmarkBuildHeader_48-12      10000000     196 ns/op   112 B/op    2 allocs/op

... and worse from there if size increases. Benchmark is included.
  • Loading branch information
crackcomm authored and emaxerrno committed Jul 31, 2018
1 parent 1c218d3 commit 25b6726
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 2 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -64,6 +64,7 @@ src/demo_apps/demo_server
# tests
src/integration_tests/*_test
src/test/*_unit_test
*.test

# docs
Doxyfile
Expand Down
62 changes: 62 additions & 0 deletions src/go/smf/header_test.go
@@ -0,0 +1,62 @@
package smf

import (
cryptorand "crypto/rand"
"io"
"math"
"math/rand"
. "testing"

"github.com/cespare/xxhash"
flatbuffers "github.com/google/flatbuffers/go"
)

func TestBuildHeader(t *T) {
for index := 0; index < 10; index++ {
meta := uint32(rand.Intn(65535))
sess := uint16(rand.Intn(65535))
body := make([]byte, rand.Intn(200))
io.ReadFull(cryptorand.Reader, body)
hbody := BuildHeader(sess, body, meta)
assertEqual(t, 16, len(hbody))
hdr := NewHeader(hbody)
assertEqual(t, meta, hdr.Meta())
assertEqual(t, sess, hdr.Session())
assertEqual(t, uint32(len(body)), hdr.Size())
checksum := uint32(math.MaxUint32 & xxhash.Sum64(body))
assertEqual(t, checksum, hdr.Checksum())
}
}

func BenchmarkBuildHeader(b *B) {
meta := uint32(rand.Intn(65535))
sess := uint16(rand.Intn(65535))
body := make([]byte, rand.Intn(200))
checksum := math.MaxUint32 & xxhash.Sum64(body)
io.ReadFull(cryptorand.Reader, body)
b.ResetTimer()
for i := 0; i < b.N; i++ {
builder := flatbuffers.NewBuilder(32) // [1]
res := CreateHeader(builder,
0, // compression int8,
0, // bitflags int8,
sess, // session uint16,
uint32(len(body)), // size uint32,
uint32(checksum), // checksum uint32,
meta, // meta uint32
)
builder.Finish(res)
// TODO(crackcomm): builder prepends 4 bytes
// the header is the last 16 bytes of message
// so I did [^1] 32 bytes allocation anyway
// I have no idea why it does that
// _ = builder.FinishedBytes()
}
}

func assertEqual(t *T, in, out interface{}) {
if in != out {
t.Helper()
t.Fatalf("expected %v got %v", in, out)
}
}
4 changes: 2 additions & 2 deletions src/go/smf/header_utils.go
Expand Up @@ -18,7 +18,7 @@ func NewHeader(buf []byte) (hdr *Header) {

// BuildHeader - Builds smf RPC request/response header.
func BuildHeader(session uint16, body []byte, meta uint32) []byte {
builder := flatbuffers.NewBuilder(20) // [1]
builder := flatbuffers.NewBuilder(32) // [1]
res := CreateHeader(builder,
0, // compression int8,
0, // bitflags int8,
Expand All @@ -30,7 +30,7 @@ func BuildHeader(session uint16, body []byte, meta uint32) []byte {
builder.Finish(res)
// TODO(crackcomm): builder prepends 4 bytes
// the header is the last 16 bytes of message
// so I did [^1] 20 bytes allocation anyway
// so I did [^1] 32 bytes allocation anyway
// I have no idea why it does that
return builder.FinishedBytes()[4:]
}
Expand Down

0 comments on commit 25b6726

Please sign in to comment.