Gen patch spacial arrangement = different performance?
I've encountered a weird behaviour. If I have two gen patches with the same exact code, their location influences the CPU usage. The one on the right is always faster (less CPU expensive) than the one on the left, almost half.
Is it expected or am I missing something?
the feature in the inspector for "Measure CPU Usage" is not always exact, you have to mouse over and over it to get it to poll. when i check out your patch, i can get both to drop to around the same CPU value of 0.000057 by continually revolving my mouse around that area to keep it polling:
seems this feature is not the most accurate, and is meant more for a general/relative measure of performance.
for now, i guess i'd just be careful if you're measuring this(the one to the farthest-left [edit- and also, even just one by itself] will sometimes show too large a value and each one can be polled to show a more correct value if you keep mousing over and over the field in the inspector).
hope it helps 🍻
Hey Cycling74, maybe this is a bug?
EDIT - IT IS A BUG! it happens even with just one
in case anyone needs a bug report:
Problem: gen~ patchers do not show accurate cpu measure within their inspector.
Steps To Reproduce:
1) create a gen~ patcher, ideally with some simple math within a codebox, and duplicate it, placing the duplicate to the left of the original
2) go into inspector for both gen~ patchers and activate 'Measure CPU Usage'
3) within inspector of one gen~ patcher, attempt to poll for the cpu value by mousing over the 'show cpu usage' field repeatedly, and notice the value displayed
4) go into inspector of other gen~ patcher, attempt to poll for cpu value there in the same way as in step 3, and notice the value displayed
5) now delete one of the gen~ patchers
6) go into the inspector of the remaining gen~ patcher, attempt to poll for cpu value same as in steps 3 and 4 and notice the value displayed
Results: The value displayed in 'show cpu usage' field of the inspector of a gen~ patcher will show an inaccurately wide range of value. When creating multiple gen~ patchers containing the same ops, the gen~ patcher to the farthest-left will show the inaccurate value, while the ones to the right will be more accurate.
Expected Results: gen~ patchers which contain the same exact operations, should measure the same cpu value(or at least, not vary as widely as 200%)
Additional Info: when instantiating more than two gen~ patchers in the same patch, it's always the gen~ patcher to the farthest-left which shows an erroneous value, but the value never seems to go higher than twice the expected value(example: i created two gen~ patchers with same ops, one measured 0.000057 the other 0.000114(sometimes when mousing over it, this one changed to 0.000057 too), then i created a third, and the third one to the farthest-left now still reports as high as 0.000114, while the other two(including the one that used to register too wide a value) then remain close to 0.000057).
also, while it seems to be a problem with simple/object ops too, it's made most apparent with functions written into codebox.
in case cycling74 doesn't see it,
anyone can additionally file the proper
bug report here -> https://cycling74.com/support/contact
It is not a bug.
But I think it may be interesting to look at what is really going on here.
Audio processing in MSP runs in blocks of audio, whose size is the "signal vector size" as reported in the audio status window. Let's say this is 64, and the current sampling rate is 48000Hz. That means one block every 64/48000 seconds, which is every 1.3333ms. That means that the entire audio processing of the Max/MSP patch has to complete 64 samples of audio within 1.3333ms, to avoid there being any audio dropouts.
Now, the CPU thread that is actually doing audio processing will wake up roughly every 1.3333ms and do all of the computations necessary to produce these 64 samples of audio required. Once it wakes up it work as fast as it can (unless it gets interrupted). So, we can check the time when the audio thread wakes up to do its work, and then check the time once it has produced all of the 64 samples, and the difference should tell us how long we were working to generate those 64 samples.
Let's say it takes only 0.1ms to actually produce those 64 samples. That's 1/13th of the available time, or 7.5%. That's what the CPU % in the Audio Status window tells you -- effectively telling you how much of the available time (which is 1.333ms for 64sigvs and 48kHz samplerate) it actually takes to do what it needs to do.
The fact that this number is not stable, even though the amount of computation to perform is the same, shows you something about how modern CPUs work -- mostly it is varying because there are other CPU threads doing other work at the same time, and sometimes this interrupts the CPU thread that is doing the audio processing. The CPU tries to balance the work between threads, and sometimes this means it takes time away from the audio thread. This is all happening at nanosecond scales of time by the way.
The "Measure CPU usage" attribute of a gen~ object does more or less the same thing, but only for 1 object: it gets the current system clock time when the gen~ object is told to generate the next 64 samples, and gets the system clock time again when the 64 samples have been generated. The difference is how long gen~ took to produce those samples. This is then divided by the available time (1.3333ms) to get the ratio of available CPU time used. If the measurement is 0.000057, then 0.000057 * 1.3333ms = 0.000076ms, or 76 nanoseconds. That's how long gen~ took to produce 64 samples of `out1 = in1*0.5`.
But, as noted above, your computer's CPU is doing lots of other things at the same time, in lots of threads and fibers etc., and sometimes that means the audio thread in Max gets a little more micro-interruptions than other times. That's why the CPU usage wobbles around. But wobbling between 76 nanoseconds and 152 nanoseconds shouldn't be of any concern!
I tried switching out the gen~ patchers to include the freeverb
abstraction inside each one, so that they have a bit more work to do. I'm seeing the CPU measurements varying between 0.0099 and 0.0015 on my machine. At 64 sigvs and 48kHz samplerate this means it is varying between about 0.0013ms and 0.002ms. Again we are talking a difference of a few hundred nanoseconds. I don't see a particular difference between the left and the right patches in terms of performance.
OK the last part -- why would it matter whether the patch is on the left or the right? Actually I think it probably doesn't, but it might matter what order they come in the signal graph, which in this case (because neither is dependent on the other) is probably determined by which gen~ object was created first. When the audio thread gets woken up to process all the objects in the Max patch and generate the next 64 samples, it goes through the MSP objects one by one according to their processing order in the audio graph. Perhaps the audio thread is more or less likely to be interrupted when it just starts up, and that is why one of your gen~ objects seems to be more susceptible to taking up to a few nanoseconds more to complete than the other? I don't know.
But assuredly, the actual machine code generated for both will be identical. The only factor in play here is the nature of modern computer CPUs, which is that performance can be somewhat unpredictable. Or, it could also be a limitation in the accuracy of the request for the system clock time -- we are talking nanoseconds here.
But don't take my word for it. Here's a patch with two identical gen~ objects in them, and the calculations of the CPU time they use, and the difference between these expressed in nanoseconds.
On my computer here sometimes it is negative, sometimes positive, which means sometimes one gen~ finishes quicker, sometimes the other does. And sometimes the difference is zero. The variance is about +/- 300 nanoseconds, less than one millionth of a second.
sorry but irrepressible: gen~ like a FPGA in an ocean full of systemic rogue waves :-)
oups