فهرست منبع

reduce copying

Jay Wren 11 ماه پیش
والد
کامیت
0f9b33aa36
2فایلهای تغییر یافته به همراه48 افزوده شده و 8 حذف شده
  1. 8 2
      interface.go
  2. 40 6
      overlay/tun_linux.go

+ 8 - 2
interface.go

@@ -297,7 +297,10 @@ func (f *Interface) listenIn(reader io.ReadWriteCloser, i int) {
 
 func (f *Interface) listenInSingle(reader io.ReadWriteCloser, i int) {
 	packet := make([]byte, mtu)
-	out := make([]byte, mtu)
+	// Allocate out buffer with virtio header headroom (10 bytes) to avoid copies on write
+	const virtioNetHdrLen = 10
+	outBuf := make([]byte, virtioNetHdrLen+mtu)
+	out := outBuf[virtioNetHdrLen:] // Use slice starting after headroom
 	fwPacket := &firewall.Packet{}
 	nb := make([]byte, 12, 12)
 
@@ -321,6 +324,7 @@ func (f *Interface) listenInSingle(reader io.ReadWriteCloser, i int) {
 
 func (f *Interface) listenInBatch(reader io.ReadWriteCloser, batchReader BatchReader, i int) {
 	batchSize := batchReader.BatchSize()
+	const virtioNetHdrLen = 10
 
 	// Allocate buffers for batch reading
 	bufs := make([][]byte, batchSize)
@@ -330,7 +334,9 @@ func (f *Interface) listenInBatch(reader io.ReadWriteCloser, batchReader BatchRe
 	sizes := make([]int, batchSize)
 
 	// Per-packet state (reused across batches)
-	out := make([]byte, mtu)
+	// Allocate out buffer with virtio header headroom to avoid copies on write
+	outBuf := make([]byte, virtioNetHdrLen+mtu)
+	out := outBuf[virtioNetHdrLen:]
 	fwPacket := &firewall.Packet{}
 	nb := make([]byte, 12, 12)
 

+ 40 - 6
overlay/tun_linux.go

@@ -92,9 +92,24 @@ func (w *wgDeviceWrapper) Read(b []byte) (int, error) {
 }
 
 func (w *wgDeviceWrapper) Write(b []byte) (int, error) {
-	// Allocate buffer with space for virtio header
-	buf := make([]byte, virtioNetHdrLen+len(b))
-	copy(buf[virtioNetHdrLen:], b)
+	// Check if buffer has the expected headroom pattern to avoid copy
+	var buf []byte
+
+	if cap(b) >= len(b)+virtioNetHdrLen {
+		buf = b[:cap(b)]
+		if len(buf) == len(b)+virtioNetHdrLen {
+			// Perfect! Buffer has headroom, no copy needed
+			buf = buf[:len(b)+virtioNetHdrLen]
+		} else {
+			// Unexpected capacity, safer to copy
+			buf = make([]byte, virtioNetHdrLen+len(b))
+			copy(buf[virtioNetHdrLen:], b)
+		}
+	} else {
+		// No headroom, need to allocate and copy
+		buf = make([]byte, virtioNetHdrLen+len(b))
+		copy(buf[virtioNetHdrLen:], b)
+	}
 
 	bufs := [][]byte{buf}
 	n, err := w.dev.Write(bufs, virtioNetHdrLen)
@@ -404,9 +419,28 @@ func (t *tun) BatchSize() int {
 func (t *tun) Write(b []byte) (int, error) {
 	if t.wgDevice != nil {
 		// Use wireguard device which handles virtio headers internally
-		// Allocate buffer with space for virtio header
-		buf := make([]byte, virtioNetHdrLen+len(b))
-		copy(buf[virtioNetHdrLen:], b)
+		// Check if buffer has the expected headroom pattern:
+		// cap(b) should be len(b) + virtioNetHdrLen, indicating pre-allocated headroom
+		var buf []byte
+
+		if cap(b) >= len(b)+virtioNetHdrLen {
+			// Buffer likely has headroom - use unsafe to access it
+			// Create a slice that includes the headroom by re-slicing from capacity
+			buf = b[:cap(b)]
+			// Check if we have exactly the right amount of extra capacity
+			if len(buf) == len(b)+virtioNetHdrLen {
+				// Perfect! This buffer was allocated with headroom, no copy needed
+				buf = buf[:len(b)+virtioNetHdrLen]
+			} else {
+				// Unexpected capacity, safer to copy
+				buf = make([]byte, virtioNetHdrLen+len(b))
+				copy(buf[virtioNetHdrLen:], b)
+			}
+		} else {
+			// No headroom, need to allocate and copy
+			buf = make([]byte, virtioNetHdrLen+len(b))
+			copy(buf[virtioNetHdrLen:], b)
+		}
 
 		bufs := [][]byte{buf}
 		n, err := t.wgDevice.Write(bufs, virtioNetHdrLen)