Any tips for better performance when using mxj?
I have an mxj external I have created (essentially a trigger sequencer, but with pattern morphing and pattern filters and a few other bits like bjorklund/euclidean pattern generation thrown in, internally it used BigInteger and lots of bitwise logic), anyway, I have spent hours lovingly crafting max for live devices so that I can use this java code to control drum racks and instruments in Live. Each track of the sequencer loads up 4 instances of the mxj to sequence various things. I can run about ten tracks before I start getting sloppy timing and audio dropouts (this is just firing samples in live, nothing fancy) on an 8 core Mac Pro. In total we are talking about forty mxj instances being banged around every 100ms.
Now, I am sure my code has plenty of room for optimisation but I was really surprised at how poorly it performed.
I prepared a fairly unscientific performance test outside of Max to test my code, I created a java test method (using JUnit) that creates 1000 instances of the class and then bangs each one of them and issues a morph command and generally gets it to do some work, it then sleeps for 10ms and does it again. This uses up around 90% of one cpu according to activity monitor, compared to around 150% when running in Live and is hitting my code several orders of magnitude more frequently (40/100ms vs 1000/10ms!).
Now, obviously there is a lot more going on when I run my mxj through Max For Live, but the difference I am seeing is huge.
So my question is, what actually happens when Max call out to java? Is there an expensive marshalling system that is really hurting my performance? What might be the low hanging fruit when trying to optimise performance? It is worth trying to reduce the number of times I move from Max to Java and back again for example?
If there are performance issues moving between max and java do these exist when using native c/c++ externals?
Hi Withakay !
Im feeling connected so i will answer .
Ive been going through the same issues some time ago . Unfortunately data flow that crosses between max and mxj require time/computation because it needs to call for Java environment at every input/output . Its similar with JS but not with C excternals whose are native to max .
Ive been implementing sequencer engine and i had timing issues due to communication between java and max or js in max . Its not recommended to use java/js for time sensitive operations . Beside optimizing your arrays, loops and reducing external functions call ,you cant do much more .
My decision was to the split engine into two parts . Java/Js for data maintaining (input/arrays) and max for note engine/triggering (output) .
Last weeks ive been implementing UI in JSUI for data input ,for computations (durations, positions ,events ) with help of Dict object (introduced to JS) which is used for retrieving appropriate data required by the sequencer engine implemented natively in max . it introduces no time lag as far as i can tell . That was the only way i could imagine it . And i did it in JS instead of JAVA because JAVA has no access to Dict object as far as i know .
Thanks for the reply.
I guess I am going to have to think about which way to turn next. c/c++ external route looks like it might be the best option for me atm.
What are you passing across the Max/Java boundary and how often?
Max for Live runs in overdrive and things like automation run at a high sample rate, so you might be getting hit on the MXJ boundary more than you think.
In my experience, Java performance gets clobbered by GC when the heap gets big – how much RAM do you have in your machine, and how big are your data structures (and how much are you mutating them)?
Mostly, I am passing in symbols that represent BigInteger values (i.e. stuff like ’0b101010010101′, but potentially much longer, gets parsed into a Java BigInteger for manipulation). If a BigInteger gets changed then I send back the new value as a string/symbol. My understanding is that symbols get put in a hash table and never expire, but from what I have read (including some posts from you Nick) this is not really a big deal in the short term, but might become an issue for long running patches (this one won’t be long running).
I have only been automating [live.text] in either button or toggle mode, so I doubt the automation is the issue (but a very good point for future reference).
I have 18GB of RAM in the machine I am working on (a Mac Pro fwiw), but I am using 32bit Max and Live for compatibility reasons (I am not sure if that affects the amount of memory that Java can use?).
I would guess that every time there is a call to the mxj it creates at least a few new BigIntegers per instance and I know these are immutable so I guess this leaves a lot of work for the GC to do. But still, run in isolation I can create thousands of instances and hit them every 10ms and see much lower CPU usage than running 48 instances via Max – obviously not a fair test but it at least suggests that the issues might be related to crossing the Max/Java boundary and not the actual Java code its self.
Next stage, I guess, is to throw a profiler at your JVM and see where it’s spending all its time…
Can you (or anyone) recommend an open source Java profiler? (I am more experienced with c#, I don’t do a great deal of Java day to day…)
having weighed up my options I just decided to re-implement my mxj as a native external using c++, it was not nearly as painful as I was expecting it to be (so far).
Performance is a lot better, I am easily running 5 times the instances without any audio dropouts or timing issues, although the gui does start to become pretty unresponsive.
Thanks for all the good ideas.
Hello, my first time in the Java forum. Glad I came and had a look here before I dived straight into Java development – I may go down the C/C++ route instead now.
P.S. – Hi Nick Rothwell – this is Patrick from the London Max/MSP Users Group.
P.P.S. – why is there no forum for C/C++ development? *EDIT* – ah, it’s called ‘Dev’.
:) why its called DEV by the way ?
// :) why its called DEV by the way ?
A guess from an oldster:
Historically, the only way to extend Max/Msp was with C/C++ . All other languages are wrapper style calling shells on the original C/C++ code. (And Jitter and Gen did not exist then):
all development of extensions to Max/Msp were in C/C++, so DEV was appropriate and fully inclusive title for forum issues with C/C++ development…
yes ,thanks . i found that "dev" term is typical description for c/c++ programming in general , outside the max world .as it stands for development , its even more clear to me now .
I’ve had a number of discussions in the past with Andrew Pask and he’s always warned me about the cost of crossing the MAX/Java boundary, saying that it is expensive, even compared with the MAX/JS boundary. I tend to write most stuff in JS now, especially as I do alot of M4L/LOM work which all runs in low pri thread anyway and is natively supported in JS, so I’m not losing anything…
Obviously the overall issue with JS is that it runs in the low pri thread and can be interrupted and deferred… This does mean that hybrid solutions tend to be the norm unfortunately…
It would be interesting to know why the ability to run JS in the high pri thread was removed from MAX 6 and whether this will return or not… I’m guessing this is due to change of JS engine, but would be nice if C74 could comment…. Anyhow, if we don’t get the ability to run JS in high priority then I fear JS is forever consigned to UI/human interaction stuff..
As for C/C++ the thing that just stops me doing this is supporting Windows and Mac and having to cross compile and address issues not reproducible on my native platform… I guess at the end of the day if any kind of timing is involved then this is what’s required
Nick – any comments on the JS implementation and limitations? thx
run 2 instances of the JS engine? restrict what can be done depending on instance, e.g. one in low priority thread can interact with patcher and use all the libraries etc and do nice MAXy stuff, the other is restricted to input, processing, and output and can run in the high priority thread – user can target which instance of the engine they want their code to run in…
I guess that’s a lot of work… ;)
whilst we’re on this subject here, anyone know how I can cross compile code from Windows to Mac?
Flext provides a common API into Max and PD, but doesn’t AFAIK advance much in terms of making code portable between OS X and Windows since that’s pretty easy to do with the standard SDK, and I don’t think it offers any kind of cross-compilation.
Seems there’s a lot of support for other platforms cross-compiling into Windows, but no the other way round.. Looks like VMWare is the route…
I can believe that – the Windows toolchain has always been more open than MacOS.
VMware Windows will certainly work for development, but you won’t be able to run the full version of Max: the PACE stuff will complain. Max Runtime will be fine though.
That’s interesting to know….thx What about M4L? (Assuming I can authorise Live, I’m checking with the Abes also…)
I’m guessing actually I won’t be able to run M4L thinking about it…. ugh…. no way to test code on Mac….