diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 528b3a88..d427253c 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -13,6 +13,7 @@ wtfblub q3cpma averrin Dylan "Gravestench" Knuth +Intyre * DIABLO2 LOGO Jose Pardilla (th3-prophetman) diff --git a/README.md b/README.md index a1c7f805..cd65c5c0 100644 --- a/README.md +++ b/README.md @@ -73,19 +73,20 @@ the game in a different location, the base path may have to be adjusted. ## Profiling -There are many profiler options to debug performance issues. These can be enabled by suppling the following command-line option: +There are many profiler options to debug performance issues. These can be enabled by suppling the following command-line option and are saved in the `pprof` directory: -`go run . --profile=cpu,mem` +`go run . --profile=cpu` Available profilers:\ `cpu` `mem` `block` `goroutine` `trace` `thread` `mutex` You can export the profiler output with the following command:\ -`go tool pprof --pdf ./OpenDiablo2 /var/path/to/profiler.pprof > file.pdf` +`go tool pprof --pdf ./OpenDiablo2 pprof/profiler.pprof > file.pdf` + +Ingame you can create a heap dump by pressing `~` and typing `dumpheap`. A heap.pprof is written to the `pprof` directory. You may need to install [Graphviz](http://www.graphviz.org/download/) in order to convert the profiler output. - ## Roadmap There is an in-progress [project roadmap](https://docs.google.com/document/d/156sWiuk-XBfomVxZ3MD-ijxnwM1X66KTHo2AcWIy8bE/edit?usp=sharing), diff --git a/main.go b/main.go index 40125204..e398d1ec 100644 --- a/main.go +++ b/main.go @@ -9,7 +9,6 @@ import ( "image/png" "log" "os" - "os/exec" "runtime" "runtime/pprof" "strconv" @@ -72,7 +71,7 @@ func main() { region := kingpin.Arg("region", "Region type id").Int() preset := kingpin.Arg("preset", "Level preset").Int() - profileOptions := kingpin.Flag("profile", "Profiles the program (cpu, mem, block, goroutine, trace, thread, mutex)").String() + profileOption := kingpin.Flag("profile", "Profiles the program, one of (cpu, mem, block, goroutine, trace, thread, mutex)").String() kingpin.Parse() @@ -83,35 +82,8 @@ func main() { log.Fatal(err) } - var profilers []func(*profile.Profile) - for _, profileOption := range strings.Split(*profileOptions, ",") { - switch strings.ToLower(strings.Trim(profileOption, " ")) { - case "cpu": - log.Printf("CPU profiling is enabled.") - profilers = append(profilers, profile.CPUProfile) - case "mem": - log.Printf("Memory profiling is enabled.") - profilers = append(profilers, profile.MemProfile) - case "block": - log.Printf("Block profiling is enabled.") - profilers = append(profilers, profile.BlockProfile) - case "goroutine": - log.Printf("Goroutine profiling is enabled.") - profilers = append(profilers, profile.GoroutineProfile) - case "trace": - log.Printf("Trace profiling is enabled.") - profilers = append(profilers, profile.TraceProfile) - case "thread": - log.Printf("Thread creation profiling is enabled.") - profilers = append(profilers, profile.ThreadcreationProfile) - case "mutex": - log.Printf("Mutex profiling is enabled.") - profilers = append(profilers, profile.MutexProfile) - } - } - - if len(profilers) > 0 { - defer profile.Start(profilers...).Stop() + if len(*profileOption) > 0 { + enableProfiler(*profileOption) } if *region == 0 { @@ -153,11 +125,11 @@ func initialize() error { } d2term.BindLogger() - d2term.BindAction("dumpheap", "dumps the heap to heap.out", func() { - fileOut, _ := os.Create("heap.out") + d2term.BindAction("dumpheap", "dumps the heap to pprof/heap.pprof", func() { + os.Mkdir("./pprof/", 0755) + fileOut, _ := os.Create("./pprof/heap.pprof") pprof.WriteHeapProfile(fileOut) fileOut.Close() - exec.Command("go", "tool", "pprof", "--pdf", "./OpenDiablo2", "./heap.out", ">", "./memprofile.pdf") }) d2term.BindAction("fullscreen", "toggles fullscreen", func() { fullscreen := !d2render.IsFullScreen() @@ -482,3 +454,35 @@ func loadStrings() error { return nil } + +func enableProfiler(profileOption string) { + var options []func(*profile.Profile) + switch strings.ToLower(strings.Trim(profileOption, " ")) { + case "cpu": + log.Printf("CPU profiling is enabled.") + options = append(options, profile.CPUProfile) + case "mem": + log.Printf("Memory profiling is enabled.") + options = append(options, profile.MemProfile) + case "block": + log.Printf("Block profiling is enabled.") + options = append(options, profile.BlockProfile) + case "goroutine": + log.Printf("Goroutine profiling is enabled.") + options = append(options, profile.GoroutineProfile) + case "trace": + log.Printf("Trace profiling is enabled.") + options = append(options, profile.TraceProfile) + case "thread": + log.Printf("Thread creation profiling is enabled.") + options = append(options, profile.ThreadcreationProfile) + case "mutex": + log.Printf("Mutex profiling is enabled.") + options = append(options, profile.MutexProfile) + } + options = append(options, profile.ProfilePath("./pprof/")) + + if len(options) > 1 { + defer profile.Start(options...).Stop() + } +}