None of your results are too surprising to me. In JRuby, we moved
several structures from encapsulating an array to using
differently-sized "slotted" objects, with performance registering much
better as a result. Some of that was due to the lack of boundschecks
on the arrays, but another portion was probably due to the reduced
size of an object + reference versus object + reference + array.

Some comments inline below.

On Sun, Nov 1, 2009 at 7:48 PM,  <[email protected]> wrote:
> public class ArrayVsClass {
>
>  public static void main(String[] args) {
>  long lVectorStartTime = System.currentTimeMillis();
>  int iterations = Integer.MAX_VALUE;
>  while (iterations-- > 0) {
>  // int iterations2 = 10;
>   //while (iterations2-- > 0)
>   {
>       //testArray(); // ARRAY
>    // vs
>    //testGETFIELD(); // GETFIELD
>    // vs
>    testIBean(); // INVOKE INTERFACE
>    // vs
>    //testBean(); // INVOKE VIRTUAL
>    // vs
>    //testABean(); // INVOKE VIRTUAL POSSIBLY THROW
>    // vs
>    //testSlots(); // INVOKE FOR AVALUE
>   }
>  }
>  long lVectorRunTime = System.currentTimeMillis() - lVectorStartTime;
>  System.out.println("Bench time: " + lVectorRunTime);
>
>  }

Because of optimization effects, you should try running them all
together in the same benchmark in varying orders. Short benchmarks
like these can skew actual results because only a small subset of the
full code needs to be considered for optimization.

>  // SLOTS time: 33157,33250,33156
>  public static void testSlots() {
>  ClassWithSlots oneSlot = new ClassWithSlots(6);
...
>  // Array time: 18438,18437,18422
>  public static void testArray() {
>  final long[] accessArray = new long[] { 6 };

Not too surprising; you're paying the cost of the array plus the cost
of the virtual invocation. So even after inlining, you've got
something like boundscheck + deref + virtual call.

>  // GETFIELD time: 14688,14531,14453
>  public static void testGETFIELD() {
>  ClassWithOneSlot oneSlot = new ClassWithOneSlot(6);
...
>  // INVOKE VIRTUAL time: 14750,14594,14719
>  public static void testBean() {
>  ClassWithOneSlot oneSlot = new ClassWithOneSlot(6);

This is exactly the pattern we use in JRuby for heap-based scopes. We
have from ZeroVarDynamicScope up to FourVarDynamicScope and then it
falls over into an array-based version. Because we can statically tell
how many variable slots we'll need in most Ruby scopes, this ended up
being a big perf improvement for us.

>  // INVOKE INTERFACE time: 14469,14610,14859
>  public static void testIBean() {
>  IBeanWithOneSlot oneSlot = new ClassWithOneSlot(6);
>
>  int iterations = Integer.MAX_VALUE;
>  long result = 0;
>  while (iterations-- > 0) {
>   result += oneSlot.getValue();
>  }
>  }

invokeinterface ends up as fast as invokevirtual once it's been
inlined, so this is no surprise.

>  // INVOKE VIRTUAL POSSIBLY THROW time: 14641,14594,14547
>  public static void testABean() {
>  AClassWithOneSlot oneSlot = new ClassWithOneSlot(6);

Exception-handling paths not followed do not impact performance, so
this is also not surprising. Try having one out of the N invocations
trigger the exception and watch the perf change drastically from then
on.

- Charlie

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "JVM 
Languages" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/jvm-languages?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to