mirror of
https://github.com/soypat/lneto.git
synced 2026-07-26 10:38:47 +00:00
testing.B.Loop() standardization and StackAsync.Debug improvement (#156)
* testing.B.Loop() standardization and StackAsync.Debug heap debugging improvement * apply @MDr164 fixes * @MDr164 great suggestions to prevent panic and print correct mallocs
This commit is contained in:
@@ -124,7 +124,7 @@ func BenchmarkParseBytes(b *testing.B) {
|
|||||||
var hdr Header
|
var hdr Header
|
||||||
b.StartTimer()
|
b.StartTimer()
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for b.Loop() {
|
||||||
err := hdr.ParseBytes(asRequest, data)
|
err := hdr.ParseBytes(asRequest, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
|
|||||||
+29
-14
@@ -2,16 +2,16 @@ package internal
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"unsafe"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
LevelTrace slog.Level = slog.LevelDebug - 2
|
LevelTrace slog.Level = slog.LevelDebug - 2
|
||||||
|
|
||||||
usePrintLogAllocs = true
|
usePrintLogAllocs = HeapAllocDebugging
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -19,9 +19,13 @@ var (
|
|||||||
lastAllocs uint64
|
lastAllocs uint64
|
||||||
lastMallocs uint64
|
lastMallocs uint64
|
||||||
allocmu sync.Mutex
|
allocmu sync.Mutex
|
||||||
allocbuf [256]byte
|
allocbuf [128]byte
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func LogAttrsAndAllocs(allocmsg string, l *slog.Logger, level slog.Level, msg string, attrs ...slog.Attr) {
|
||||||
|
logAttrsAndAllocs(allocmsg, l, level, msg, attrs...)
|
||||||
|
}
|
||||||
|
|
||||||
func LogAllocs(msg string) {
|
func LogAllocs(msg string) {
|
||||||
allocmu.Lock()
|
allocmu.Lock()
|
||||||
runtime.ReadMemStats(&memstats)
|
runtime.ReadMemStats(&memstats)
|
||||||
@@ -29,23 +33,34 @@ func LogAllocs(msg string) {
|
|||||||
allocmu.Unlock()
|
allocmu.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
inc := int64(memstats.TotalAlloc) - int64(lastAllocs)
|
||||||
|
numAlloc := int64(memstats.Mallocs) - int64(lastMallocs)
|
||||||
|
free := memstats.HeapSys - memstats.HeapInuse
|
||||||
if usePrintLogAllocs {
|
if usePrintLogAllocs {
|
||||||
|
// Branch used when debugheaplog enabled
|
||||||
print("[ALLOC] ", msg)
|
print("[ALLOC] ", msg)
|
||||||
print(" inc=", int64(memstats.TotalAlloc)-int64(lastAllocs))
|
print(" inc=", inc)
|
||||||
print(" n=", int64(memstats.Mallocs)-int64(lastMallocs))
|
print(" n=", numAlloc)
|
||||||
print(" heap=", memstats.HeapAlloc)
|
print(" heap=", memstats.HeapAlloc)
|
||||||
print(" free=", memstats.HeapSys-memstats.HeapInuse)
|
print(" free=", free)
|
||||||
print(" tot=", memstats.TotalAlloc)
|
print(" tot=", memstats.TotalAlloc)
|
||||||
println()
|
println()
|
||||||
} else {
|
} else {
|
||||||
n := copy(allocbuf[:], "[ALLOC] ")
|
buf := allocbuf[:len(allocbuf)-1] // keep one character for newline.
|
||||||
n += copy(allocbuf[n:], msg)
|
n := copy(buf[:], "[ALLOC] ")
|
||||||
n += copyValueInt(allocbuf[n:], "inc", int64(memstats.TotalAlloc)-int64(lastAllocs))
|
n += copy(buf[n:], msg)
|
||||||
n += copyValueInt(allocbuf[n:], "n", int64(memstats.Mallocs)-int64(lastMallocs))
|
n += copyValueInt(buf[n:], "inc", inc)
|
||||||
n += copyValueUint(allocbuf[n:], "heap", memstats.HeapAlloc)
|
n += copyValueInt(buf[n:], "n", numAlloc)
|
||||||
n += copyValueUint(allocbuf[n:], "free", memstats.HeapSys-memstats.HeapInuse)
|
n += copyValueUint(buf[n:], "heap", memstats.HeapAlloc)
|
||||||
n += copyValueUint(allocbuf[n:], "tot", memstats.TotalAlloc)
|
n += copyValueUint(buf[n:], "free", free)
|
||||||
println(unsafe.String(&allocbuf[0], n))
|
lastN := copyValueUint(buf[n:], "tot", memstats.TotalAlloc)
|
||||||
|
n += lastN
|
||||||
|
allocbuf[n] = '\n' // n will never be larger than len(allocbuf)-1
|
||||||
|
os.Stdout.Write(allocbuf[:n+1])
|
||||||
|
if lastN == 0 {
|
||||||
|
n2 := copy(allocbuf[:], "[WARN] ALLOC BUF OVERRUN\n")
|
||||||
|
os.Stdout.Write(allocbuf[:n2])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
lastAllocs = memstats.TotalAlloc
|
lastAllocs = memstats.TotalAlloc
|
||||||
lastMallocs = memstats.Mallocs
|
lastMallocs = memstats.Mallocs
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ package internal
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"runtime"
|
|
||||||
"time"
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
@@ -22,10 +21,13 @@ func LogEnabled(l *slog.Logger, lvl slog.Level) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func logAttrsAndAllocs(allocmsg string, l *slog.Logger, level slog.Level, msg string, attrs ...slog.Attr) {
|
||||||
|
LogAttrs(nil, level, msg, attrs...) // already logs attributes
|
||||||
|
}
|
||||||
|
|
||||||
func LogAttrs(_ *slog.Logger, level slog.Level, msg string, attrs ...slog.Attr) {
|
func LogAttrs(_ *slog.Logger, level slog.Level, msg string, attrs ...slog.Attr) {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
n := len(now.AppendFormat(timebuf[:0], timefmt))
|
n := len(now.AppendFormat(timebuf[:0], timefmt))
|
||||||
LogAllocs(msg)
|
|
||||||
print("time=", unsafe.String(&timebuf[0], n), " ")
|
print("time=", unsafe.String(&timebuf[0], n), " ")
|
||||||
if level == LevelTrace {
|
if level == LevelTrace {
|
||||||
print("TRACE ")
|
print("TRACE ")
|
||||||
@@ -35,7 +37,6 @@ func LogAttrs(_ *slog.Logger, level slog.Level, msg string, attrs ...slog.Attr)
|
|||||||
print(level.String(), " ")
|
print(level.String(), " ")
|
||||||
}
|
}
|
||||||
print(msg)
|
print(msg)
|
||||||
|
|
||||||
for _, a := range attrs {
|
for _, a := range attrs {
|
||||||
switch a.Value.Kind() {
|
switch a.Value.Kind() {
|
||||||
case slog.KindString:
|
case slog.KindString:
|
||||||
@@ -49,12 +50,5 @@ func LogAttrs(_ *slog.Logger, level slog.Level, msg string, attrs ...slog.Attr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
println()
|
println()
|
||||||
allocmu.Lock()
|
LogAllocs(msg)
|
||||||
runtime.ReadMemStats(&memstats)
|
|
||||||
if lastAllocs != memstats.TotalAlloc {
|
|
||||||
print("alloc increase in heaplog")
|
|
||||||
}
|
|
||||||
lastAllocs = memstats.TotalAlloc
|
|
||||||
lastMallocs = memstats.Mallocs
|
|
||||||
allocmu.Unlock()
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,3 +21,9 @@ func LogAttrs(l *slog.Logger, level slog.Level, msg string, attrs ...slog.Attr)
|
|||||||
l.LogAttrs(context.Background(), level, msg, attrs...)
|
l.LogAttrs(context.Background(), level, msg, attrs...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func logAttrsAndAllocs(allocmsg string, l *slog.Logger, level slog.Level, msg string, attrs ...slog.Attr) {
|
||||||
|
LogAllocs(allocmsg)
|
||||||
|
LogAttrs(l, level, msg, attrs...)
|
||||||
|
LogAllocs(msg) // Should not log again unless LogAttrs allocated.
|
||||||
|
}
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ func BenchmarkPcap(b *testing.B) {
|
|||||||
var frames []Frame
|
var frames []Frame
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for b.Loop() {
|
||||||
frames, _ = pb.CaptureEthernet(frames[:0], tc.pkt, 0)
|
frames, _ = pb.CaptureEthernet(frames[:0], tc.pkt, 0)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -148,7 +148,7 @@ func BenchmarkPcap(b *testing.B) {
|
|||||||
var buf []byte
|
var buf []byte
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for b.Loop() {
|
||||||
buf, _ = f.FormatFrames(buf[:0], frames, tc.pkt)
|
buf, _ = f.FormatFrames(buf[:0], frames, tc.pkt)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -161,7 +161,7 @@ func BenchmarkPcap(b *testing.B) {
|
|||||||
var buf []byte
|
var buf []byte
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for b.Loop() {
|
||||||
frames, _ = pb.CaptureEthernet(frames[:0], tc.pkt, 0)
|
frames, _ = pb.CaptureEthernet(frames[:0], tc.pkt, 0)
|
||||||
buf, _ = f.FormatFrames(buf[:0], frames, tc.pkt)
|
buf, _ = f.FormatFrames(buf[:0], frames, tc.pkt)
|
||||||
}
|
}
|
||||||
@@ -193,7 +193,7 @@ func BenchmarkPcapPhases(b *testing.B) {
|
|||||||
var buf []byte
|
var buf []byte
|
||||||
var decNs, fmtNs int64
|
var decNs, fmtNs int64
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for b.Loop() {
|
||||||
t0 := time.Now()
|
t0 := time.Now()
|
||||||
frames, _ = pb.CaptureEthernet(frames[:0], tc.pkt, 0)
|
frames, _ = pb.CaptureEthernet(frames[:0], tc.pkt, 0)
|
||||||
t1 := time.Now()
|
t1 := time.Now()
|
||||||
|
|||||||
@@ -227,7 +227,7 @@ func BenchmarkSYNCookie_Generate(b *testing.B) {
|
|||||||
clientISN := Value(0x12345678)
|
clientISN := Value(0x12345678)
|
||||||
|
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for b.Loop() {
|
||||||
sc.MakeSYNCookie(srcAddr, dstAddr, srcPort, dstPort, clientISN)
|
sc.MakeSYNCookie(srcAddr, dstAddr, srcPort, dstPort, clientISN)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -247,7 +247,7 @@ func BenchmarkSYNCookie_Validate(b *testing.B) {
|
|||||||
ackNum := cookie + 1
|
ackNum := cookie + 1
|
||||||
|
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for b.Loop() {
|
||||||
sc.ValidateSYNCookie(srcAddr, dstAddr, srcPort, dstPort, clientISN, ackNum)
|
sc.ValidateSYNCookie(srcAddr, dstAddr, srcPort, dstPort, clientISN, ackNum)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-10
@@ -842,24 +842,18 @@ func addr4(addr [4]byte, ok bool) netip.Addr {
|
|||||||
return netip.AddrFrom4(addr)
|
return netip.AddrFrom4(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debug prints debugging information. Very useful for users when coupled with
|
// Debug prints debugging and heap information.
|
||||||
// the debugheaplog build tag. See [internal.LogAttrs] debugheaplog version.
|
|
||||||
//
|
|
||||||
// go build -tags=debugheaplog ./yourprogram
|
|
||||||
func (s *StackAsync) Debug(msg string) {
|
func (s *StackAsync) Debug(msg string) {
|
||||||
internal.LogAttrs(slog.Default(), slog.LevelDebug, "stackasync",
|
internal.LogAttrsAndAllocs(msg, slog.Default(), slog.LevelDebug, "stackasync",
|
||||||
slog.String("umsg", msg),
|
slog.String("umsg", msg),
|
||||||
slog.Uint64("sent", s.stats.TotalSent),
|
slog.Uint64("sent", s.stats.TotalSent),
|
||||||
slog.Uint64("recv", s.stats.TotalReceived),
|
slog.Uint64("recv", s.stats.TotalReceived),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DebugErr prints debugging and error info. Very useful for users when coupled with
|
// DebugErr prints debugging and heap information.
|
||||||
// the debugheaplog build tag. See [internal.LogAttrs] debugheaplog version.
|
|
||||||
//
|
|
||||||
// go build -tags=debugheaplog ./yourprogram
|
|
||||||
func (s *StackAsync) DebugErr(msg, err string) {
|
func (s *StackAsync) DebugErr(msg, err string) {
|
||||||
internal.LogAttrs(slog.Default(), slog.LevelError, "stackasync",
|
internal.LogAttrsAndAllocs(msg, slog.Default(), slog.LevelError, "stackasync",
|
||||||
slog.String("umsg", msg),
|
slog.String("umsg", msg),
|
||||||
slog.String("err", err),
|
slog.String("err", err),
|
||||||
slog.Uint64("sent", s.stats.TotalSent),
|
slog.Uint64("sent", s.stats.TotalSent),
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ func BenchmarkARPExchange(b *testing.B) {
|
|||||||
var buf [frameSize]byte
|
var buf [frameSize]byte
|
||||||
|
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for b.Loop() {
|
||||||
err = c1.StartResolveHardwareAddress6(queryAddr)
|
err = c1.StartResolveHardwareAddress6(queryAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
@@ -130,7 +130,7 @@ func BenchmarkTCPHandshake(b *testing.B) {
|
|||||||
var pktbuf [frameSize]byte
|
var pktbuf [frameSize]byte
|
||||||
|
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for b.Loop() {
|
||||||
// Setup connections.
|
// Setup connections.
|
||||||
err = sv.ListenTCP4(svconn, svPort)
|
err = sv.ListenTCP4(svconn, svPort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -2,7 +2,11 @@
|
|||||||
|
|
||||||
package xnet
|
package xnet
|
||||||
|
|
||||||
import "os"
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/soypat/lneto/internal"
|
||||||
|
)
|
||||||
|
|
||||||
var _pcap CapturePrinter
|
var _pcap CapturePrinter
|
||||||
|
|
||||||
@@ -14,4 +18,7 @@ func init() {
|
|||||||
|
|
||||||
func debugPacket(msg string, b []byte) {
|
func debugPacket(msg string, b []byte) {
|
||||||
_pcap.PrintEthernet(msg, b)
|
_pcap.PrintEthernet(msg, b)
|
||||||
|
if internal.HeapAllocDebugging {
|
||||||
|
internal.LogAllocs(msg)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestTinyGoTest(t *testing.T) {
|
func TestTinyGoTest(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("`tinygo test` skipped on short test")
|
||||||
|
}
|
||||||
if exec.Command("tinygo", "version").Run() != nil {
|
if exec.Command("tinygo", "version").Run() != nil {
|
||||||
t.Skip("tinygo not installed")
|
t.Skip("tinygo not installed")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user