diff --git a/debugGochan.go b/debugGochan.go new file mode 100644 index 0000000..e21dda8 --- /dev/null +++ b/debugGochan.go @@ -0,0 +1,100 @@ +// https://www.digitalocean.com/community/tutorials/how-to-run-multiple-functions-concurrently-in-go +// who came up with the idea of making community tutorials. that was a good idea! + +package debugger + +import ( + "fmt" + "sync" + + "go.wit.com/log" + "go.wit.com/gui/gui" +) + +var debugWG *sync.WaitGroup +var debugNumberChan chan int + +func DebugGoChannels(n *gui.Node) { + var w, g *gui.Node + + w = n.NewWindow("Debug GO Channels") + w.Custom = w.StandardClose + + g = w.NewGroup("Channel stuff") + + // var debugWG sync.WaitGroup + g.NewButton("init()", func () { + if (debugNumberChan == nil) { + log.Log(true, "making debugNumberChan channel") + debugNumberChan = make(chan int) + } else { + log.Log(true, "debugNumberChan already made") + } + debugWG = new(sync.WaitGroup) + }) + g.NewButton("go printInt(x) (read x values off the channel)", func () { + debugWG.Add(1) + go printInt(2, "routine1") + debugWG.Add(1) + go printInt(2, "routine2") + }) + g.NewButton("sendNumber(2) (chan <- 2, 4)", func () { + debugWG.Add(1) + debugWG.Add(1) + go sendNumber(2) + go sendNumber(4) + }) + g.NewButton("sendNumber(1) (chan <- 7)", func () { + debugWG.Add(1) + go sendNumber(7) + }) + g.NewButton("send 4 numbers (chan <- int)", func () { + log.Log(true, "generateNumbers(4)") + go generateNumbers(4) + }) + g.NewButton("debugWG.Done()", func () { + log.Log(true, "ran debugWG.Done()") + debugWG.Done() + }) + g.NewButton("close chan", func () { + log.Log(true, "close() on", debugNumberChan) + close(debugNumberChan) + }) + g.NewButton("print", func () { + log.Log(true, "waitgroup counter is ?") + }) +} +func sendNumber(i int) { + log.Log(true, "START debugNumberChan <-", i, " (sending", i, "to channel)") + debugNumberChan <- i + debugWG.Wait() + log.Log(true, "END debugNumberChan sendNumber() done", i) +} + +func generateNumbers(total int) { + fmt.Printf("START generateNumbers()\n") + for idx := 1; idx <= total; idx++ { + log.Log(true, "ran debugNumberChan <= idx where idx =", idx) + fmt.Printf("S generateNumbers() sending %d to channel\n", idx) + debugNumberChan <- idx + // res, err := (<-r)() + fmt.Printf("E generateNumbers() sending %d to channel\n", idx) + } + debugWG.Wait() + fmt.Printf("END generateNumbers()\n") +} + +// i equals the number of times to read values from the channel +func printInt(i int, name string) { + tmp := 1 + log.Log(true, "START printInt", name, "read debugNumberChan()") + for num := range debugNumberChan { + log.Log(true, "printInt()",name, "read", num, "from channel") + debugWG.Done() + if (tmp == i) { + return + } + tmp += 1 + } + fmt.Printf("END printInt()", name, "read debugNumberChan\n") +} diff --git a/debugGolang.go b/debugGolang.go new file mode 100644 index 0000000..1cddf9a --- /dev/null +++ b/debugGolang.go @@ -0,0 +1,175 @@ +package debugger + +import ( + "fmt" + "bytes" + // "os" + "runtime" + "runtime/debug" + "runtime/pprof" + + "go.wit.com/log" + "go.wit.com/gui/gui" +) + +func DebugGolangWindow(n *gui.Node) { + var newW, newB, g, og, outputTextbox *gui.Node + + newW = n.NewWindow("GO") + newW.Custom = newW.StandardClose + newB = newW.NewBox("hBox", true) + + g = newB.NewGroup("Language Internals") + + g.NewButton("ReadModuleInfo()", func () { + tmp, _ := debug.ReadBuildInfo() + outputTextbox.SetText(tmp.String()) + }) + g.NewButton("runtime.NumGoroutine()", func () { + buf := new(bytes.Buffer) + pprof.Lookup("goroutine").WriteTo(buf, 1) + outputTextbox.SetText(buf.String()) + + outputTextbox.AppendText(fmt.Sprintln("runtime.NumGoroutine() = ", runtime.NumGoroutine())) + }) + g.NewButton("pprof.Lookup(heap)", func () { + buf := new(bytes.Buffer) + pprof.Lookup("heap").WriteTo(buf, 1) + outputTextbox.SetText(buf.String()) + }) + g.NewButton("debug.PrintStack(current)", func () { + outputTextbox.SetText(string(debug.Stack())) + }) + g.NewButton("pprof.Lookup(goroutine)", func () { + buf := new(bytes.Buffer) + pprof.Lookup("goroutine").WriteTo(buf, 1) + outputTextbox.SetText(buf.String()) + }) + g.NewButton("pprof.Lookup(block)", func () { + buf := new(bytes.Buffer) + pprof.Lookup("block").WriteTo(buf, 1) + outputTextbox.SetText(buf.String()) + }) + g.NewButton("pprof.Lookup threadcreate", func () { + buf := new(bytes.Buffer) + pprof.Lookup("threadcreate").WriteTo(buf, 1) + outputTextbox.SetText(buf.String()) + }) + + g.NewButton("runtime.ReadMemStats()", func () { + outputTextbox.SetText(runtimeReadMemStats()) + }) + + g.NewButton("debug.FreeOSMemory()", func () { + var out string = "Before debug.FreeOSMemory():\n\n" + out += runtimeReadMemStats() + debug.FreeOSMemory() + out += "\n\nAfter debug.FreeOSMemory():\n\n" + out += runtimeReadMemStats() + outputTextbox.SetText(out) + }) + + g.NewButton("debug.ReadGCStats()", func () { + var tmp debug.GCStats + var out string + debug.ReadGCStats(&tmp) + log.Log(true, tmp) + 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) + }) + + g.NewButton("debug.SetTraceback('all')", func () { + debug.SetTraceback("all") + }) + + g.NewButton("panic()", func () { + panic("test") + }) + + g = newB.NewGroup("TODO: finish these") + + // g.NewLabel("TODO:") + + g.NewButton("runtime.Stack(true)", func () { + // TODO: https://stackoverflow.com/questions/61127053/how-to-list-all-the-running-goroutines-in-a-go-program + // func Stack(buf []byte, all bool) int + }) + + g.NewButton("debug.SetMemoryLimit(int)", func () { + // TODO: + //debug.SetMemoryLimit(1024 * 1024 * 100) + }) + + g.NewButton("debug.SetMaxStack(int bytes)", func () { + // default is apparently 1GB + }) + + g.NewButton("debug.SetMaxThreads(int)", func () { + // default is apparently 10,000 + }) + + g.NewButton("debug.SetTraceback('all')", func () { + debug.SetTraceback("all") + }) + + // deprecated (probably) by String() implementation within golang + g.NewButton("dumpModuleInfo() (deprecate)", func () { + outputTextbox.SetText(dumpModuleInfo()) + }) + + og = newB.NewGroup("output") + outputTextbox = og.NewTextbox("outputBox") + outputTextbox.Custom = func () { + log.Log(true, "custom TextBox() for golang output a =", outputTextbox.S) + } +} + +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") + out += fmt.Sprintln("heap-idle:", s.HeapIdle,"bytes") + 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 +} diff --git a/mainWindow.go b/mainWindow.go index ee3e354..d7d18f9 100644 --- a/mainWindow.go +++ b/mainWindow.go @@ -50,10 +50,10 @@ func DebugWindow2(n *gui.Node, title string) *gui.Node { gui.DebugWidgetWindow(myGui) }) gog.NewButton("GO Language Internals", func () { - bugWin.DebugGolangWindow() + DebugGolangWindow(bugWin) }) gog.NewButton("GO Channels debug", func () { - bugWin.DebugGoChannels() + DebugGoChannels(bugWin) }) gog.NewLabel("Force Quit:")