mirror of
https://github.com/JetSetIlly/Gopher2600.git
synced 2024-06-02 20:18:20 -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:
|
case cmdMemUsage:
|
||||||
var m runtime.MemStats
|
option, ok := tokens.Get()
|
||||||
runtime.ReadMemStats(&m)
|
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("Alloc = %v MB\n", m.Alloc/1048576))
|
||||||
s.WriteString(fmt.Sprintf(" TotalAlloc = %v MB\n", m.TotalAlloc/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(" Sys = %v MB\n", m.Sys/1048576))
|
||||||
s.WriteString(fmt.Sprintf(" NumGC = %v", m.NumGC))
|
s.WriteString(fmt.Sprintf(" NumGC = %v", m.NumGC))
|
||||||
|
|
||||||
dbg.printLine(terminal.StyleLog, s.String())
|
dbg.printLine(terminal.StyleLog, s.String())
|
||||||
|
}
|
||||||
|
|
||||||
case cmdVersion:
|
case cmdVersion:
|
||||||
dbg.printLine(terminal.StyleLog, version.Version)
|
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
|
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.`,
|
but with the maybe unwanted side effect of clearing the log.`,
|
||||||
|
|
||||||
cmdMemUsage: "Print memory usage information",
|
cmdMemUsage: `Print memory usage information. The PROFILE option will save a pprof file in
|
||||||
cmdVersion: "Print version information for the emulator",
|
the working directory.`,
|
||||||
|
|
||||||
|
cmdVersion: "Print version information for the emulator",
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,7 +143,7 @@ var commandTemplate = []string{
|
||||||
|
|
||||||
// emulation
|
// emulation
|
||||||
cmdLog + " (LAST|RECENT|CLEAR)",
|
cmdLog + " (LAST|RECENT|CLEAR)",
|
||||||
cmdMemUsage,
|
cmdMemUsage + " (PROFILE)",
|
||||||
cmdVersion + " (REVISION)",
|
cmdVersion + " (REVISION)",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,8 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"runtime"
|
||||||
|
"runtime/pprof"
|
||||||
"strings"
|
"strings"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
@ -1489,7 +1491,7 @@ func (dbg *Debugger) InsertCartridge(filename string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLiveDisasmEntry returns the formatted disasembly entry of the last CPU
|
// 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 {
|
func (dbg *Debugger) GetLiveDisasmEntry() disassembly.Entry {
|
||||||
if dbg.liveDisasmEntry == nil {
|
if dbg.liveDisasmEntry == nil {
|
||||||
return disassembly.Entry{}
|
return disassembly.Entry{}
|
||||||
|
@ -1502,3 +1504,23 @@ func (dbg *Debugger) GetLiveDisasmEntry() disassembly.Entry {
|
||||||
func (dbg *Debugger) GetCoProcBus() coprocessor.CartCoProcBus {
|
func (dbg *Debugger) GetCoProcBus() coprocessor.CartCoProcBus {
|
||||||
return dbg.vcs.Mem.Cart.GetCoProcBus()
|
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
|
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:
|
case sdl.SCANCODE_M:
|
||||||
if ctrl {
|
if ctrl {
|
||||||
img.toggleAudioMute()
|
if alt {
|
||||||
|
img.dbg.PushMemoryProfile()
|
||||||
|
} else {
|
||||||
|
img.toggleAudioMute()
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
handled = false
|
handled = false
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue