From 9cdc7260bb053bd941a5c3b08bebbe0cfee83ffa Mon Sep 17 00:00:00 2001 From: Noah Petherbridge Date: Sat, 16 Apr 2022 17:50:40 -0700 Subject: [PATCH] Prepare v0.12.1 for release --- Changes.md | 32 ++++++++++++++++++++++++++++++ cmd/doodle/main.go | 22 ++++++++++++++++++++ pkg/balance/debug.go | 2 +- pkg/fps.go | 30 +++++++++++++++++++++++++++- pkg/main_scene.go | 11 ++++++++++ pkg/modal/loadscreen/loadscreen.go | 6 ++++++ 6 files changed, 101 insertions(+), 2 deletions(-) diff --git a/Changes.md b/Changes.md index 1c89f50..6fea4a9 100644 --- a/Changes.md +++ b/Changes.md @@ -1,5 +1,37 @@ # Changes +## v0.12.1 (April 16 2022) + +This update focuses on memory and performance improvements for the game. +Some larger levels such as "Azulian Tag - Forest" could run out of +memory on 32-bit systems. To improve on memory usage, the game more +aggressively frees SDL2 textures when no longer needed and it doesn't +try to keep the _whole_ level's chunks ready in memory (as rendered +images) -- only the chunks near the window viewport are loaded, and +chunks that leave the viewport are freed to reclaim memory. Improvements +are still a work in progress. + +New fields are added to the F3 debug overlay to peek at its performance: + +* "Textures:" shows the count of SDL2 textures currently loaded + in memory. Some textures, such as toolbar buttons and the + loadscreen wallpaper, lazy load and persist in memory. Most level + and doodad textures should free when the level exits. +* "Sys/Heap:" shows current memory utilization in terms of MiB taken + from the OS and MiB of active heap memory, respectively. +* "Threads:" counts the number of goroutines currently active. In + gameplay, each actor monitors its PubSub queue on a goroutine and + these should clean up when the level exits. +* "Chunks:" shows the count of level chunks inside and outside the + loading viewport. + +Some other changes and bug fixes in this release include: + +* Fixed the bug where the player was able to "climb" vertical walls to + their right. +* When entering a cheat code that changes the default player character + during gameplay, you immediately become that character. + ## v0.12.0 (March 27 2022) This update adds several new features to gameplay and the Level Editor. diff --git a/cmd/doodle/main.go b/cmd/doodle/main.go index 4bcbc41..ef2efc5 100644 --- a/cmd/doodle/main.go +++ b/cmd/doodle/main.go @@ -7,6 +7,7 @@ import ( "os" "regexp" "runtime" + "runtime/pprof" "sort" "strconv" "time" @@ -88,6 +89,10 @@ func main() { Aliases: []string{"d"}, Usage: "enable debug level logging", }, + &cli.StringFlag{ + Name: "pprof", + Usage: "record pprof metrics to a filename", + }, &cli.StringFlag{ Name: "chdir", Usage: "working directory for the game's runtime package", @@ -125,6 +130,23 @@ func main() { } } + // Recording pprof stats? + if cpufile := c.String("pprof"); cpufile != "" { + log.Info("Saving CPU profiling data to %s", cpufile) + fh, err := os.Create(cpufile) + if err != nil { + log.Error("--pprof: can't create file: %s", err) + return err + } + defer fh.Close() + + if err := pprof.StartCPUProfile(fh); err != nil { + log.Error("pprof: %s", err) + return err + } + defer pprof.StopCPUProfile() + } + var filename string if c.NArg() > 0 { filename = c.Args().Get(0) diff --git a/pkg/balance/debug.go b/pkg/balance/debug.go index 0a964f7..fbb931e 100644 --- a/pkg/balance/debug.go +++ b/pkg/balance/debug.go @@ -17,7 +17,7 @@ var ( // Debug overlay (FPS etc.) settings. DebugFontFilename = SansBoldFont - DebugFontSize = 16 + DebugFontSize = 14 DebugLabelColor = render.MustHexColor("#FF9900") DebugValueColor = render.MustHexColor("#00CCFF") DebugStrokeDarken = 80 diff --git a/pkg/fps.go b/pkg/fps.go index 7f9a93b..0208829 100644 --- a/pkg/fps.go +++ b/pkg/fps.go @@ -2,6 +2,7 @@ package doodle import ( "fmt" + "runtime" "strings" "git.kirsle.net/apps/doodle/pkg/balance" @@ -38,6 +39,11 @@ var ( fpsInterval uint32 = 1000 fpsDoNotCap bool // remove the FPS delay cap in main loop + // Memory usage metrics. + memHeap uint64 // Current heap memory size (shrinks on GC) + memSys uint64 // Current total memory usage + numGoroutine int + // Custom labels for individual Scenes to add debug info. customDebugLabels []debugLabel ) @@ -72,13 +78,17 @@ func (d *Doodle) DrawDebugOverlay() { "FPS:", "Scene:", "Mouse:", - "Tex:", + "Textures:", + "Sys/Heap:", + "Threads:", } values = []string{ fmt.Sprintf("%d %s", fpsCurrent, framesSkipped), d.Scene.Name(), fmt.Sprintf("%d,%d", d.event.CursorX, d.event.CursorY), texCount, + fmt.Sprintf("%d MiB / %d MiB", memSys, memHeap), + fmt.Sprintf("%d", numGoroutine), } ) @@ -202,4 +212,22 @@ func (d *Doodle) TrackFPS(skipped uint32) { // FPS in the title bar. d.Engine.SetTitle(fmt.Sprintf("%s (%d FPS)", d.Title(), fpsCurrent)) + + // Refresh memory usage. + GetMemUsage() +} + +// GetMemUsage collects statistics on memory utilization. +func GetMemUsage() { + var m runtime.MemStats + runtime.ReadMemStats(&m) + + memHeap = bToMb(m.Alloc) + memSys = bToMb(m.Sys) + + numGoroutine = runtime.NumGoroutine() +} + +func bToMb(b uint64) uint64 { + return b / 1024 / 1024 } diff --git a/pkg/main_scene.go b/pkg/main_scene.go index a25b6f9..d01e1be 100644 --- a/pkg/main_scene.go +++ b/pkg/main_scene.go @@ -57,6 +57,9 @@ type MainScene struct { // happens one time, and does not re-adapt when the window is made // tall enough again. landscapeMode bool + + // Debug F3 overlay vars + debLoadingViewport *string } /* @@ -88,6 +91,11 @@ func (s *MainScene) Name() string { // Setup the scene. func (s *MainScene) Setup(d *Doodle) error { + s.debLoadingViewport = new(string) + customDebugLabels = []debugLabel{ + {"Chunks:", s.debLoadingViewport}, + } + s.Supervisor = ui.NewSupervisor() if err := s.SetupDemoLevel(d); err != nil { @@ -405,6 +413,9 @@ func (s *MainScene) SetupDemoLevel(d *Doodle) error { func (s *MainScene) Loop(d *Doodle, ev *event.State) error { s.Supervisor.Loop(ev) + inside, outside := s.canvas.LoadUnloadMetrics() + *s.debLoadingViewport = fmt.Sprintf("%d in %d out", inside, outside) + if err := s.scripting.Loop(); err != nil { log.Error("MainScene.Loop: scripting.Loop: %s", err) } diff --git a/pkg/modal/loadscreen/loadscreen.go b/pkg/modal/loadscreen/loadscreen.go index f06d753..cdae60c 100644 --- a/pkg/modal/loadscreen/loadscreen.go +++ b/pkg/modal/loadscreen/loadscreen.go @@ -63,6 +63,12 @@ func ShowWithProgress() { visible = true withProgress = true subtitle = "" + + // TODO: hide the progress trough. With the new LoadUnloadChunks, + // the progress bar does nothing - all the loading time is spent + // reading the level from disk and then it starts. + withProgress = false + SetProgress(0) }