(newbie) java reflection pb

Feb 9, 2006 at 5:13pm

(newbie) java reflection pb

#24350
Feb 9, 2006 at 5:30pm

#70299
Feb 9, 2006 at 5:54pm

I just found it also. It works like a charm.

Thanks for the explanations.
ej

#70300
Feb 9, 2006 at 6:23pm

Hi Emmanuel,

Glad you solved your problem. Since it seems like you are doing this
for speed reasons, I thought I would mention that I’ve read that the
reflection API is very slow. You may want to benchmark these three
different solutions:

1. the reflection solution you’ve already got working,
2. the if / else switching code you were trying to avoid,
3. the interface design pattern. Your interface would look something like this:

public interface ListOperator {
public float[] operate(float a[], float b[]);
}

and the addition class would look something like this:

public class ListAddition implements ListOperator {
public float[] operate(float a[], float b[])
{
…..
}
}

and then in your MaxObject’s constructor you could create an instance
of the operator requested:

ListOperator myListOperator;

public simpleOp(Atom[] args)
{
declareIO(2,1);
myListOperator = new ListAddition();
}

and call it like so in your float method:

public void inlet(float f[])
{
if (getInlet() == 1)
b = f;
else {
a = f;

outlet(0, myListOperator.operate(a,b));
}

This is the standard Java design pattern for this type of problem and
I suspect it will be the fastest.

Ben

#70301
Feb 9, 2006 at 6:54pm

Hi Ben,

Thanks for the suggestions. I’ll try to test the different versions
soon. But, to be sure I understand correctly, with the interface
solution, I still need a “big” if/else to do the List operator
choice, right?

if (op.equals(“+”))
myListOperator = new ListAddition();
else if (op.equals(“-”))
myListOperator = new ListSoustraction();

Best,
ej

#70302
Feb 9, 2006 at 6:59pm

> Thanks for the suggestions. I’ll try to test the different versions
> soon. But, to be sure I understand correctly, with the interface
> solution, I still need a “big” if/else to do the List operator
> choice, right?

yes, but just in the constructor, not in the method that handles incoming lists.

Another place to look for ideas of how you might set up your code is
the ListProcessor stuff I made for the initial Max 4.5 release.

Ben

#70303
Feb 9, 2006 at 7:10pm

#70304
Feb 9, 2006 at 7:15pm

I also was just reading some stuff that faster reflection is possible
using the sun.misc.Unsafe class. This class is pretty interesting and
lives up to its name!
Topher

#70305
Feb 9, 2006 at 8:10pm

> I’ll look at it more slowly. Just one thing about this package, I use
> a lot, is there any possibility to rename list.sum and list.delta in
> list.Sum and list.Delta. There’s just two classes with the first
> letter un lowercase.

Yeah, sorry about that. Can’t rename them anymore, since they could
be used in other people’s patches, but feel free to rename your local
copies. :)

Ben

#70306
Feb 9, 2006 at 8:41pm

i am pretty sure you would have to rename and recompile if you take
that route.
toph

#70307
Feb 9, 2006 at 10:27pm

> i am pretty sure you would have to rename and recompile if you take
> that route.

Yes, and change the constructor code to be capitalized. I am so used
to Eclipse, which would not only rename and modify the code for that
class appropriately, it would also look through all the projects in
your workspace to rename the class anywhere else it was used. The
ability to refactor as easily as that is a big reason I like
developing in Java.

Ben

#70308
Feb 10, 2006 at 2:35pm

#70309
Feb 10, 2006 at 4:30pm

> On the list operator problem, I made the different versions (with if,
> with reflection, with interface).
> http://www.e–j.com/beta/lop-tests.zip
>
> The performances (measured in Max) are quite the same (the interface
> solution is generally a little bit faster). Is there any better
> strategy to evaluate the speed of the java code?

Yes, there is something very important here to understand. When you
are testing a piece of code for speed it is important to isolate it
from as much other code as possible. In the test patch that you set
up, the reason the three Java classes were so close in execution time
is that the test time was completely dominated by the slow boundary
crossing between Java and C. In other words, it’s very important to
avoid all inlet and outlet calls when testing various pieces of Java
code against one another.

I’ve attached a new lop-tests.zip. I added an “iterations” attribute
to each class, I added a calculeResultat() method to each class that
calculates the result but doesn’t output it, and I added an iterate()
method that uses a for loop to call the calculeResultat() method
iterations times. I modified the patch so that the same lists were
sent to all three Java objects, and then the iterate method is called
on all three.

