How to tell where CPU is being spent handling GUI stuff?

Andrew Richards's icon

Hi all. I'm new to programming in Max. I'm using Max for Live. I'm adding a small UI to my device/patch, which only does MIDI processing and no audio processing. I'm trying to figure out how to monitor time and resources spent drawing and handling the GUI components. I'm considering using the 'jsui' object to draw some parts of it. But I don't see how to monitor or analyze the various drawing and UI operations take from the documentation, so I don't really have a foothold on what to prioritize. Max is running all of this code in a managed environment, so I've probably just missed finding something. Any help? Thanks!

tyler mazaika's icon

AFAIK there isn't a way to get this information out of JSUI. But having done a fair bit of this myself, and been concerned with CPU impact I've tried to figure some concept of "best practices", here's what I've got...

1) I think the "paint()" function only ever executes if the device is visible in the currently selected track (unless you've put up a window with a jsui). You can verify this pretty easily using "post()" calls and some automatic redrawing in a jsui in an unselected track. As a result, if there are supporting calculations that really only need to be done at drawing time, its better to call those functions from inside paint().

Its not always a viable solution for time-based/history-tracking drawing elements. But it makes for an ok diaper allowing for suboptimal programming to not wreck things.

2) You can save a number of drawing calls if you can use cached images in mgraphics. For instance for a 'tab' style button, you can cache a "background" image of all buttons unselected, and then only redraw the selected button on the fly. You probably want to upscale images cached like this by 2x when drawing these and then downscale before you do image_surface_draw(), otherwise they look like sh** on "retina" displays.

3) You can do similar by caching of complex drawing paths using copy_path(), and then append_path() to re-use them.

4) Regardless of these optimizations, I would say that for reasons I don't understand just the canvas size seems to have a lot to do with overall drawing CPU usage, even if you're only using few or simple drawing commands. So then rate-limiting redraws is helpful. I've taken to using a Task() which I schedule after a completed redraw for ~30ms in the future that just evaluates a <shouldiredraw?> bool and calls mgraphics.redraw only if needed.


But if its a small UI you're making, you probably don't need to worry too much unless you're drawing is quite dense or is refreshing very rapidly.

And FWIW, I'm on macOS and I usually just use Activity Monitor to monitor CPU of Max / Ableton when drawing things. Its coarse, but you can a/b test solutions this way.