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:
Fazlul Shahriar
2020-08-11 16:43:23 -07:00
committed by gVisor bot
parent 89f3197fc3
commit 49947d2eb9
3 changed files with 33 additions and 35 deletions
+2
View File
@@ -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
View File
@@ -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 {
+2
View File
@@ -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)