Skip to content

Commit

Permalink
kv: allocate BatchResponse header and responses together
Browse files Browse the repository at this point in the history
Avoids a heap allocation on each BatchResponse creations.

```
name                                           old time/op    new time/op    delta
Sysbench/KV/1node_remote/oltp_point_select-10    39.8µs ±16%    39.6µs ±19%    ~     (p=0.968 n=9+10)

name                                           old alloc/op   new alloc/op   delta
Sysbench/KV/1node_remote/oltp_point_select-10    6.79kB ± 4%    6.77kB ± 4%    ~     (p=0.671 n=10+10)

name                                           old allocs/op  new allocs/op  delta
Sysbench/KV/1node_remote/oltp_point_select-10      60.0 ± 0%      59.0 ± 0%  -1.67%  (p=0.000 n=9+8)
```
  • Loading branch information
nvanbenschoten committed Dec 10, 2024
1 parent 34e3abf commit 0165b50
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 4 deletions.
38 changes: 36 additions & 2 deletions pkg/kv/kvpb/batch_generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

40 changes: 38 additions & 2 deletions pkg/kv/kvpb/gen/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -366,13 +366,49 @@ func (ba *BatchRequest) WriteSummary(b *strings.Builder) {
allocTypes[resV.variantName] = allocName
}

fmt.Fprint(f, `
func allocBatchResponse(nResps int) *BatchResponse {
if nResps <= 1 {
alloc := new(struct {
br BatchResponse
resps [1]ResponseUnion
})
alloc.br.Responses = alloc.resps[:nResps]
return &alloc.br
} else if nResps <= 2 {
alloc := new(struct {
br BatchResponse
resps [2]ResponseUnion
})
alloc.br.Responses = alloc.resps[:nResps]
return &alloc.br
} else if nResps <= 4 {
alloc := new(struct {
br BatchResponse
resps [4]ResponseUnion
})
alloc.br.Responses = alloc.resps[:nResps]
return &alloc.br
} else if nResps <= 8 {
alloc := new(struct {
br BatchResponse
resps [8]ResponseUnion
})
alloc.br.Responses = alloc.resps[:nResps]
return &alloc.br
}
br := &BatchResponse{}
br.Responses = make([]ResponseUnion, nResps)
return br
}
`)

fmt.Fprint(f, `
// CreateReply creates replies for each of the contained requests, wrapped in a
// BatchResponse. The response objects are batch allocated to minimize
// allocation overhead.
func (ba *BatchRequest) CreateReply() *BatchResponse {
br := &BatchResponse{}
br.Responses = make([]ResponseUnion, len(ba.Requests))
br := allocBatchResponse(len(ba.Requests))
counts := ba.getReqCounts()
Expand Down

0 comments on commit 0165b50

Please sign in to comment.