debugger
debugger copied to clipboard
[Feature] Force refresh button [sf#165]
Reported by sd-snatcher on 2009-03-07 14:25 UTC Sometimes openMSX-debugger stays showing older data, then I have to close it and open again, to force it to reload everything. It would be nice to have a button to force the refresh of all data.
Commented by sd-snatcher on 2010-08-23 22:47 UTC Some more details to this feature request, since I'm not sure if it shouldn't be opened as a bug:
It frequently happens that the "Code View" window persists showing incorrect (not updated) code. This usually happens on the following situations:
-
When I close openMSX, recompile the code, run openMSX again and connect the debugger to it. All of this without closing the debugger to save time and not to lose the current breakpoints.
-
Sometimes on some types of paging: Mostly PPI paging and MegaROM paging.
The only current work-around is to quit the debugger and reopen it, and that shift of focus isn't good for concentration and productivity.
The best solutions would be:
- OpenMSX-debugger should refresh all code/data windows upon connecting
- A forced refresh button would also be helpfull
Commented by manuelbi on 2014-02-08 16:15 UTC Is this still happening?
Commented by sd-snatcher on 2014-05-17 21:12 UTC I just tested it and, yes it's still happening.
Tested with:
- openMSX 0.10.1 on Mac OS-X 10.9.2
- openMSX-debugger 0.9.0-dev12821
Still the same...
There is another situation where the problem arises: on self-modifying routines!
For example, some Gremlin Graphics games build in run-time the needed op-code to check row and column of the keyboard matrix in an very efficient way.
If the modified address isn't close to that routine, you may not notice about it, so when you execute the new instruction you'll go bananas while trying to understand what's going on (because what you see is NOT what you get).
I frequently have the problem of the disassembly view showing old data as well, but I don’t agree with the suggested solution;
I think it would be much better to solve the problem in a way which doesn’t require explicit user intervention, otherwise I’ll be pressing the refresh button continuously because I don’t trust the debugger’s output… definitely a bad thing (the distrust), and also unnecessary manual labour the computer can do rather than me. Other fields on screen are also updated when I hit a breakpoint and step through the code, so why shouldn’t the code view be able to as well.
Additionally, the case where I most often encounter this issue is when I recompile and relaunch openMSX, and then reconnect the debugger. If the breakpoint I hit is close to where I previously disconnected the debugger is still using the cached data disassembly. Definitely when the debugger is reconnected it could flush the cache.
@edwin-v how hard is this to fix? Any hints/pointers?
If that happens, it's a bug. It should fully refresh on reconnect. I'll have a look.
Any progress in this front? btw
Haven't had a single bit of time. Every thing that requires concentration has been delay to vacation time. Which starts next week!
lol, ok! totally understandable! :) not much time on my end either (and using all the time I have to try to get my MSXDev entry on time), but if I can be of any use testing anything, I'm happy to help! :)
@edwin-v Any news on this? People keep posting about this problem...
@edwin-v Another report about this today:
<p_gimeno> ok, "step back" worked judging by the slots and the BC register, but the code window didn't refresh. Is there some way to force it to refresh? <Quibus> I've heard more often about refresh issues, but Edwin couldn't reproduce them, he said <p_gimeno> I can give a reproduction recipe if that helps <p_gimeno> (1) run openmsx -machine Toshiba_HX-10, wait for BASIC to be ready; (2) run the debugger and connect, (3) set a breakpoint on a write to port $A8, (4) in BASIC enter out &ha8,15, (5) the debugger should now show all rst 56; select Step Back and notice it doesn't change <p_gimeno> rst 38h* <p_gimeno> I've noticed similar refresh issues when doing other things; maybe it should have a manual refresh command <p_gimeno> I think that another one happened when single-stepping an instruction that wrote to FFFF
+1 on this. Not sure how to reproduce, but code view did not show what I was expecting, and showed other data than the debuggable memory view.
@edwin-v Any chance you can take a look?
Other fields on screen are also updated when I hit a breakpoint and step through the code, so why shouldn’t the code view be able to as well.
Forcing a refresh when on a breakpoint is also nice. But it's also nice to have the possibility to refresh all fields without having to press the break button and then the run button just for that.
@edwin-v Still there, Edwin?
Still alive, but definitely won't have time to look into anything until at least the end of the year.
@edwin-v How are you now? :)
@edwin-v can you review that Pull Request?
I think this issue can be considered closed now, right?
Yes, the disasm view is updated each step, so that should cover this. Thanks for the PR!
This problem is still happening frequently.
-
If I have two openMSX executables running side by side and disconnect/reconnect the debugger to alternate between the two, the code almost view almost always is not updated
-
Self executable code, or even DOS apps that load different overlays from the disk are a nightmare, because the debugger frequently keeps showing the old code. Sometimes doing a lot of rewind steps forces it to update, but sometimes not even this workarounds the problem
This problem is still happening frequently.
- If I have two openMSX executables running side by side and disconnect/reconnect the debugger to alternate between the two, the code almost view almost always is not updated
- Self executable code, or even DOS apps that load different overlays from the disk are a nightmare, because the debugger frequently keeps showing the old code. Sometimes doing a lot of rewind steps forces it to update, but sometimes not even this workarounds the problem
I confirm this behaviour. As a workaround, I usually reload the symbols file. It's easier than doing rewind steps.
Nothing has really changed for a while. Should have a bit more time to look into it, but it is sort of a race condition in the asynchronous communication that has no easy solution.
@edwin-v can you explain exactly what is going on in these cases?
@Colpocorto and @sdsnatcher apparently the debug view is now updated each step. So I'm wondering why that wouldn't be sufficient. Perhaps the race condition that @edwin-v is talking about, but I'd like to understand in more detail...
Can you guys try out the experimental Dear ImGUI openMSX build from for example https://github.com/openMSX/openMSX/actions/runs/5137117621 and see how debugging works for you there? It should always be real-time updated, due to the nature of its design. Remember: highly experimental!
I have an idea to fix this, but to be thorough it has to be a three part fix:
- connect DebuggerForm::connected to DisasmViewer::refresh to force the debugger to fetch the memory again when connected (PR #183 pending);
- create memory watch points the size of the memory window, so we detect memory operations that overwrite RAM, like LDIR and connect them to DisasmViewer::refresh;
- detect slot and subslot changes and connect them to DisasmViewer::refresh;
Number 2 will cause an explosion of watch point indexes, so it is probably not desirable. And it seems that number 3 already happens.
@pvmm: Your idea is to automatically refresh. So without the need for a manual refresh button, right?
Point 2 can indeed be a problem. Setting a large watchpoint on the full 64k range will indeed trigger the slow-emulation-path on all memory accesses. That's not ideal. Depending on the details of your implementation this will also send messages from openMSX to the debugger application, likely tens of thousands per second. My guess is that sending so many messages will be a much bigger problem.
Note that a wtachpoint only triggers when the Z80 explicitly wrote to a memory location, it does not trigger when the underlying memory view changes for some other reason. So your point 3 "detect (sub)slot changes" is indeed important. But to be complete it needs to be extended with memory-mapper and rom mapper changes E.g. memory mapper and some rom mappers change by writing to a specific IO port, those ports should then also be monitored. Most rom mappers change by writing to a specific memory location, that's already covered by point 2.
Nevertheless feel free to try out your idea. If it works well, and if it performs acceptable (on a modern host machine) we can pull it. Though my guess is that a manual refresh button might be a simpler/better solution.
Background info: The new imgui based debugger bypasses this refresh-problem by simply re-querying all the needed(*1) information every frame. But that's only possible because that debugger is integrated in the openMSX executable itself. So exchanging messages is many orders of magnitude faster than in the current debugger. (*1) it still only does the minimal amount of queries to redraw the currently visible information. So e.g. only that part of the memory that's currently shown (not that part that's scrolled off screen).
Many parts of the new imgui debugger are already implemented. I hope to finish the remaining parts in the following month(s). Feel free to already try it and give feedback.
Point 2 can indeed be a problem. Setting a large watchpoint on the full 64k range will indeed trigger the slow-emulation-path on all memory accesses. That's not ideal. Depending on the details of your implementation this will also send messages from openMSX to the debugger application, likely tens of thousands per second. My guess is that sending so many messages will be a much bigger problem.
We don´t need to watch the full 64k range, just the current memory window displayed on the DisasmViewer
(around 460 bytes, depending on the size of the disassembly widget). As long as we create and destroy the new watch point as the memory window moves. That will create and destroy a lot of watch points, but we only need to actually create the watch point when we leave break status (and delete it when we enter break status).
Note that a wtachpoint only triggers when the Z80 explicitly wrote to a memory location, it does not trigger when the underlying memory view changes for some other reason. So your point 3 "detect (sub)slot changes" is indeed important. But to be complete it needs to be extended with memory-mapper and rom mapper changes E.g. memory mapper and some rom mappers change by writing to a specific IO port, those ports should then also be monitored. Most rom mappers change by writing to a specific memory location, that's already covered by point 2.
I wonder if a more generic approach is possible from OpenMSX side. For instance, we write a debuggable called "page swapping" that triggers an event when page swapping is detected and the debugger listens to that event.
We don´t need to watch the full 64k range, just the current memory window displayed on the
DisasmViewer
(around 460 bytes, depending on the size of the disassembly widget). As long as we create and destroy the new watch point as the memory window moves. That will create and destroy a lot of watch points, but we only need to actually create the watch point when we leave break status (and delete it when we enter break status).
That would help. Creating/destroying watchpoints often shouldn't be a problem as this is only done when you're interacting with the debugger. It's fine to send hundreds of messages per second over the openMSX-debugger-connection. But (tens of) thousands likely is a problem.
I wonder if a more generic approach is possible from OpenMSX side. For instance, we write a debuggable called "page swapping" that triggers an event when page swapping is detected and the debugger listens to that event.
Technically that's possible. Though I'm hesitant to implement that because of the following reasons. I'll first give a summary and then later go in more detail and suggest an alternative:
- It's a lot of work, not difficult work, but a lot of work.
- It's still only a partial solution: ** Memory can still change for other reasons than page swaps. ** It only improves the situation for main memory, not for all the other debuggables (e.g. VRAM).
- In exceptional(?) cases there can be thousands of page flips per second. Getting a callback for each might still be slow.
- There is a known better solution: the new imgui debugger has proven to solve this problem very well.
Because of the combination of all these reasons, my current preference is to not go for this solution.
Adding a callback mechanism for page swaps seems simple, in principle. But to be complete this has to work for all devices: we have +80 rom-mapper types and several non-rom-mappers that all have some form of page-swapping. Often page swapping is implemented via some common mechanism, but unfortunately not always. So at the very least we'd have to audit all memory-based device implementations, (re-)understand their behavior (related to page-swaps), and then make sure that the callback gets triggered. This isn't very difficult work, but it is a LOT of work.
Sometimes the memory content can change without any page swaps and without an explicit write from the CPU. A typical example is memory mapped IO (e.g. the FDC or IDE registers). And for these it isn't possible to add a callback (well everything is possible of course, but figuring out when the callback should trigger is more expensive than constantly querying the value). Memory mapped registers typically aren't meaningful for the disassembly view, but they are often shown in the memory viewer.
And speaking of the memory viewer ... next to main-memory there are a whole lot of other debuggables that can be shown in the hex-viewers (or others visualizations). Ideally those should also auto-refresh, but the callback-on-page-switch doesn't address those at all.
The solution taken by the new imgui debugger is to not store any local state (that needs to be kept in sync with the openMSX state). Instead it simply re-queries the information whenever it is needed (often this means whenever the debugger is redrawn, thus every frame, 60 times per second). This works well for the imgui debugger because it's directly integrated in the openMSX process itself. This approach probably(*1) wouldn't work well for the current debugger.
Though this last paragraph gave me an idea for an alternative solution. Instead of re-querying all information on every frame, you could only re-query it once or a few times per second.
(*1) My impression is that the slowness is mainly caused by the amount of messages that are send (per second). Not (or to a lesser degree) by the size of those messages. So a few big queries per second work better than many small queries, even if the total amount of data is lower in the 2nd case.