You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
There are a bunch of unnecessary defers that incur
a speed cost as defers are slower by ~2X than a
plain function call. Noticed while instrumenting
this driver with OpenCensus.
For those that need numbers to motivate the change:
$ benchstat before.txt after.txt
name old time/op new time/op delta
ConnectionDeficientSize-4 1.15ms ±77% 1.02ms ±55% ~ (p=0.280 n=10+10)
ConnectionDeficientMessageBody-4 2.23ms ±20% 1.94ms ±24% -12.75% (p=0.035 n=10+10)
ConnectionDeficientHeader-4 1.86ms ±41% 1.97ms ±27% ~ (p=0.423 n=9+8)
ConnectionDeficientOpReply-4 2.06ms ±19% 2.11ms ±20% ~ (p=0.931 n=9+9)
Given these benchmarks
```go
package main
import (
"context"
"net"
"testing"
"github.com/mongodb/mongo-go-driver/core/address"
"github.com/mongodb/mongo-go-driver/core/connection"
)
type branch int
const (
deficientSize branch = iota
deficientMessageBody
deficientHeader
deficientOpReply
)
func BenchmarkConnectionDeficientSize(b *testing.B) {
benchmarkAndTakeBranches(b, deficientSize)
}
func BenchmarkConnectionDeficientMessageBody(b *testing.B) {
benchmarkAndTakeBranches(b, deficientMessageBody)
}
func BenchmarkConnectionDeficientHeader(b *testing.B) {
benchmarkAndTakeBranches(b, deficientHeader)
}
func BenchmarkConnectionDeficientOpReply(b *testing.B) {
benchmarkAndTakeBranches(b, deficientOpReply)
}
func benchmarkAndTakeBranches(b *testing.B, behavior branch) {
ln, err := net.Listen("tcp", ":0")
if err != nil {
b.Fatalf("Failed to get address: %v", err)
}
defer ln.Close()
b.ReportAllocs()
// Server routine
go func() {
id := uint64(0)
for {
conn, err := ln.Accept()
id += 1
if err != nil {
return
}
// Expecting:
// 1. 4 bytes for Size
// 2. 16 bytes for MessageHeader
// 3. At least 36 bytes for the message body
// 3. 16 bytes: reply.MessageHeader
// 4. 4 bytes: CursorID
// 5. 4 bytes: StartingFrom
// 6. 4 bytes: Number returned
// buf := new(bytes.Buffer)
switch behavior {
case deficientSize:
// Expecting >= 4 bytes containing the size of the message but
//we'll give them just 3 to trigger "unable to decode message length"
conn.Write([]byte{0x01, 0x02, 0x03})
conn.Close()
case deficientMessageBody:
// Expecting >= 20 bytes of body, but we'll give
// them 5 trigger "unable to read full message"
bz := make([]byte, 5)
bz[0] = 0x10
bz[1] = 0x00
bz[2] = 0x00
bz[3] = 0x00
conn.Write(bz)
conn.Close()
case deficientHeader:
// Expecting >= 20 bytes of body so we'll give them 20
// with no opcode set trigger "opcode not implemented"
bz := make([]byte, 20)
bz[0] = 0x10
bz[1] = 0x00
bz[2] = 0x00
bz[3] = 0x00
conn.Write(bz)
conn.Close()
case deficientOpReply:
// Expecting >= 20 bytes of body so we'll give them 20
// with an opcode set to "OpReply" i.e. 0x01 to trigger
// "unable to decode OP_REPLY"
bz := make([]byte, 20)
bz[0] = 0x10
bz[1] = 0x00
bz[2] = 0x00
bz[3] = 0x00
// set the OpCode to "OpReply" i.e. 0x01
bz[12] = 0x01
conn.Write(bz)
conn.Close()
}
}
}()
ctx := context.Background()
addr := address.Address(ln.Addr().String())
for i := 0; i < b.N; i++ {
conn, _, err := connection.New(ctx, addr)
if err != nil {
b.Errorf("Failed to create connection: %v", err)
continue
}
_, err = conn.ReadWireMessage(ctx)
_ = conn.Close()
}
}
```
0 commit comments