performance degeneration from jdk7u2 to jdk7u6?

Jochen Theodorou blackdrag at gmx.org
Thu May 24 01:38:11 PDT 2012


Am 23.05.2012 23:33, schrieb Rémi Forax:
> On 05/23/2012 07:50 PM, Jochen Theodorou wrote:
>> no one helping me on the assembly analysis?
>
> Wow, you have generated the biggest fib function I have ever seen.
>
> About the bytecode you generate, as you said you have to remove
> $getCallSiteArray() because it seems it does some side effects
> so the JIT is not able to remove it.

the first time an array is generated, later nothing happens anymore... 
but yes, this has to go.

> I don't understand why when you call fib in the body of fib,
> you are not able to say that the signature is (Object)I. You detect
> that this is a recursive call (you don't use the same BSM)
> but it seems you think that because fib can be changed
> using the meta object protocol, you should type it (Object)Object.
> But because you are in already fib, you already suppose that
> at least the return type is int. Basically, you can change
> the method fib when being in the middle of the execution of fib,
> because at least one call of fib is on the stack,
> the new method must have a return type which is compatible with fib.

the method signature is (I)I, it is called with Object in the body, 
because I cannot ensure that x-1 and x-2 will return an int. Since I 
cannot know for sure that fib(I)I is called, the result of the recursive 
fib call is seen as Object. All I know for sure is that the result of 
"fib(x-1)+fib(x-2)" will be converted to an int later and will cause an 
exception if the conversion is not possible. But that is the result of 
the plus, thus you don't exactly need a compatible return type for fib. 
In for example:

int fib(int x) {
   if (x<2) return 1
   this.metaClass.fib = {int i -> i==1?"Forax":"Remi "}
   String.metaClass.plus = {String b -> delegate.length()+b.length()}
   return fib(x-1)+fib(x-2)
}
assert fib(3)== 10

I replace fib inside fib with, well it returns a String, but signature 
wise I replace it with a method returning Object. String is not 
compatible with int. And it does not lead to an exception because I also 
replace String#plus with a version that simply returns the added length 
of both Strings. So fib(3) will call fib(2) and fib(1), which has the 
results "Remi " and "Forax". Then I call plus on those results, leading 
to String#plus, which returns the added lengths, which is 10 and 
compatible with int.


> Also, you should never use methods like
> |DefaultTypeTransformation.intUnbox|
> because you know that the return type is an int, you should
> back-propagate it and the return type of plus should be (Object;Object)I

in the original example that is true, yes. That may allow to skip at 
intUnbox call... but only if I later select a plus method that returns 
int or Integer. In a different thread I already asked for requirements 
in that direction and that I get very differing results depending on 
what signatures I use. No I have at lest the hint, that returning int or 
Integer might be a good idea.

> Now, the generated code, because of getCallSiteArray(),
> your real code starts at line 168 and here you start
> to box the two ints to two Integers to be able to call
> NumberMath.subtract(Number,Number) which call
> IntegerMath.substractImpl that unbox them.
> The VM is not able to remove calls to box / unbox for j.l.Integer.

I see... unfortunate.

> You should generate a must simpler path here.
> You should never call a class like g.r.typehandling.*Math because
> all of these methods takes Numbers as parameters.
> You should create one simple class, with methods like this:
>     static int add(int left, int right) {
>       return left + right;
>     }
> because it doesn't force you to do the boxing.
> So you will do the boxing only if it's necessary, i.e. only
> when the parameter is Object.
> And to now which method you have to call, instead of
> relying on getMath() you should use guardWithTest and
> test only parameters that are Object.

Object is pretty often the case. Well if I count boxing and unboxing for 
(a+b)+(c+d), then now I have to box a to d, unbox for the add, box the 
result, no boxing for the outer plus call, but two unboxing and a boxing 
for the result and... if the method returns int, a final unboxing. That 
makes 7 boxing and 7 unboxing.

If I use your add(II)I and backpropagate the return type, then I have 
one boxing each for the inner pluses, two unboxing for the outer plus. 
Totals to 2 boxing, 2 unboxing. Sounds better... even without 
backpropagating the call. I will try that out.

bye Jochen

-- 
Jochen "blackdrag" Theodorou - Groovy Project Tech Lead
blog: http://blackdragsview.blogspot.com/
german groovy discussion newsgroup: de.comp.lang.misc
For Groovy programming sources visit http://groovy-lang.org



More information about the mlvm-dev mailing list