mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Eliminate one allocation per send/recv for non-flipcall transport.
Ported from https://github.com/hugelgupf/p9/pull/44. name old time/op new time/op delta SendRecvLegacy-6 61.5µs ± 6% 60.1µs ±11% ~ (p=0.063 n=9+9) SendRecv-6 40.7µs ± 2% 39.8µs ± 5% -2.27% (p=0.035 n=10+10) name old alloc/op new alloc/op delta SendRecvLegacy-6 769B ± 0% 705B ± 0% -8.37% (p=0.000 n=8+10) SendRecv-6 320B ± 0% 256B ± 0% -20.00% (p=0.000 n=10+10) name old allocs/op new allocs/op delta SendRecvLegacy-6 25.0 ± 0% 23.0 ± 0% -8.00% (p=0.000 n=10+10) SendRecv-6 14.0 ± 0% 12.0 ± 0% -14.29% (p=0.000 n=10+10) PiperOrigin-RevId: 326127979
This commit is contained in:
committed by
gVisor bot
parent
89f3197fc3
commit
49947d2eb9
@@ -62,6 +62,8 @@ func TestVersion(t *testing.T) {
|
||||
}
|
||||
|
||||
func benchmarkSendRecv(b *testing.B, fn func(c *Client) func(message, message) error) {
|
||||
b.ReportAllocs()
|
||||
|
||||
// See above.
|
||||
serverSocket, clientSocket, err := unet.SocketPair(false)
|
||||
if err != nil {
|
||||
|
||||
+29
-35
@@ -66,14 +66,17 @@ const (
|
||||
var dataPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
// These buffers are used for decoding without a payload.
|
||||
return make([]byte, initialBufferLength)
|
||||
// We need to return a pointer to avoid unnecessary allocations
|
||||
// (see https://staticcheck.io/docs/checks#SA6002).
|
||||
b := make([]byte, initialBufferLength)
|
||||
return &b
|
||||
},
|
||||
}
|
||||
|
||||
// send sends the given message over the socket.
|
||||
func send(s *unet.Socket, tag Tag, m message) error {
|
||||
data := dataPool.Get().([]byte)
|
||||
dataBuf := buffer{data: data[:0]}
|
||||
data := dataPool.Get().(*[]byte)
|
||||
dataBuf := buffer{data: (*data)[:0]}
|
||||
|
||||
if log.IsLogging(log.Debug) {
|
||||
log.Debugf("send [FD %d] [Tag %06d] %s", s.FD(), tag, m.String())
|
||||
@@ -141,7 +144,7 @@ func send(s *unet.Socket, tag Tag, m message) error {
|
||||
}
|
||||
|
||||
// All set.
|
||||
dataPool.Put(dataBuf.data)
|
||||
dataPool.Put(&dataBuf.data)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -227,12 +230,29 @@ func recv(s *unet.Socket, msize uint32, lookup lookupTagAndType) (Tag, message,
|
||||
|
||||
// Not yet initialized.
|
||||
var dataBuf buffer
|
||||
var vecs [][]byte
|
||||
|
||||
appendBuffer := func(size int) *[]byte {
|
||||
// Pull a data buffer from the pool.
|
||||
datap := dataPool.Get().(*[]byte)
|
||||
data := *datap
|
||||
if size > len(data) {
|
||||
// Create a larger data buffer.
|
||||
data = make([]byte, size)
|
||||
datap = &data
|
||||
} else {
|
||||
// Limit the data buffer.
|
||||
data = data[:size]
|
||||
}
|
||||
dataBuf = buffer{data: data}
|
||||
vecs = append(vecs, data)
|
||||
return datap
|
||||
}
|
||||
|
||||
// Read the rest of the payload.
|
||||
//
|
||||
// This requires some special care to ensure that the vectors all line
|
||||
// up the way they should. We do this to minimize copying data around.
|
||||
var vecs [][]byte
|
||||
if payloader, ok := m.(payloader); ok {
|
||||
fixedSize := payloader.FixedSize()
|
||||
|
||||
@@ -246,22 +266,8 @@ func recv(s *unet.Socket, msize uint32, lookup lookupTagAndType) (Tag, message,
|
||||
}
|
||||
|
||||
if fixedSize != 0 {
|
||||
// Pull a data buffer from the pool.
|
||||
data := dataPool.Get().([]byte)
|
||||
if int(fixedSize) > len(data) {
|
||||
// Create a larger data buffer, ensuring
|
||||
// sufficient capicity for the message.
|
||||
data = make([]byte, fixedSize)
|
||||
defer dataPool.Put(data)
|
||||
dataBuf = buffer{data: data}
|
||||
vecs = append(vecs, data)
|
||||
} else {
|
||||
// Limit the data buffer, and make sure it
|
||||
// gets filled before the payload buffer.
|
||||
defer dataPool.Put(data)
|
||||
dataBuf = buffer{data: data[:fixedSize]}
|
||||
vecs = append(vecs, data[:fixedSize])
|
||||
}
|
||||
datap := appendBuffer(int(fixedSize))
|
||||
defer dataPool.Put(datap)
|
||||
}
|
||||
|
||||
// Include the payload.
|
||||
@@ -274,20 +280,8 @@ func recv(s *unet.Socket, msize uint32, lookup lookupTagAndType) (Tag, message,
|
||||
vecs = append(vecs, p)
|
||||
}
|
||||
} else if remaining != 0 {
|
||||
// Pull a data buffer from the pool.
|
||||
data := dataPool.Get().([]byte)
|
||||
if int(remaining) > len(data) {
|
||||
// Create a larger data buffer.
|
||||
data = make([]byte, remaining)
|
||||
defer dataPool.Put(data)
|
||||
dataBuf = buffer{data: data}
|
||||
vecs = append(vecs, data)
|
||||
} else {
|
||||
// Limit the data buffer.
|
||||
defer dataPool.Put(data)
|
||||
dataBuf = buffer{data: data[:remaining]}
|
||||
vecs = append(vecs, data[:remaining])
|
||||
}
|
||||
datap := appendBuffer(int(remaining))
|
||||
defer dataPool.Put(datap)
|
||||
}
|
||||
|
||||
if len(vecs) > 0 {
|
||||
|
||||
@@ -182,6 +182,8 @@ func TestSendClosed(t *testing.T) {
|
||||
}
|
||||
|
||||
func BenchmarkSendRecv(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
server, client, err := unet.SocketPair(false)
|
||||
if err != nil {
|
||||
b.Fatalf("socketpair got err %v expected nil", err)
|
||||
|
||||
Reference in New Issue
Block a user