Skip to content

Commit

Permalink
main: cleanup marshalling and unmarshalling benchmarks
Browse files Browse the repository at this point in the history
This adds comments to the Marshal/Unmarshal benchmarks to make it clear
their goals and caveats.

It also splits the marshalling benchmark into two: one with and one
without message reuse.
  • Loading branch information
matheusd committed Aug 1, 2024
1 parent ab9d4d0 commit b0b04f3
Showing 1 changed file with 83 additions and 11 deletions.
94 changes: 83 additions & 11 deletions integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1725,43 +1725,112 @@ func unsafeBytesToString(b []byte) string {
return *(*string)(unsafe.Pointer(&b))
}

// BenchmarkMarshal benchmarks marshalling a message using the simplest API
// available to go-capnp users.
func BenchmarkMarshal(b *testing.B) {
r := rand.New(rand.NewSource(12345))
data := make([]*A, 1000)
for i := range data {
data[i] = generateA(r)
}
arena := make([]byte, 0, 512)
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
a := data[r.Intn(len(data))]
msg, seg, _ := capnp.NewMessage(capnp.SingleSegment(arena[:0]))
root, _ := air.NewRootBenchmarkA(seg)
msg, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
if err != nil {
b.Fatal(err)
}
root, err := air.NewRootBenchmarkA(seg)
if err != nil {
b.Fatal(err)
}
a.fill(root)
_, err = msg.Marshal()
if err != nil {
b.Fatal(err)
}
}
}

// BenchmarkMarshal_ReuseMsg benchmarks marshalling while reusing the message
// object.
func BenchmarkMarshal_ReuseMsg(b *testing.B) {
r := rand.New(rand.NewSource(12345))
data := make([]*A, 1000)
for i := range data {
data[i] = generateA(r)
}
msg, _, err := capnp.NewMessage(capnp.SingleSegment(nil))
if err != nil {
b.Fatal(err)
}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
a := data[r.Intn(len(data))]
seg, err := msg.Reset(msg.Arena)
if err != nil {
b.Fatal(err)
}
root, err := air.NewRootBenchmarkA(seg)
if err != nil {
b.Fatal(err)
}
a.fill(root)
msg.Marshal()
_, err = msg.Marshal()
if err != nil {
b.Fatal(err)
}
}
}

// BenchmarkUnmarshal benchmarks unmarshalling using the simplest API possible
// available to go-capnp users.
func BenchmarkUnmarshal(b *testing.B) {
r := rand.New(rand.NewSource(12345))
data := make([][]byte, 1000)
type testCase struct {
a A
data []byte
}

data := make([]testCase, 1000)
for i := range data {
a := generateA(r)
msg, seg, _ := capnp.NewMessage(capnp.SingleSegment(nil))
root, _ := air.NewRootBenchmarkA(seg)
a.fill(root)
data[i], _ = msg.Marshal()
buf, err := msg.Marshal()
if err != nil {
b.Fatal(err)
}
data[i].data, data[i].a = buf, *a
}

b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
msg, _ := capnp.Unmarshal(data[r.Intn(len(data))])
a, _ := air.ReadRootBenchmarkA(msg)
unmarshalA(a)
testIdx := r.Intn(len(data))
msg, err := capnp.Unmarshal(data[testIdx].data)
if err != nil {
b.Fatal(err)
}
a, err := air.ReadRootBenchmarkA(msg)
if err != nil {
b.Fatal(err)
}
gotA := unmarshalA(a)
if gotA != data[testIdx].a {
b.Fatal("unexpected unmarshalled data")
}
}
}

// BenchmarkUnmarshal_Reuse benchmarks unmarshalling by reusing the msg object
// and directly using the test data buffer as an arena.
//
// NOTE: this bypasses framing done by capnp marshalling, thus expects the
// caller to frame the message appropriately.
func BenchmarkUnmarshal_Reuse(b *testing.B) {
type testCase struct {
a A
Expand All @@ -1786,10 +1855,13 @@ func BenchmarkUnmarshal_Reuse(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
testIdx := r.Intn(len(data))
*ta = testArena(data[testIdx].data[8:])
*ta = testArena(data[testIdx].data[8:]) // [8:] to skip header
msg.Release()
msg.Arena = ta
a, _ := air.ReadRootBenchmarkA(msg)
a, err := air.ReadRootBenchmarkA(msg)
if err != nil {
b.Fatal(err)
}
gotA := unmarshalA(a)
if gotA != data[testIdx].a {
b.Fatal("unexpected unmarshalled data")
Expand Down

0 comments on commit b0b04f3

Please sign in to comment.