2024-01-03 11:59:45 -06:00
|
|
|
package debugger
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2024-01-18 01:34:32 -06:00
|
|
|
"fmt"
|
2024-01-18 22:36:35 -06:00
|
|
|
|
2024-01-03 11:59:45 -06:00
|
|
|
// "os"
|
|
|
|
"runtime"
|
|
|
|
"runtime/debug"
|
|
|
|
"runtime/pprof"
|
|
|
|
|
2024-01-18 22:36:35 -06:00
|
|
|
"go.wit.com/gui"
|
2024-01-18 01:34:32 -06:00
|
|
|
"go.wit.com/lib/gadgets"
|
|
|
|
"go.wit.com/log"
|
2024-01-03 11:59:45 -06:00
|
|
|
)
|
|
|
|
|
2024-01-04 23:28:55 -06:00
|
|
|
func DebugGolangWindow(p *gui.Node) *gadgets.BasicWindow {
|
|
|
|
var w *gadgets.BasicWindow
|
|
|
|
var g, og, outputTextbox *gui.Node
|
2024-01-03 11:59:45 -06:00
|
|
|
|
2024-01-04 23:28:55 -06:00
|
|
|
w = gadgets.NewBasicWindow(p, "GO")
|
2024-01-05 16:56:03 -06:00
|
|
|
w.Draw()
|
2024-01-04 23:28:55 -06:00
|
|
|
g = w.Box().NewGroup("Language Internals").Pad()
|
2024-01-03 11:59:45 -06:00
|
|
|
|
2024-01-18 01:34:32 -06:00
|
|
|
g.NewButton("ReadModuleInfo()", func() {
|
2024-01-03 11:59:45 -06:00
|
|
|
tmp, _ := debug.ReadBuildInfo()
|
|
|
|
outputTextbox.SetText(tmp.String())
|
|
|
|
})
|
2024-01-18 01:34:32 -06:00
|
|
|
g.NewButton("runtime.NumGoroutine()", func() {
|
2024-01-03 11:59:45 -06:00
|
|
|
buf := new(bytes.Buffer)
|
|
|
|
pprof.Lookup("goroutine").WriteTo(buf, 1)
|
|
|
|
outputTextbox.SetText(buf.String())
|
|
|
|
|
|
|
|
outputTextbox.AppendText(fmt.Sprintln("runtime.NumGoroutine() = ", runtime.NumGoroutine()))
|
|
|
|
})
|
2024-01-18 01:34:32 -06:00
|
|
|
g.NewButton("pprof.Lookup(heap)", func() {
|
2024-01-03 11:59:45 -06:00
|
|
|
buf := new(bytes.Buffer)
|
|
|
|
pprof.Lookup("heap").WriteTo(buf, 1)
|
|
|
|
outputTextbox.SetText(buf.String())
|
|
|
|
})
|
2024-01-18 01:34:32 -06:00
|
|
|
g.NewButton("debug.PrintStack(current)", func() {
|
2024-01-03 11:59:45 -06:00
|
|
|
outputTextbox.SetText(string(debug.Stack()))
|
|
|
|
})
|
2024-01-18 01:34:32 -06:00
|
|
|
g.NewButton("pprof.Lookup(goroutine)", func() {
|
2024-01-03 11:59:45 -06:00
|
|
|
buf := new(bytes.Buffer)
|
|
|
|
pprof.Lookup("goroutine").WriteTo(buf, 1)
|
|
|
|
outputTextbox.SetText(buf.String())
|
|
|
|
})
|
2024-01-18 01:34:32 -06:00
|
|
|
g.NewButton("pprof.Lookup(block)", func() {
|
2024-01-03 11:59:45 -06:00
|
|
|
buf := new(bytes.Buffer)
|
|
|
|
pprof.Lookup("block").WriteTo(buf, 1)
|
|
|
|
outputTextbox.SetText(buf.String())
|
|
|
|
})
|
2024-01-18 01:34:32 -06:00
|
|
|
g.NewButton("pprof.Lookup threadcreate", func() {
|
2024-01-03 11:59:45 -06:00
|
|
|
buf := new(bytes.Buffer)
|
|
|
|
pprof.Lookup("threadcreate").WriteTo(buf, 1)
|
|
|
|
outputTextbox.SetText(buf.String())
|
|
|
|
})
|
|
|
|
|
2024-01-18 01:34:32 -06:00
|
|
|
g.NewButton("runtime.ReadMemStats()", func() {
|
2024-01-03 11:59:45 -06:00
|
|
|
outputTextbox.SetText(runtimeReadMemStats())
|
|
|
|
})
|
|
|
|
|
2024-01-18 01:34:32 -06:00
|
|
|
g.NewButton("debug.FreeOSMemory()", func() {
|
2024-01-03 11:59:45 -06:00
|
|
|
var out string = "Before debug.FreeOSMemory():\n\n"
|
|
|
|
out += runtimeReadMemStats()
|
|
|
|
debug.FreeOSMemory()
|
|
|
|
out += "\n\nAfter debug.FreeOSMemory():\n\n"
|
|
|
|
out += runtimeReadMemStats()
|
|
|
|
outputTextbox.SetText(out)
|
|
|
|
})
|
|
|
|
|
2024-01-18 01:34:32 -06:00
|
|
|
g.NewButton("debug.ReadGCStats()", func() {
|
2024-01-03 11:59:45 -06:00
|
|
|
var tmp debug.GCStats
|
|
|
|
var out string
|
|
|
|
debug.ReadGCStats(&tmp)
|
2024-01-08 22:33:18 -06:00
|
|
|
log.Log(INFO, tmp)
|
2024-01-03 11:59:45 -06:00
|
|
|
out += fmt.Sprintln("LastGC:", tmp.LastGC, "// time.Time time of last collection")
|
|
|
|
out += fmt.Sprintln("NumGC:", tmp.NumGC, "// number of garbage collections")
|
|
|
|
out += fmt.Sprintln("PauseTotal:", tmp.PauseTotal, "// total pause for all collections")
|
|
|
|
out += fmt.Sprintln("Pause:", tmp.Pause, "// []time.Duration pause history, most recent first")
|
|
|
|
out += fmt.Sprintln("PauseEnd:", tmp.Pause, "// []time.Time pause history, most recent first")
|
|
|
|
out += fmt.Sprintln("PauseQuantiles:", tmp.PauseQuantiles, "// []time.Duration")
|
|
|
|
outputTextbox.SetText(out)
|
|
|
|
})
|
|
|
|
|
2024-01-18 01:34:32 -06:00
|
|
|
g.NewButton("debug.SetTraceback('all')", func() {
|
2024-01-03 11:59:45 -06:00
|
|
|
debug.SetTraceback("all")
|
|
|
|
})
|
|
|
|
|
2024-01-18 01:34:32 -06:00
|
|
|
g.NewButton("panic()", func() {
|
2024-01-03 11:59:45 -06:00
|
|
|
panic("test")
|
|
|
|
})
|
|
|
|
|
2024-01-04 23:28:55 -06:00
|
|
|
g = w.Box().NewGroup("TODO: finish these").Pad()
|
2024-01-03 11:59:45 -06:00
|
|
|
|
|
|
|
// g.NewLabel("TODO:")
|
|
|
|
|
2024-01-18 01:34:32 -06:00
|
|
|
g.NewButton("runtime.Stack(true)", func() {
|
2024-01-03 11:59:45 -06:00
|
|
|
// TODO: https://stackoverflow.com/questions/61127053/how-to-list-all-the-running-goroutines-in-a-go-program
|
|
|
|
// func Stack(buf []byte, all bool) int
|
|
|
|
})
|
|
|
|
|
2024-01-18 01:34:32 -06:00
|
|
|
g.NewButton("debug.SetMemoryLimit(int)", func() {
|
2024-01-03 11:59:45 -06:00
|
|
|
// TODO:
|
|
|
|
//debug.SetMemoryLimit(1024 * 1024 * 100)
|
|
|
|
})
|
|
|
|
|
2024-01-18 01:34:32 -06:00
|
|
|
g.NewButton("debug.SetMaxStack(int bytes)", func() {
|
2024-01-03 11:59:45 -06:00
|
|
|
// default is apparently 1GB
|
|
|
|
})
|
|
|
|
|
2024-01-18 01:34:32 -06:00
|
|
|
g.NewButton("debug.SetMaxThreads(int)", func() {
|
2024-01-03 11:59:45 -06:00
|
|
|
// default is apparently 10,000
|
|
|
|
})
|
|
|
|
|
2024-01-18 01:34:32 -06:00
|
|
|
g.NewButton("debug.SetTraceback('all')", func() {
|
2024-01-03 11:59:45 -06:00
|
|
|
debug.SetTraceback("all")
|
|
|
|
})
|
|
|
|
|
|
|
|
// deprecated (probably) by String() implementation within golang
|
2024-01-18 01:34:32 -06:00
|
|
|
g.NewButton("dumpModuleInfo() (deprecate)", func() {
|
2024-01-03 11:59:45 -06:00
|
|
|
outputTextbox.SetText(dumpModuleInfo())
|
|
|
|
})
|
|
|
|
|
2024-01-04 23:28:55 -06:00
|
|
|
og = w.Box().NewGroup("output").Pad()
|
2024-01-03 11:59:45 -06:00
|
|
|
outputTextbox = og.NewTextbox("outputBox")
|
2024-01-18 01:34:32 -06:00
|
|
|
outputTextbox.Custom = func() {
|
2024-01-17 22:43:57 -06:00
|
|
|
log.Log(INFO, "custom TextBox() for golang output a =", outputTextbox.String())
|
2024-01-03 11:59:45 -06:00
|
|
|
}
|
2024-01-04 23:28:55 -06:00
|
|
|
|
|
|
|
return w
|
2024-01-03 11:59:45 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func runtimeReadMemStats() string {
|
|
|
|
var s runtime.MemStats
|
|
|
|
var out string
|
|
|
|
runtime.ReadMemStats(&s)
|
|
|
|
out += fmt.Sprintln("alloc:", s.Alloc, "bytes")
|
|
|
|
out += fmt.Sprintln("total-alloc:", s.TotalAlloc, "bytes")
|
|
|
|
out += fmt.Sprintln("sys:", s.Sys, "bytes")
|
|
|
|
out += fmt.Sprintln("lookups:", s.Lookups)
|
|
|
|
out += fmt.Sprintln("mallocs:", s.Mallocs)
|
|
|
|
out += fmt.Sprintln("frees:", s.Frees)
|
|
|
|
out += fmt.Sprintln("heap-alloc:", s.HeapAlloc, "bytes")
|
|
|
|
out += fmt.Sprintln("heap-sys:", s.HeapSys, "bytes")
|
2024-01-18 01:34:32 -06:00
|
|
|
out += fmt.Sprintln("heap-idle:", s.HeapIdle, "bytes")
|
2024-01-03 11:59:45 -06:00
|
|
|
out += fmt.Sprintln("heap-in-use:", s.HeapInuse, "bytes")
|
|
|
|
out += fmt.Sprintln("heap-released:", s.HeapReleased, "bytes")
|
|
|
|
out += fmt.Sprintln("heap-objects:", s.HeapObjects)
|
|
|
|
out += fmt.Sprintln("stack-in-use:", s.StackInuse, "bytes")
|
|
|
|
out += fmt.Sprintln("stack-sys", s.StackSys, "bytes")
|
|
|
|
out += fmt.Sprintln("next-gc: when heap-alloc >=", s.NextGC, "bytes")
|
|
|
|
out += fmt.Sprintln("last-gc:", s.LastGC, "ns")
|
|
|
|
out += fmt.Sprintln("gc-pause:", s.PauseTotalNs, "ns")
|
|
|
|
out += fmt.Sprintln("num-gc:", s.NumGC)
|
|
|
|
out += fmt.Sprintln("enable-gc:", s.EnableGC)
|
|
|
|
out += fmt.Sprintln("debug-gc:", s.DebugGC)
|
|
|
|
return out
|
|
|
|
}
|
|
|
|
|
|
|
|
func dumpModuleInfo() string {
|
|
|
|
var out string
|
|
|
|
tmp, _ := debug.ReadBuildInfo()
|
|
|
|
if tmp == nil {
|
|
|
|
out += fmt.Sprintln("This wasn't compiled with go module support")
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
out += fmt.Sprintln("mod.Path = ", tmp.Path)
|
|
|
|
out += fmt.Sprintln("mod.Main.Path = ", tmp.Main.Path)
|
|
|
|
out += fmt.Sprintln("mod.Main.Version = ", tmp.Main.Version)
|
|
|
|
out += fmt.Sprintln("mod.Main.Sum = ", tmp.Main.Sum)
|
|
|
|
for _, value := range tmp.Deps {
|
|
|
|
out += fmt.Sprintln("\tmod.Path = ", value.Path)
|
|
|
|
out += fmt.Sprintln("\tmod.Version = ", value.Version)
|
|
|
|
}
|
|
|
|
return out
|
|
|
|
}
|