New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Perfmon System version 2 #1453
Perfmon System version 2 #1453
Conversation
I still need to polish some comments and add types, but ready for high level review. |
Moved the perfmon parts of napari#1354 to new PR napari#1453. This PR contains the ChunkLoader parts of napari#1354.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wow, this is amazing! Just gave it a spin and everything works great. I love the config file, so great to be able to specify the callables that I want to trace, I can imagine this being incredibly useful when developing and debuging. Right now I need to use benchmarks and airspeed velocity for all profiling, which can be nice for seeing everything, but I see this as being much faster and easier to use when figuring things out the first time.
Curious how @tlambert03 thinks about this, but I guess after we merge #1183 we'll probably want to combine that config file into that approach, but that can come later. Definitely nothing that needs to hold this PR up.
Now PerfTimer has a kwargs field that lets you set arbitrary key=value pairs that will be displayed into the GUI when you click on an event. With monkey patching you can't use these, but with a manual perf_timer you can.
When you say GUI here you mean the chrome tracing GUI right? not napari? this is how you injected your additional metadata that you wanted to view in the tracing tool right? just want to make sure I understand.
but you could use it to patch anything
Just curious what else could you imagine we might want to patch in like this?
final comment
I also read through the whole code and everything seemed very simple and clear - I won't claim to understand every line after this read, but it all looks very good to me and well documented. I think this is good to merge, but will let @jni and @tlambert03 review before then
Good point. I corrected it above to say "chrome://tracing GUI". Before I actually just tacked the key/value pairs onto the string name like
When you click on that event in Chrome you can see your values under Args: So this might be useful if you had a lot of values or big values. In fact looking at those Args it looks like the variable view in the debugger. And the nested rectangles depict the stack. So tracing is sort of a marriage between "debug prints" and "debugger technology". It's after the fact, but a fairly rich display of what happened. I'm bullish on tracing being useful well beyond timing. From my experience debugging with it, the code could statically look good but the trace looks wonky. You might see A calls B and B takes unexpectedly long. Or why do we call C from 3 different places? Or doing D triggers a ton of stuff. And it's all through the lens of time, because really fast stuff basically disappear unless you zoom way in.
I'm not really sure. At first the patcher was perf-specific but then I realized perf could just pass I guess you could have a The patcher format is so simple and useful I'm guessing there are packages that do the same thing? Maybe even
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm with @sofroniewn... this looks amazing & useful and the code is very clean and readable. I also can't claim to fully follow everything that's happening here without spending more time than I currently have... but since this is still an opt-in feature, I have no issues merging this to master.
I guess one request for a follow-up PR would be a bit of a "beginners guide" to using it. I'm new to this sort of performance tracing, so it's not totally clear to me whether the only output here is the "latest.json
" file which should be evaluated in chrome://tracing
, or whether there are other ways that you're using this. I wouldn't want you to regurgitate some chrome tracing tutorial that is already available elsewhere, but some docs that point to useful resources, with a quick example workflow (e.g. create something that doesn't perform that well, monitor it, fix it, and show how you know it got fixed) would be great.
Yes I think it very much needs kind of walkthrough of usage. I can create a folder Although as an aside, I've grown to somewhat feel that "tracing" is actually a bigger thing than just "performance monitoring". I think "tracing" is kind of purpose-neutral in the same way that "logging" is purpose-neutral. And in a way tracing is just logging, but it's logging in a very specific format. Because you could use tracing or logging to investigate performance issues, but you could use them for other reasons. A lot of the traces I made working on async where not really for "performance" they were getting things working correctly, at whatever speed. That's a pretty subtle point though. All the code is in |
Sounds great @pwinston thanks. I think I'll see if @jni has any additional comments on this PR in the next few hours and if not will merge before I go to sleep tonight so you can make the updated async PR tomorrow morning. That docs change can then come in its own PR.
Good points! Exciting to get this in!! |
I'd stick it in docs/source/developers, where benchmarks live. (For now, anyway.) In the future, maybe we can collect this together with your previous performance doc in a "speed" folder? btw why are all the filenames yelling at me in that folder? 😂 All in favour of changing the filenames to lowercase? 🙋
Gonna have a look in a bit but if you don't hear from me, go ahead. =) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @pwinston, much simpler now from my perspective! I've made a couple of extra notes around docstrings.
I'm unclear from your comment whether we should wait to merge for you to use my toolz suggestion to simplify the timer, or whether you'd rather move on to other things! Either is fine. (But toolz is awesome ;)
Change pid/tid to process_id/thread_id Add comment about "X" and "I"
This makes it clearer that it's a chrome://tracing thing and not just a generic "type" thing.
Co-authored-by: Juan Nunez-Iglesias <juan.nunez-iglesias@monash.edu>
Co-authored-by: Juan Nunez-Iglesias <juan.nunez-iglesias@monash.edu>
I have not really noticed where this shows up in the UI so until we feel it's useful best to leave it out.
These are not needed now that we have the patcher.
I think everything is resolved. All feedback/changes were beneficial I think, improved things. Only totally missing thing is external documentation, like a "how to" guide. I don't think that needs to be part of this PR relative to getting async further along |
Remove _utils.py since there was only 1 thing left in it.
Great! Thanks for the review @jni and making those changes @pwinston!
Agreed. I will wait till tests pass here and then merge shortly. I'm looking forward to checking out the async PR!! |
Add new start_file_on_start config file option instead. Using a separate env var was legacy, everything should be controlled via the config file now.
I snuck in the previous commit to get rid of
Which means if perfmon is enabled it starts writing to latest.json as soon as it starts. I find this really useful because when investigating something I just want to:
No need to use our Debug->Start Trace File menu option. Although I think it makes sense to keep that option. |
Yes, love this! Very nice |
Description
Updates to the perfmon system which were made while investigating and solving #1320:
kwargs
toperf_timer
to display per-event key/values in Chrome tracing.add_instant_event()
per API to add vertical lines in Chrome tracing.napari.utils.patcher.py
does the monkey patching, it's generic not perf specific.Type of change
Example 1
Example 2
Notes
New NAPARI_TRACE_FILE env var
Set this to a file path and Napari will trace to file on startup. I basically always use this and never start a trace from the debug menu anymore, although we should keep that option because it's more discoverable and useful for one-time tracing. This is how I tend to use perfmon today:
NAPARI_TRACE_FILE
to some locallatest.json
filelatest.json
intochrome://tracing
.So every time I run napari I get a trace file, and if I care what's in it I just throw it into Chrome.
Checking NAPARI_PERFMON
Before we took care to check the
NAPARI_PERFMON
env var without importing perf in a few place. Now with a config file we have to check the settings in that file to know whether to trace Qt events, so it's more natural to import perf. We check whether to trace Qt events like this:Perfmon Config File
If
NAPARI_PERFMON=1
we turn on Qt Event tracing like before, and we do nothing else. IfNAPARI_PERFMON
is a file path however, we load that as our perfmon config file. The format of the config file is:The
PerfmonConfig
class monkey patches ourperf_timer
context object into each function or method above. This means we don't have to modify the code at all, not even to add a decorator. And it also means we can have different trace sets, even overlapping ones, that we can toggle on or off as needed. You want enough tracing to see what you want, but not so much that the overhead is annoying.Add kwargs to perf_timer
Now
PerfTimer
has akwargs
field that lets you set arbitrary key=value pairs that will be displayed into thechrome://tracing
GUI when you click on an event. With monkey patching you can't use these, but with a manualperf_timer
you can.New add_instant_event()
New
add_instant_event()
is shown inchrome://tracing
as a vertical line. This is useful because very short events are invisible unless you zoom way in. But instant events are always visible as lines. For instance when debugging I created instant events forMousePressed
andMouseReleased
. There are 3-4 other graphical things in the chrome tracing spec that we aren't using yet, need to look into those."Tracing" vs. "Timing"
I've been switching to the term "tracing" based on my experience using the perf stuff. The Chrome feature is called
chrome://tracing
and tracing really is the right term. There is timing information, but just visualizing how the code executes is a big part of things, beyond the timing information. I might rename the whole module from "perf" to "tracing" at some point.Call Stack
The
perf_timer
wrappers clutter up the stack. If you want to debug might want to turn off perfmon.Patcher
The new
napari.utils.patcher.py
is actually totally generic for patching functions/methods. The perf code usespatcher
to patch inperf_timer
but you could use it to patch anything. Not sure if there is some library (eventwrapt
itself?) that can patch lists of callables like we are doing, but it was not hard to implement. It's only 150 lines with comments.How has this been tested?
Final checklist: