mirror of
https://github.com/JetSetIlly/Gopher2600.git
synced 2024-05-20 13:48:02 -04:00
added MEMUSAGE PROFILE command
mem profile saved on ctrl+alt+m memory profiles can be used with "go tool pprof"
This commit is contained in:
parent
47c7c95fd7
commit
c9ee3fc20f
|
@ -2109,17 +2109,30 @@ func (dbg *Debugger) processTokens(tokens *commandline.Tokens) error {
|
|||
}
|
||||
|
||||
case cmdMemUsage:
|
||||
var m runtime.MemStats
|
||||
runtime.ReadMemStats(&m)
|
||||
option, ok := tokens.Get()
|
||||
if ok {
|
||||
option = strings.ToUpper(option)
|
||||
switch option {
|
||||
case "PROFILE":
|
||||
fn, err := dbg.memoryProfile()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dbg.printLine(terminal.StyleLog, fmt.Sprintf("memory profile written to %s", fn))
|
||||
}
|
||||
} else {
|
||||
var m runtime.MemStats
|
||||
runtime.ReadMemStats(&m)
|
||||
|
||||
s := strings.Builder{}
|
||||
s := strings.Builder{}
|
||||
|
||||
s.WriteString(fmt.Sprintf("Alloc = %v MB\n", m.Alloc/1048576))
|
||||
s.WriteString(fmt.Sprintf(" TotalAlloc = %v MB\n", m.TotalAlloc/1048576))
|
||||
s.WriteString(fmt.Sprintf(" Sys = %v MB\n", m.Sys/1048576))
|
||||
s.WriteString(fmt.Sprintf(" NumGC = %v", m.NumGC))
|
||||
s.WriteString(fmt.Sprintf("Alloc = %v MB\n", m.Alloc/1048576))
|
||||
s.WriteString(fmt.Sprintf(" TotalAlloc = %v MB\n", m.TotalAlloc/1048576))
|
||||
s.WriteString(fmt.Sprintf(" Sys = %v MB\n", m.Sys/1048576))
|
||||
s.WriteString(fmt.Sprintf(" NumGC = %v", m.NumGC))
|
||||
|
||||
dbg.printLine(terminal.StyleLog, s.String())
|
||||
dbg.printLine(terminal.StyleLog, s.String())
|
||||
}
|
||||
|
||||
case cmdVersion:
|
||||
dbg.printLine(terminal.StyleLog, version.Version)
|
||||
|
|
|
@ -532,6 +532,8 @@ Note that while "ONSTEP LOG LAST" is a valid construct it may not print what you
|
|||
log entry after every step, even if the last log entry is not new. "ONSTEP LOG LAST; LOG CLEAR" is maybe more intuitive
|
||||
but with the maybe unwanted side effect of clearing the log.`,
|
||||
|
||||
cmdMemUsage: "Print memory usage information",
|
||||
cmdVersion: "Print version information for the emulator",
|
||||
cmdMemUsage: `Print memory usage information. The PROFILE option will save a pprof file in
|
||||
the working directory.`,
|
||||
|
||||
cmdVersion: "Print version information for the emulator",
|
||||
}
|
||||
|
|
|
@ -143,7 +143,7 @@ var commandTemplate = []string{
|
|||
|
||||
// emulation
|
||||
cmdLog + " (LAST|RECENT|CLEAR)",
|
||||
cmdMemUsage,
|
||||
cmdMemUsage + " (PROFILE)",
|
||||
cmdVersion + " (REVISION)",
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@ import (
|
|||
"io"
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
"runtime/pprof"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
|
@ -1489,7 +1491,7 @@ func (dbg *Debugger) InsertCartridge(filename string) {
|
|||
}
|
||||
|
||||
// GetLiveDisasmEntry returns the formatted disasembly entry of the last CPU
|
||||
// execution and the bank information
|
||||
// execution and the bank informations.String())
|
||||
func (dbg *Debugger) GetLiveDisasmEntry() disassembly.Entry {
|
||||
if dbg.liveDisasmEntry == nil {
|
||||
return disassembly.Entry{}
|
||||
|
@ -1502,3 +1504,23 @@ func (dbg *Debugger) GetLiveDisasmEntry() disassembly.Entry {
|
|||
func (dbg *Debugger) GetCoProcBus() coprocessor.CartCoProcBus {
|
||||
return dbg.vcs.Mem.Cart.GetCoProcBus()
|
||||
}
|
||||
|
||||
// memoryProfile forces a garbage collection event and takes a runtime memory
|
||||
// profile and saves it to the working directory
|
||||
func (dbg *Debugger) memoryProfile() (string, error) {
|
||||
fn := unique.Filename("", dbg.cartload.Name)
|
||||
fn = fmt.Sprintf("%s_mem.profile", fn)
|
||||
|
||||
f, err := os.Create(fn)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
runtime.GC()
|
||||
err = pprof.WriteHeapProfile(f)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return fn, nil
|
||||
}
|
||||
|
|
|
@ -81,3 +81,16 @@ func (dbg *Debugger) PushPropertyLookup(hashMD5 string, result chan properties.E
|
|||
result <- e
|
||||
})
|
||||
}
|
||||
|
||||
// PushMemoryProfile forces a garbage collection event and takes a runtime
|
||||
// memory profile and saves it to the working directory
|
||||
func (dbg *Debugger) PushMemoryProfile() {
|
||||
dbg.PushFunctionImmediate(func() {
|
||||
fn, err := dbg.memoryProfile()
|
||||
if err != nil {
|
||||
logger.Logf(logger.Allow, "memory profiling", err.Error())
|
||||
return
|
||||
}
|
||||
logger.Logf(logger.Allow, "memory profiling", "saved to %s", fn)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -205,7 +205,11 @@ func (img *SdlImgui) serviceKeyboard(ev *sdl.KeyboardEvent) {
|
|||
|
||||
case sdl.SCANCODE_M:
|
||||
if ctrl {
|
||||
img.toggleAudioMute()
|
||||
if alt {
|
||||
img.dbg.PushMemoryProfile()
|
||||
} else {
|
||||
img.toggleAudioMute()
|
||||
}
|
||||
} else {
|
||||
handled = false
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue