netstack: speed up merge

Merge clears the other buffer, so rather than cloning and dealing with
refcounts, we can just steal other's view list and adjust sizes.

This increases the speed of Merge 10x, and this was with a benchmark that
didn't do any TrimFront/Truncate (which will induce copying in the old
implementation).

BenchmarkMerge
BenchmarkMerge-33               99412884                12.74 ns/op            0 B/op          0 allocs/op
BenchmarkOldMerge
BenchmarkOldMerge-33             6075222               217.4 ns/op             0 B/op          0 allocs/op

This change uncovered that PacketBuffer.DeepCopyForForwarding wasn't doing a
true deep copy. It seems that, in the ICMP error path, a call to Merge was
forcing a deep copy (maybe because Append was copying bytes), obfuscating the
issue. This change also addresses that issue by having DeepCopyForForwarding
produce a copy that shares no data with other packets.

PiperOrigin-RevId: 537143838
This commit is contained in:
Kevin Krakauer
2023-06-01 15:25:28 -07:00
committed by gVisor bot
parent cb0481301f
commit 9510e0939a
2 changed files with 16 additions and 6 deletions
+13 -5
View File
@@ -414,6 +414,16 @@ func (b *Buffer) Clone() Buffer {
return other
}
// DeepClone creates a deep clone of b, copying data such that no bytes are
// shared with any other Buffers.
func (b *Buffer) DeepClone() Buffer {
newBuf := Buffer{}
buf := b.Clone()
reader := buf.AsBufferReader()
newBuf.WriteFromReader(&reader, b.size)
return newBuf
}
// Apply applies the given function across all valid data.
func (b *Buffer) Apply(fn func(*View)) {
for v := b.data.Front(); v != nil; v = v.Next() {
@@ -468,13 +478,11 @@ func (b *Buffer) Checksum(offset int) uint16 {
// The other Buffer will be appended to v, and other will be empty after this
// operation completes.
func (b *Buffer) Merge(other *Buffer) {
// Copy over all buffers.
for v := other.data.Front(); v != nil; v = other.data.Front() {
b.Append(v.Clone())
other.removeView(v)
}
b.data.PushBackList(&other.data)
other.data = viewList{}
// Adjust sizes.
b.size += other.size
other.size = 0
}
+3 -1
View File
@@ -433,9 +433,11 @@ func (pk PacketBufferPtr) CloneToInbound() PacketBufferPtr {
// The returned packet buffer will have the network and transport headers
// set if the original packet buffer did.
func (pk PacketBufferPtr) DeepCopyForForwarding(reservedHeaderBytes int) PacketBufferPtr {
payload := BufferSince(pk.NetworkHeader())
defer payload.Release()
newPk := NewPacketBuffer(PacketBufferOptions{
ReserveHeaderBytes: reservedHeaderBytes,
Payload: BufferSince(pk.NetworkHeader()),
Payload: payload.DeepClone(),
IsForwardedPacket: true,
})