Add call trace command

This commit is contained in:
Tulir Asokan 2019-06-15 19:10:18 +03:00
parent ef509eb308
commit 6bb932212c
3 changed files with 31 additions and 31 deletions

View File

@ -34,8 +34,6 @@ import (
func init() { func init() {
gob.Register(map[string]interface{}{}) gob.Register(map[string]interface{}{})
gob.Register([]interface{}{}) gob.Register([]interface{}{})
gob.Register(&Room{})
gob.Register(0)
} }
type RoomNameSource int type RoomNameSource int

View File

@ -109,6 +109,7 @@ func NewCommandProcessor(parent *MainView) *CommandProcessor {
"invite": cmdInvite, "invite": cmdInvite,
"hprof": cmdHeapProfile, "hprof": cmdHeapProfile,
"cprof": cmdCPUProfile, "cprof": cmdCPUProfile,
"trace": cmdTrace,
}, },
} }
} }

View File

@ -19,10 +19,12 @@ package ui
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io"
"os" "os"
"runtime" "runtime"
dbg "runtime/debug" dbg "runtime/debug"
"runtime/pprof" "runtime/pprof"
"runtime/trace"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@ -92,38 +94,37 @@ func cmdHeapProfile(cmd *Command) {
} }
} }
func cmdCPUProfile(cmd *Command) { func runTimedProfile(cmd *Command, start func(writer io.Writer) error, stop func(), task, file string) {
if len(cmd.Args) == 0 { if len(cmd.Args) == 0 {
cmd.Reply("Usage: /cprof <seconds>") cmd.Reply("Usage: /%s <seconds>", cmd.Command)
return } else if dur, err := strconv.Atoi(cmd.Args[0]); err != nil || dur < 0 {
} cmd.Reply("Usage: /%s <seconds>", cmd.Command)
dur, err := strconv.Atoi(cmd.Args[0]) } else if cpuProfile, err := os.Create(file); err != nil {
if err != nil || dur < 0 { debug.Printf("Failed to open %s: %v", file, err)
cmd.Reply("Usage: /cprof <seconds>") } else if err = start(cpuProfile); err != nil {
return
}
cpuProfile, err := os.Create("gomuks.cpu.prof")
if err != nil {
debug.Print("Failed to open gomuks.cpu.prof:", err)
return
}
err = pprof.StartCPUProfile(cpuProfile)
if err != nil {
_ = cpuProfile.Close() _ = cpuProfile.Close()
debug.Print("CPU profile error:", err) debug.Print(task, "error:", err)
return } else {
} cmd.Reply("Started %s for %d seconds", task, dur)
cmd.Reply("Started CPU profiling for %d seconds", dur)
go func() { go func() {
time.Sleep(time.Duration(dur) * time.Second) time.Sleep(time.Duration(dur) * time.Second)
pprof.StopCPUProfile() stop()
cmd.Reply("CPU profiling finished.") cmd.Reply("%s finished.", task)
err := cpuProfile.Close() err := cpuProfile.Close()
if err != nil { if err != nil {
debug.Print("Failed to close gomuks.cpu.prof:", err) debug.Print("Failed to close gomuks.cpu.prof:", err)
} }
}() }()
}
}
func cmdCPUProfile(cmd *Command) {
runTimedProfile(cmd, pprof.StartCPUProfile, pprof.StopCPUProfile, "CPU profiling", "gomuks.cpu.prof")
}
func cmdTrace(cmd *Command) {
runTimedProfile(cmd, trace.Start, trace.Stop, "Call tracing", "gomuks.trace")
} }
// TODO this command definitely belongs in a plugin once we have a plugin system. // TODO this command definitely belongs in a plugin once we have a plugin system.