jGE Experiments
JavaCompiler vs. JikesCompiler
Speed Improvements on the Compilation/Execution of Java Code
The first version of the Evaluation component used the JavaCompiler class to evaluate the Java programs (phenotypes). This compiles (using the javac.exe compiler), and executes (using the java.exe runtime), once in each generation of a run, the dynamically created java source code which are the phenotypes of all the individuals of the population.
This is an extremely time consuming task and for problems such as Symbolic Regression this is the most important factor which effects the execution speed. In each Symbolic Regression experiment the compilation/execution is taking place once when a new run starts (for the creation of the sample data) and once in each generation (during the evaluation of the individuals of the population).
Although the time complexity with respect to the compilation/execution of java code is linear (Θ(N), where N is the number of generations of a run), it is a significantly time consuming task which can significantly degrade overall performance. Moreover, other problems will have a higher rate of growth of execution time if they need to frequently use the source code compilation and bytecode execution tasks.
For the above reasons, some experiments were conducted into alternative methods regarding the compilation and execution of java code. The experimental evidence (see below) leads to the conclusion that a much better solution than using javac.exe and java.exe is the following setup:
a) Use of the Jikes compiler (IBM) for the compilation of the java source code.
b) Utilization of the Dynamic Class Loading and Introspection features of the Java Virtual Machine (ClassLoader class and the Reflection API).
Jikes is an open source Java compiler written in the C++ language and translates Java source files into the bytecode instructions set and binary format defined in the Java Virtual Machine Specification. Jikes has the following advantages as noted in the official web site of the compiler:
- Open source.
- Strictly Java compatible.
- High performance.
- Dependency analysis.
- Constructive Assistance.
The Java ClassLoader is an important component of the Java Virtual Machine which is responsible for finding and loading classes at runtime. It is the part of the Java Virtual Machine that loads classes on demand into memory during the execution of a java program. Furthermore, it is written in the Java Language and can be extended in order to load Java classes from every possible source (local or network file system, network resources, etc.). Using both the ClassLoader and the Reflection API, it is possible to perform the loading of java bytecode and its execution from inside of any java program using the same instance (process) of JVM.
The above have been implemented in the JikesCompiler class of the jGE Library. The JikesCompiler class compiles java source code using the Jikes compiler and loads/executes the resulting bytecode using the FileClassLoader class and the Reflection API. Furthermore, it captures the standard output of the executed code by redirecting it in a StringBuilder object with the help of the CapturedOutputStream class. In the current version (v0.1), the jGE Library provides the option of using either the Sun JVM or the IBM Jikes for the execution and compilation of Java code.
Below are the results of the benchmarking of the JavaCompiler and the JikesCompiler. The following Java Code (Listing 1) was used for the benchmarking:
public class MainTest {
public static void main(String[] args) {
System.out.println("Hello World!");
double sum = 0;
for (int i = 1; i <= 100000; i++) {
sum += Math.pow(Math.sqrt(i) + Math.log10(i), 2);
}
System.out.println("Sum: " + sum);
for (int i = 0; i < 100; i++) {
if (i % 10 == 0) System.out.println();
System.out.print(i + " ");
}
System.out.println();
System.out.println("Hello World!");
}
}
Listing 1: MainTest Class for the Benchmarking of JavaCompiler and JikesCompiler classes
Benchmarking Results*
| |
Duration of the Compilation of the Source Code |
Duration of the Execution of the Bytecode |
| |
JavaCompiler |
JikesCompiler |
JavaCompiler |
JikesCompiler |
| Test 1 |
860 |
203 |
250 |
78 |
| Test 2 |
844 |
172 |
250 |
62 |
| Test 3 |
844 |
172 |
219 |
62 |
| Test 4 |
906 |
188 |
219 |
62 |
| Test 5 |
844 |
156 |
219 |
62 |
| Test 6 |
860 |
172 |
218 |
63 |
| Test 7 |
906 |
187 |
219 |
63 |
| Test 8 |
844 |
172 |
218 |
63 |
| Test 9 |
859 |
172 |
203 |
63 |
| Test 10 |
859 |
187 |
219 |
47 |
| |
|
|
|
|
| Average Results |
862,6 |
178,1 |
223,4 |
62,5 |
* Time is measured in milliseconds (msec)
Notes about the Benchmark:
The results of the execution time of each task have only a comparative value because they depend heavily on the underlying computer hardware, operating system, and configuration.
Also, they provide just an indication of the efficiency of the JikesCompiler class over the JavaCompiler class. No precise results can be extracted from only the above tests on how much faster the JikesCompiler class is compared to the JavaCompiler class. |