Skip to content

Commit a720b30

Browse files
Jorropogopherbot
authored andcommitted
http2: allocate buffer pools using pointers to arrays
This remove the allocation for the slice header in sync.Pool.New and putDataBufferChunk. It also divide the number of allocations kept alive by the pool. Change-Id: Icf493ebc568ae80a4e73e9768a6f1c7fce8e1365 Reviewed-on: https://go-review.googlesource.com/c/net/+/539915 Reviewed-by: Bryan Mills <[email protected]> Auto-Submit: Damien Neil <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Brad Fitzpatrick <[email protected]> Reviewed-by: Damien Neil <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Run-TryBot: qiulaidongfeng <[email protected]> Reviewed-by: qiulaidongfeng <[email protected]>
1 parent a7ef1a2 commit a720b30

File tree

1 file changed

+31
-28
lines changed

1 file changed

+31
-28
lines changed

http2/databuffer.go

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -20,41 +20,44 @@ import (
2020
// TODO: Benchmark to determine if the pools are necessary. The GC may have
2121
// improved enough that we can instead allocate chunks like this:
2222
// make([]byte, max(16<<10, expectedBytesRemaining))
23-
var (
24-
dataChunkSizeClasses = []int{
25-
1 << 10,
26-
2 << 10,
27-
4 << 10,
28-
8 << 10,
29-
16 << 10,
30-
}
31-
dataChunkPools = [...]sync.Pool{
32-
{New: func() interface{} { return make([]byte, 1<<10) }},
33-
{New: func() interface{} { return make([]byte, 2<<10) }},
34-
{New: func() interface{} { return make([]byte, 4<<10) }},
35-
{New: func() interface{} { return make([]byte, 8<<10) }},
36-
{New: func() interface{} { return make([]byte, 16<<10) }},
37-
}
38-
)
23+
var dataChunkPools = [...]sync.Pool{
24+
{New: func() interface{} { return new([1 << 10]byte) }},
25+
{New: func() interface{} { return new([2 << 10]byte) }},
26+
{New: func() interface{} { return new([4 << 10]byte) }},
27+
{New: func() interface{} { return new([8 << 10]byte) }},
28+
{New: func() interface{} { return new([16 << 10]byte) }},
29+
}
3930

4031
func getDataBufferChunk(size int64) []byte {
41-
i := 0
42-
for ; i < len(dataChunkSizeClasses)-1; i++ {
43-
if size <= int64(dataChunkSizeClasses[i]) {
44-
break
45-
}
32+
switch {
33+
case size <= 1<<10:
34+
return dataChunkPools[0].Get().(*[1 << 10]byte)[:]
35+
case size <= 2<<10:
36+
return dataChunkPools[1].Get().(*[2 << 10]byte)[:]
37+
case size <= 4<<10:
38+
return dataChunkPools[2].Get().(*[4 << 10]byte)[:]
39+
case size <= 8<<10:
40+
return dataChunkPools[3].Get().(*[8 << 10]byte)[:]
41+
default:
42+
return dataChunkPools[4].Get().(*[16 << 10]byte)[:]
4643
}
47-
return dataChunkPools[i].Get().([]byte)
4844
}
4945

5046
func putDataBufferChunk(p []byte) {
51-
for i, n := range dataChunkSizeClasses {
52-
if len(p) == n {
53-
dataChunkPools[i].Put(p)
54-
return
55-
}
47+
switch len(p) {
48+
case 1 << 10:
49+
dataChunkPools[0].Put((*[1 << 10]byte)(p))
50+
case 2 << 10:
51+
dataChunkPools[1].Put((*[2 << 10]byte)(p))
52+
case 4 << 10:
53+
dataChunkPools[2].Put((*[4 << 10]byte)(p))
54+
case 8 << 10:
55+
dataChunkPools[3].Put((*[8 << 10]byte)(p))
56+
case 16 << 10:
57+
dataChunkPools[4].Put((*[16 << 10]byte)(p))
58+
default:
59+
panic(fmt.Sprintf("unexpected buffer len=%v", len(p)))
5660
}
57-
panic(fmt.Sprintf("unexpected buffer len=%v", len(p)))
5861
}
5962

6063
// dataBuffer is an io.ReadWriter backed by a list of data chunks.

0 commit comments

Comments
 (0)