Showing posts with label JVMIT. Show all posts
Showing posts with label JVMIT. Show all posts

Friday, August 15, 2008

A Java-near-speed Groovy

Almost 2 months that I have not posted here. I'm still in the final phase of Google Summer of Code. The world is going to be wonderful when you have got a really good result from your hard work, is that right ?

I'm currently be able to make Groovy speed step closer to Java. It's a high aim, and it's clear to be possible with JVMIT now. I was working on optimising callsites, but could not find a way to make it faster than Alex T.'s implementation because he did really good job of implementing it. So I went back to look at my old GJIT code. What I found is that something had been fooling my eyes for almost a year. There is a way to avoid JVM 6 specific code to implement an agent for JVM 5. Then I re-read AspectJ source again, and found something useful. I has started to re-write a GJIT agent for JVM 5 from then.

My prototype of the second generation of GJIT was done with Soot framework, where I really learned a lot of useful optimisation tricks (e.g., SourceValue). Later, I found that Soot is not suite for implementing JIT, because of 1. it's somewhat big structure 2. it's class loading problem. I then have had to implement a whole thing using ASM. It really was a nightmare because there is no Jimple to help your analysis. I re-wrote at least 3-4 version of ASM optimisers, and finally got the current one, which has a good enough structure to patch.

Now my goal is to beat all shootout benchmarks. Here's the result from partial sums benchmark compared with Java on my machine.


$ export JAVA_OPTS="-server"
$ time `java -cp bin alioth.PartialSumsJ 5000000`
real 0m10.246s
user 0m0.030s
sys 0m0.015s

$ time `groovy.bat test/partial_sums.groovy 5000000`
real 0m27.110s
user 0m0.030s
sys 0m0.016s

$ time `groovy.bat test/alioth/PartialSums.groovy 5000000`
real 0m28.409s
user 0m0.030s
sys 0m0.015s

$ export JAVA_OPTS="-server
-javaagent:C:\\groovy-ck1\\healthy\\target\\install\\lib\\gjit-0.1.jar"
$ time `groovy.bat test/alioth/PartialSums.groovy 5000000`
real 0m13.434s
user 0m0.030s
sys 0m0.030s



It's 200% faster than current Groovy, and ~20-30% slower than Java. There's still room to go. I hope to take some more steps closer to Java's speed.

Wednesday, August 08, 2007

Possible JIT for Groovy with JVMTI

Nothing involves Groovy bytecode analysis at the moment, but I show you here the possible way to re-define a Java class with a Java 6 JVMTI agent. Yes, I say Java 6 as Java 5 does not support class re-definition through java.lang.instrument package.

As you might know, several AOP systems, that enable load-time weaving, use class transformation at load-time to weave aspects to the existing programs. They use a java JVMTI agent to achieve this.

Now in Java 6, you can do a bit more further as it offers method

Instrumentation.redefineClasses(ClassDefinition[] defs);




I'm experimenting this technique with a normal class, here:

package org.groovy.git.test;

public class TestClass {

public void myMethod(){
System.out.println("a");
}
}



The re-definition process is performed just to change a TestClass object from printing "a" to printing "b".


package org.groovy.git.test;

import java.lang.instrument.ClassDefinition;
import java.lang.instrument.Instrumentation;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;

import org.groovy.git.Agent;

public class AgentTest {

public static void main(String[] args) throws Exception {
// get an instrumentation from the agent
Instrumentation i = Agent.getInstrumentation();

// here, print "a"
TestClass t1 = new TestClass();
t1.myMethod();

// doing bytecode manipulation,
// replace a new method body for "myMethod"

CtClass ct = ClassPool.getDefault().get(TestClass.class.getName());
CtMethod m = ct.getDeclaredMethod("myMethod");
m.setBody("{ System.out.println(\"b\");}"); // make it printing "b"
byte[] bytes = ct.toBytecode();

// prepare a new class definition
ClassDefinition[] def=new ClassDefinition[1];
def[0] = new ClassDefinition(TestClass.class, bytes);
i.redefineClasses(def);

// this shows "b"
TestClass t2 = new TestClass();
t2.myMethod();
}

}



You might see that the above code get instrumentation from the Agent class, which is in a jar loaded by -javaagent:jarfile. In this experiment, I use Javassist for bytecode manipulation.

As you expected, the above code will show:

a
b


as the TestClass has been re-defined and its method, myMethod, body's been replaced.