mirror of
https://github.com/soypat/lneto.git
synced 2026-07-26 10:38:47 +00:00
157a8537a2
* testing.B.Loop() standardization and StackAsync.Debug heap debugging improvement * apply @MDr164 fixes * @MDr164 great suggestions to prevent panic and print correct mallocs
104 lines
2.5 KiB
Go
104 lines
2.5 KiB
Go
package internal
|
|
|
|
import (
|
|
"log/slog"
|
|
"os"
|
|
"runtime"
|
|
"strconv"
|
|
"sync"
|
|
)
|
|
|
|
const (
|
|
LevelTrace slog.Level = slog.LevelDebug - 2
|
|
|
|
usePrintLogAllocs = HeapAllocDebugging
|
|
)
|
|
|
|
var (
|
|
memstats runtime.MemStats
|
|
lastAllocs uint64
|
|
lastMallocs uint64
|
|
allocmu sync.Mutex
|
|
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) {
|
|
allocmu.Lock()
|
|
runtime.ReadMemStats(&memstats)
|
|
if memstats.TotalAlloc == lastAllocs {
|
|
allocmu.Unlock()
|
|
return
|
|
}
|
|
inc := int64(memstats.TotalAlloc) - int64(lastAllocs)
|
|
numAlloc := int64(memstats.Mallocs) - int64(lastMallocs)
|
|
free := memstats.HeapSys - memstats.HeapInuse
|
|
if usePrintLogAllocs {
|
|
// Branch used when debugheaplog enabled
|
|
print("[ALLOC] ", msg)
|
|
print(" inc=", inc)
|
|
print(" n=", numAlloc)
|
|
print(" heap=", memstats.HeapAlloc)
|
|
print(" free=", free)
|
|
print(" tot=", memstats.TotalAlloc)
|
|
println()
|
|
} else {
|
|
buf := allocbuf[:len(allocbuf)-1] // keep one character for newline.
|
|
n := copy(buf[:], "[ALLOC] ")
|
|
n += copy(buf[n:], msg)
|
|
n += copyValueInt(buf[n:], "inc", inc)
|
|
n += copyValueInt(buf[n:], "n", numAlloc)
|
|
n += copyValueUint(buf[n:], "heap", memstats.HeapAlloc)
|
|
n += copyValueUint(buf[n:], "free", free)
|
|
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
|
|
lastMallocs = memstats.Mallocs
|
|
allocmu.Unlock()
|
|
}
|
|
|
|
func copyValueInt(buf []byte, key string, v int64) int {
|
|
// ' ' + key + '=' + up to 20 chars for int64
|
|
if len(buf) < 2+len(key)+20 {
|
|
return 0
|
|
}
|
|
buf[0] = ' '
|
|
n := 1 + copy(buf[1:], key)
|
|
buf[n] = '='
|
|
n++
|
|
return n + copyInt(buf[n:], v)
|
|
}
|
|
|
|
func copyValueUint(buf []byte, key string, v uint64) int {
|
|
if len(buf) < 2+len(key)+20 {
|
|
return 0
|
|
}
|
|
buf[0] = ' '
|
|
n := 1 + copy(buf[1:], key)
|
|
buf[n] = '='
|
|
n++
|
|
return n + copyUint(buf[n:], v)
|
|
}
|
|
|
|
// copyInt formats v into buf and returns the number of bytes written.
|
|
// Caller must ensure cap(buf) >= 20.
|
|
func copyInt(buf []byte, v int64) int {
|
|
return len(strconv.AppendInt(buf[:0], v, 10))
|
|
}
|
|
|
|
// copyUint formats v into buf and returns the number of bytes written.
|
|
// Caller must ensure cap(buf) >= 20.
|
|
func copyUint(buf []byte, v uint64) int {
|
|
return len(strconv.AppendUint(buf[:0], v, 10))
|
|
}
|