mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
netstack: don't allocate by calling AsSlices() in fdbased endpoint
In a redis-benchmark PING_INLINE test, this reduces allocations by 23%. PiperOrigin-RevId: 614144212
This commit is contained in:
committed by
gVisor bot
parent
7e395bbbd4
commit
6ad1af2b9c
+1
-1
@@ -21,7 +21,7 @@ go_template_instance(
|
||||
name = "view_list",
|
||||
out = "view_list.go",
|
||||
package = "buffer",
|
||||
prefix = "view",
|
||||
prefix = "View",
|
||||
template = "//pkg/ilist:generic_list",
|
||||
types = {
|
||||
"Element": "*View",
|
||||
|
||||
@@ -28,7 +28,7 @@ import (
|
||||
//
|
||||
// +stateify savable
|
||||
type Buffer struct {
|
||||
data viewList `state:".([]byte)"`
|
||||
data ViewList `state:".([]byte)"`
|
||||
size int64
|
||||
}
|
||||
|
||||
@@ -398,6 +398,12 @@ func (b *Buffer) Size() int64 {
|
||||
return b.size
|
||||
}
|
||||
|
||||
// AsViewList returns the ViewList backing b. Users may not save or modify the
|
||||
// ViewList returned.
|
||||
func (b *Buffer) AsViewList() ViewList {
|
||||
return b.data
|
||||
}
|
||||
|
||||
// Clone creates a copy-on-write clone of b. The underlying chunks are shared
|
||||
// until they are written to.
|
||||
func (b *Buffer) Clone() Buffer {
|
||||
@@ -476,7 +482,7 @@ func (b *Buffer) Checksum(offset int) uint16 {
|
||||
// operation completes.
|
||||
func (b *Buffer) Merge(other *Buffer) {
|
||||
b.data.PushBackList(&other.data)
|
||||
other.data = viewList{}
|
||||
other.data = ViewList{}
|
||||
|
||||
// Adjust sizes.
|
||||
b.size += other.size
|
||||
|
||||
+1
-1
@@ -48,7 +48,7 @@ var viewPool = sync.Pool{
|
||||
//
|
||||
// +stateify savable
|
||||
type View struct {
|
||||
viewEntry `state:"nosave"`
|
||||
ViewEntry `state:"nosave"`
|
||||
read int
|
||||
write int
|
||||
chunk *chunk
|
||||
|
||||
@@ -642,8 +642,16 @@ func (e *endpoint) sendBatch(batchFDInfo fdInfo, pkts []*stack.PacketBuffer) (in
|
||||
vnetHdrBuf = vnetHdr.marshal()
|
||||
}
|
||||
|
||||
views := pkt.AsSlices()
|
||||
numIovecs := len(views)
|
||||
views, offset := pkt.AsViewList()
|
||||
var skipped int
|
||||
var view *buffer.View
|
||||
for view = views.Front(); view != nil && offset >= view.Size(); view = view.Next() {
|
||||
offset -= view.Size()
|
||||
skipped++
|
||||
}
|
||||
|
||||
// We've made it to the usable views.
|
||||
numIovecs := views.Len() - skipped
|
||||
if len(vnetHdrBuf) != 0 {
|
||||
numIovecs++
|
||||
}
|
||||
@@ -665,8 +673,10 @@ func (e *endpoint) sendBatch(batchFDInfo fdInfo, pkts []*stack.PacketBuffer) (in
|
||||
// they will escape this loop iteration via mmsgHdrs.
|
||||
iovecs := make([]unix.Iovec, 0, numIovecs)
|
||||
iovecs = rawfile.AppendIovecFromBytes(iovecs, vnetHdrBuf, numIovecs)
|
||||
for _, v := range views {
|
||||
iovecs = rawfile.AppendIovecFromBytes(iovecs, v, numIovecs)
|
||||
// At most one slice has a non-zero offset.
|
||||
iovecs = rawfile.AppendIovecFromBytes(iovecs, view.AsSlice()[offset:], numIovecs)
|
||||
for view = view.Next(); view != nil; view = view.Next() {
|
||||
iovecs = rawfile.AppendIovecFromBytes(iovecs, view.AsSlice(), numIovecs)
|
||||
}
|
||||
|
||||
var mmsgHdr rawfile.MMsgHdr
|
||||
|
||||
@@ -276,6 +276,9 @@ func (pk *PacketBuffer) Data() PacketData {
|
||||
}
|
||||
|
||||
// AsSlices returns the underlying storage of the whole packet.
|
||||
//
|
||||
// Note that AsSlices can allocate a lot. In hot paths it may be preferable to
|
||||
// iterate over a PacketBuffer's data via AsViewList.
|
||||
func (pk *PacketBuffer) AsSlices() [][]byte {
|
||||
var views [][]byte
|
||||
offset := pk.headerOffset()
|
||||
@@ -285,6 +288,12 @@ func (pk *PacketBuffer) AsSlices() [][]byte {
|
||||
return views
|
||||
}
|
||||
|
||||
// AsViewList returns the list of Views backing the PacketBuffer along with the
|
||||
// header offset into them. Users may not save or modify the ViewList returned.
|
||||
func (pk *PacketBuffer) AsViewList() (buffer.ViewList, int) {
|
||||
return pk.buf.AsViewList(), pk.headerOffset()
|
||||
}
|
||||
|
||||
// ToBuffer returns a caller-owned copy of the underlying storage of the whole
|
||||
// packet.
|
||||
func (pk *PacketBuffer) ToBuffer() buffer.Buffer {
|
||||
|
||||
Reference in New Issue
Block a user