To give you an idea of the difference in speed between internal Java
calculations and the boundary crossing of inlet and outlet calls, with
your old method 5 iterations were taking about 210 ms on my computer.
With my new method, 60000 iterations take 254 ms using reflection, 247
ms using if statements, and only 212 ms using the Interface design
pattern. So it looks like the Interface design pattern is
significantly faster.

But on the other hand – and this is probably the most valuable thing
to keep in mind when working with Java for small utility objects like
this – in the context of a patch, the execution time of this object
will be completely dominated by the input/output boundary crossing
between Java and C. So unless you’re doing a LOT of math in response
to input messages, it’s really not worth the time to highly optimize
your Java code, because you probably won’t notice the difference
anyway. For example, according to this test using the Interface
design pattern instead of Reflection will save you 0.7 MICROSECONDS
every time you want to multiply some lists together.

To make the most of your Max programming time, write Java code that
works and is easy to read.

> The problem with the interface solution is that
> you get a lot a class files.

Yeah, I know, this is an unfortunate. One way to deal with this is to
bundle class files into a JAR file.

Ben

#70310
Feb 10, 2006 at 5:33pm

#70311
Feb 10, 2006 at 6:23pm

> the reason the three Java classes were so close in execution time
> is that the test time was completely dominated by the slow boundary
> crossing between Java and C.

i really wish there was something we could do about this. thats why
i was looking at sun.misc.Unsafe. sigh.

topher

#70312
Feb 10, 2006 at 6:39pm

#70313
Feb 10, 2006 at 9:56pm

> > the reason the three Java classes were so close in execution time
> > is that the test time was completely dominated by the slow boundary
> > crossing between Java and C.
>
> i really wish there was something we could do about this. thats why
> i was looking at sun.misc.Unsafe. sigh.

Well actually it’s not as bad as I thought. :) I took another look at
Emmanuel’s patch and classes. There is an important thing that can
change to improve the performance by a lot.

inlet(float[]) and inlet(int[]) are optimized and are faster than
inlet(Atom[]). I just tested it out, and this small change reduced
the time taken to process an inlet call by almost 65%. In other
words, according to my unscientific test inlet(Atom[]) is three times
slower than inlet(float[]) and inlet(int[]).

With this trick in place, performance is pretty good. The object
takes in two lists, processes, and sends out a list in somewhere
between 20 and 60 microseconds. That includes all the surrounding C
objects doing their timing work.

Ben

ps. outlet(float[]) and outlet(int[]) are similarly optimized over
outlet(Atom[])

#70314
Feb 10, 2006 at 10:00pm

Not really much documentation on this one.

in the console:

javap sun.misc.Unsafe

topher

#70315
Feb 10, 2006 at 10:15pm

Cool Ben.
The inlet stuff explains some other behavior someone was telling me
about!

> ps. outlet(float[]) and outlet(int[]) are similarly optimized over
> outlet(Atom[])

as are outlet(String msg, float[]), outlet(String msg, int[])!

Toph

#70316
Feb 11, 2006 at 9:34am

Hi,

> inlet(float[]) and inlet(int[]) are optimized and are faster than
> inlet(Atom[]). I just tested it out, and this small change reduced

does the measurements exclude the time for creating Atom[] and int[] ?
because creating an array of atom of int seams longer than creating an
int array.

regards,
chris

#70317
Feb 11, 2006 at 5:37pm

> does the measurements exclude the time for creating Atom[] and int[] ?
> because creating an array of atom of int seams longer than creating an
> int array.

Well yes, because the test was comparing the performance of inlet
calls. So it is faster for the mxj C code to create an array of ints
or floats than it is for the code to create an array of Atoms.

Ben

#70318
Feb 11, 2006 at 6:00pm

#70319
Feb 11, 2006 at 6:06pm

#70320
Feb 11, 2006 at 6:40pm

Hi,

> You mean list(float[] something), don’t you?

Yes, sorry.

> By the way, I though list method could
> only accept atoms, as suggest the MaxObject.html.

Thanks for mentioning this – I see that MaxObject was not updated the
way it should have been when the optimization for list(float[]) and
list(int[]) was added. I’ll address this shortly.

Ben

#70321

You must be logged in to reply to this topic.