mirror of
https://github.com/soypat/lneto.git
synced 2026-09-08 07:49:05 +00:00
Reduce heap allocs 2 (#46)
* reduce heap allocations in tcp logging; omit use of AppendFloat which allocates a metric sh*tton * debugheaplog: better heap statistic logging * heap: use string for pcap.Frame.Protocol * add potential to eliminate Flags.String heap alloc, remove incorrect HEAP comments * add StackAsync.DebugErr and httpraw.SetBytes * many heap alloc reductions and replacement of bytes.Equal with internal.BytesEqual
This commit is contained in:
+18
-22
@@ -4,7 +4,6 @@ import (
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"net/netip"
|
||||
"slices"
|
||||
@@ -12,8 +11,8 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
_ "time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/soypat/lneto"
|
||||
"github.com/soypat/lneto/ethernet"
|
||||
"github.com/soypat/lneto/ntp"
|
||||
"github.com/soypat/lneto/tcp"
|
||||
@@ -38,6 +37,7 @@ type Formatter struct {
|
||||
// FormatFrames appends the formatted frame data to the destination buffer according the Formatter state.
|
||||
// Is equivalent to [Formatter.FormatFrame] called on each Frame with the FrameSep inserted between frames.
|
||||
func (f *Formatter) FormatFrames(dst []byte, frms []Frame, pkt []byte) (_ []byte, err error) {
|
||||
debuglog("pcap:fmt:start")
|
||||
sep := f.frameSep()
|
||||
for ifrm := range frms {
|
||||
if ifrm != 0 {
|
||||
@@ -48,14 +48,16 @@ func (f *Formatter) FormatFrames(dst []byte, frms []Frame, pkt []byte) (_ []byte
|
||||
return dst, err
|
||||
}
|
||||
}
|
||||
debuglog("pcap:fmt:done")
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
// FormatFrame formats a single frame's protocol, fields, and errors into dst.
|
||||
func (f *Formatter) FormatFrame(dst []byte, frm Frame, pkt []byte) (_ []byte, err error) {
|
||||
debuglog("pcap:fmtframe:start")
|
||||
sep := f.fieldSep()
|
||||
bitlen := frm.LenBits()
|
||||
dst = appendProtocol(dst, frm.Protocol)
|
||||
dst = append(dst, frm.Protocol...)
|
||||
if bitlen%8 == 0 {
|
||||
dst = append(dst, " len="...)
|
||||
dst = strconv.AppendInt(dst, int64(bitlen/8), 10)
|
||||
@@ -70,7 +72,7 @@ func (f *Formatter) FormatFrame(dst []byte, frm Frame, pkt []byte) (_ []byte, er
|
||||
continue
|
||||
}
|
||||
dst = append(dst, sep...)
|
||||
if field.Class == FieldClassFlags && frm.Protocol == lneto.IPProtoTCP {
|
||||
if field.Class == FieldClassFlags && frm.Protocol == "TCP" {
|
||||
// TCP flags pretty print special case.
|
||||
dst = append(dst, "flags="...)
|
||||
v, err := f.fieldAsUint(pkt, frm.PacketBitOffset+field.FrameBitOffset, field.BitLength, field.Flags.IsRightAligned())
|
||||
@@ -95,6 +97,7 @@ func (f *Formatter) FormatFrame(dst []byte, frm Frame, pkt []byte) (_ []byte, er
|
||||
}
|
||||
dst = append(dst, ')')
|
||||
}
|
||||
debuglog("pcap:fmtframe:done")
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
@@ -135,6 +138,9 @@ func (f *Formatter) formatField(dst []byte, pktStartOff int, field FrameField, p
|
||||
if hasSpaces {
|
||||
dst = append(dst, ')')
|
||||
}
|
||||
if field.BitLength == 0 {
|
||||
return dst, nil
|
||||
}
|
||||
dst = append(dst, '=')
|
||||
f.mubuf.Lock()
|
||||
defer f.mubuf.Unlock()
|
||||
@@ -142,6 +148,7 @@ func (f *Formatter) formatField(dst []byte, pktStartOff int, field FrameField, p
|
||||
if err != nil {
|
||||
return dst, err
|
||||
}
|
||||
debuglog("pcap:fmtfield:append-done")
|
||||
fieldBitStart := pktStartOff + field.FrameBitOffset
|
||||
switch field.Class {
|
||||
default:
|
||||
@@ -151,6 +158,7 @@ func (f *Formatter) formatField(dst []byte, pktStartOff int, field FrameField, p
|
||||
dst = append(dst, "0x"...)
|
||||
dst = hex.AppendEncode(dst, f.buf)
|
||||
case FieldClassTimestamp:
|
||||
debuglog("pcap:fmtfield:timestamp")
|
||||
// inspired by [time.RFC3339]
|
||||
const littlerfc3339 = "2006-01-02T15:04:05.9999"
|
||||
if len(f.buf) != 8 {
|
||||
@@ -158,8 +166,13 @@ func (f *Formatter) formatField(dst []byte, pktStartOff int, field FrameField, p
|
||||
}
|
||||
ts := ntp.TimestampFromUint64(binary.BigEndian.Uint64(f.buf))
|
||||
dst = ts.Time().AppendFormat(dst, littlerfc3339)
|
||||
debuglog("pcap:fmtfield:timestamp-done")
|
||||
case FieldClassText:
|
||||
dst = strconv.AppendQuote(dst, string(f.buf))
|
||||
debuglog("pcap:fmtfield:text")
|
||||
if len(f.buf) > 0 {
|
||||
dst = strconv.AppendQuote(dst, unsafe.String(&f.buf[0], len(f.buf)))
|
||||
}
|
||||
debuglog("pcap:fmtfield:text-done")
|
||||
case FieldClassDst, FieldClassSrc, FieldClassSize, FieldClassAddress, FieldClassOperation:
|
||||
// IP, MAC addresses and ports.
|
||||
if field.BitLength <= 16 {
|
||||
@@ -219,20 +232,3 @@ func (f *Formatter) fieldAsUint(pkt []byte, fieldBitStart, bitlen int, rightAlig
|
||||
}
|
||||
return binary.BigEndian.Uint64(f.uintBuf[:]), nil
|
||||
}
|
||||
|
||||
// appendProtocol appends the string representation of a Frame.Protocol value
|
||||
// to dst without going through fmt.Appendf reflect machinery.
|
||||
func appendProtocol(dst []byte, p any) []byte {
|
||||
switch p := p.(type) {
|
||||
case proto:
|
||||
return append(dst, string(p)...)
|
||||
case string:
|
||||
return append(dst, p...)
|
||||
case ethernet.Type:
|
||||
return append(dst, p.String()...)
|
||||
case lneto.IPProto:
|
||||
return append(dst, p.String()...)
|
||||
default:
|
||||
return fmt.Appendf(dst, "%v", p)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user