mirror of
https://github.com/JetSetIlly/Gopher2600.git
synced 2025-04-02 11:02:17 -04:00
o gopher2600
- debugger can now be run in a cpu profiling loop
This commit is contained in:
parent
f334e6e94d
commit
9e32748b0a
5 changed files with 73 additions and 46 deletions
|
@ -16,7 +16,7 @@ const (
|
|||
PlayError
|
||||
DebuggerError
|
||||
DisasmError
|
||||
FPSError
|
||||
PerformanceError
|
||||
|
||||
// debugger
|
||||
ParserError
|
||||
|
|
|
@ -12,10 +12,10 @@ var messages = map[Errno]string{
|
|||
TVOutOfSpec: "tv out of spec: %s", // sentinal
|
||||
|
||||
// program modes
|
||||
PlayError: "error emulating vcs: %s",
|
||||
DebuggerError: "error debugging vcs: %s",
|
||||
FPSError: "error during fps profiling: %s",
|
||||
DisasmError: "error during disassembly: %s",
|
||||
PlayError: "error emulating vcs: %s",
|
||||
DebuggerError: "error debugging vcs: %s",
|
||||
PerformanceError: "error during performance profiling: %s",
|
||||
DisasmError: "error during disassembly: %s",
|
||||
|
||||
// debugger
|
||||
ParserError: "parser error: %s: %s (char %d)", // first placeholder is the command definition
|
||||
|
|
|
@ -169,6 +169,7 @@ func main() {
|
|||
tvType := modeFlags.String("tv", "AUTO", "television specification: NTSC, PAL")
|
||||
termType := modeFlags.String("term", "COLOR", "terminal type to use in debug mode: COLOR, PLAIN")
|
||||
initScript := modeFlags.String("initscript", defaultInitScript, "terminal type to use in debug mode: COLOR, PLAIN")
|
||||
profile := modeFlags.Bool("profile", false, "run debugger through cpu profiler")
|
||||
modeFlagsParse()
|
||||
|
||||
dbg, err := debugger.NewDebugger(*tvType)
|
||||
|
@ -195,10 +196,27 @@ func main() {
|
|||
// it's okay if DEBUG mode is started with no cartridges
|
||||
fallthrough
|
||||
case 1:
|
||||
err := dbg.Start(term, *initScript, modeFlags.Arg(0))
|
||||
if err != nil {
|
||||
fmt.Printf("* %s\n", err)
|
||||
os.Exit(2)
|
||||
runner := func() error {
|
||||
err := dbg.Start(term, *initScript, modeFlags.Arg(0))
|
||||
if err != nil {
|
||||
return errors.NewFormattedError(errors.PerformanceError, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if *profile {
|
||||
err := performance.ProfileCPU("debug.cpu.profile", runner)
|
||||
if err != nil {
|
||||
fmt.Printf("* %s\n", err)
|
||||
os.Exit(2)
|
||||
}
|
||||
err = performance.ProfileMem("debug.mem.profile")
|
||||
if err != nil {
|
||||
fmt.Printf("* %s\n", err)
|
||||
os.Exit(2)
|
||||
}
|
||||
} else {
|
||||
runner()
|
||||
}
|
||||
default:
|
||||
fmt.Printf("* too many arguments for %s mode\n", mode)
|
||||
|
|
|
@ -21,46 +21,46 @@ func Check(output io.Writer, profile bool, cartridgeFile string, display bool, t
|
|||
if display {
|
||||
ftv, err = sdl.NewGUI(tvType, scaling, nil)
|
||||
if err != nil {
|
||||
return errors.NewFormattedError(errors.FPSError, err)
|
||||
return errors.NewFormattedError(errors.PerformanceError, err)
|
||||
}
|
||||
|
||||
err = ftv.(gui.GUI).SetFeature(gui.ReqSetVisibility, true)
|
||||
if err != nil {
|
||||
return errors.NewFormattedError(errors.FPSError, err)
|
||||
return errors.NewFormattedError(errors.PerformanceError, err)
|
||||
}
|
||||
} else {
|
||||
ftv, err = television.NewStellaTelevision(tvType)
|
||||
if err != nil {
|
||||
return errors.NewFormattedError(errors.FPSError, err)
|
||||
return errors.NewFormattedError(errors.PerformanceError, err)
|
||||
}
|
||||
}
|
||||
|
||||
// create vcs using the tv created above
|
||||
vcs, err := hardware.NewVCS(ftv)
|
||||
if err != nil {
|
||||
return errors.NewFormattedError(errors.FPSError, err)
|
||||
return errors.NewFormattedError(errors.PerformanceError, err)
|
||||
}
|
||||
|
||||
// attach cartridge to te vcs
|
||||
err = vcs.AttachCartridge(cartridgeFile)
|
||||
if err != nil {
|
||||
return errors.NewFormattedError(errors.FPSError, err)
|
||||
return errors.NewFormattedError(errors.PerformanceError, err)
|
||||
}
|
||||
|
||||
// parse supplied duration
|
||||
duration, err := time.ParseDuration(runTime)
|
||||
if err != nil {
|
||||
return errors.NewFormattedError(errors.FPSError, err)
|
||||
return errors.NewFormattedError(errors.PerformanceError, err)
|
||||
}
|
||||
|
||||
// get starting frame number (should be 0)
|
||||
startFrame, err := ftv.GetState(television.ReqFramenum)
|
||||
if err != nil {
|
||||
return errors.NewFormattedError(errors.FPSError, err)
|
||||
return errors.NewFormattedError(errors.PerformanceError, err)
|
||||
}
|
||||
|
||||
// run for specified period of time
|
||||
err = cpuProfile(profile, "cpu.profile", func() error {
|
||||
runner := func() error {
|
||||
// setup trigger that expires when duration has elapsed
|
||||
timesUp := make(chan bool)
|
||||
|
||||
|
@ -85,23 +85,34 @@ func Check(output io.Writer, profile bool, cartridgeFile string, display bool, t
|
|||
}
|
||||
})
|
||||
if err != nil {
|
||||
return errors.NewFormattedError(errors.FPSError, err)
|
||||
return errors.NewFormattedError(errors.PerformanceError, err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
if profile {
|
||||
err = ProfileCPU("cpu.profile", runner)
|
||||
} else {
|
||||
err = runner()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return errors.NewFormattedError(errors.FPSError, err)
|
||||
return errors.NewFormattedError(errors.PerformanceError, err)
|
||||
}
|
||||
|
||||
// get ending frame number
|
||||
endFrame, err := vcs.TV.GetState(television.ReqFramenum)
|
||||
if err != nil {
|
||||
return errors.NewFormattedError(errors.FPSError, err)
|
||||
return errors.NewFormattedError(errors.PerformanceError, err)
|
||||
}
|
||||
|
||||
numFrames := endFrame - startFrame
|
||||
fps, accuracy := CalcFPS(ftv, numFrames, duration.Seconds())
|
||||
output.Write([]byte(fmt.Sprintf("%.2f fps (%d frames in %.2f seconds) %.1f%%\n", fps, numFrames, duration.Seconds(), accuracy)))
|
||||
|
||||
return memProfile(profile, "mem.profile")
|
||||
if profile {
|
||||
err = ProfileMem("mem.profile")
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -7,36 +7,34 @@ import (
|
|||
"runtime/pprof"
|
||||
)
|
||||
|
||||
func cpuProfile(profile bool, outFile string, run func() error) error {
|
||||
if profile {
|
||||
// write cpu profile
|
||||
f, err := os.Create(outFile)
|
||||
if err != nil {
|
||||
return errors.NewFormattedError(errors.FPSError, err)
|
||||
}
|
||||
err = pprof.StartCPUProfile(f)
|
||||
if err != nil {
|
||||
return errors.NewFormattedError(errors.FPSError, err)
|
||||
}
|
||||
defer pprof.StopCPUProfile()
|
||||
// ProfileCPU runs supplied function "through" the pprof CPU profiler
|
||||
func ProfileCPU(outFile string, run func() error) error {
|
||||
// write cpu profile
|
||||
f, err := os.Create(outFile)
|
||||
if err != nil {
|
||||
return errors.NewFormattedError(errors.PerformanceError, err)
|
||||
}
|
||||
err = pprof.StartCPUProfile(f)
|
||||
if err != nil {
|
||||
return errors.NewFormattedError(errors.PerformanceError, err)
|
||||
}
|
||||
defer pprof.StopCPUProfile()
|
||||
|
||||
return run()
|
||||
}
|
||||
|
||||
func memProfile(profile bool, outFile string) error {
|
||||
if profile {
|
||||
f, err := os.Create(outFile)
|
||||
if err != nil {
|
||||
return errors.NewFormattedError(errors.FPSError, err)
|
||||
}
|
||||
runtime.GC()
|
||||
err = pprof.WriteHeapProfile(f)
|
||||
if err != nil {
|
||||
return errors.NewFormattedError(errors.FPSError, err)
|
||||
}
|
||||
f.Close()
|
||||
// ProfileMem takes a snapshot of memory and writes to outFile
|
||||
func ProfileMem(outFile string) error {
|
||||
f, err := os.Create(outFile)
|
||||
if err != nil {
|
||||
return errors.NewFormattedError(errors.PerformanceError, err)
|
||||
}
|
||||
runtime.GC()
|
||||
err = pprof.WriteHeapProfile(f)
|
||||
if err != nil {
|
||||
return errors.NewFormattedError(errors.PerformanceError, err)
|
||||
}
|
||||
f.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue