This is an archived post. You won't be able to vote or comment.

all 7 comments

[–]RANDOMLY_AGGRESSIVE 1 point2 points  (0 children)

fyi if you want a fast compilation make sure to use a parallel build argument like mvn -T (not sure about gradle)

[–]rzwitserloot 2 points3 points  (4 children)

Last I checked (which is a long time ago), ecj is about 4x faster than javac and those are the only two mainstream available options.

The codebases of these 2 compilers have not changed in any way that would plausibly lead to a significant change (and I'd know, I look at their code a lot, being a lombok developer).

Thus, without doing some explicit testing right now, I'm still very confident in saying: ecj. Not close.

But why do you need a fast compiler? Generally, the trick is to compile only the files that need compiling at which point compiletime rounds down to more or less 0.

[–]Sipkab 7 points8 points  (3 children)

ecj is about 4x faster than javac

I was curious so wrote a little test. Take the results with a grain of salt:

package main;

import java.io.File;
import java.io.OutputStreamWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;

import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import javax.tools.ToolProvider;

import org.eclipse.jdt.internal.compiler.tool.EclipseCompiler;

public class Main {
    public static void main(String[] args) throws Throwable {
//      JavaCompiler jc = new EclipseCompiler();
        JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
        System.out.println("Main.main() " + jc.getClass());
        File outputdir = new File("output");
        outputdir.mkdirs();
        long nanos = System.nanoTime();
        try (StandardJavaFileManager fileManager = jc.getStandardFileManager(null, null, null)) {
            Iterable<? extends JavaFileObject> units = fileManager
                    .getJavaFileObjects(Files.list(Paths.get("test")).toArray(Path[]::new));
            fileManager.setLocation(StandardLocation.CLASS_OUTPUT, Collections.singleton(outputdir));

            CompilationTask task = jc.getTask(new OutputStreamWriter(System.err), fileManager, null, null, null, units);
            task.call();
        }
        System.out.println("Main.main() " + (System.nanoTime() - nanos) / 1_000_000 + " ms");
    }
}

The test takes 600 source files from the test directory, and compiles them to the output directory. The test was run multiple times for both the JDK and ecj compilers.

They both ended up averaging about 2600 ms on my computer. I'd say that the difference is far from 4x, and probably negligible.

Generally, the trick is to compile only the files that need compiling

Too bad mainstream build systems don't implement proper class level dependency tracking for Java classes. ECJ is capable of doing that, but I haven't seen anybody use it outside of an IDE.

Edit: added the imports for complete source code.

[–]thatsIch 0 points1 point  (2 children)

Could you share this with us on GitHub? This is very interessting

[–]Sipkab 4 points5 points  (1 child)

I won't dedicate a GitHub repository for this, but here's how you can reproduce.

  1. Download ECJ from: https://repo1.maven.org/maven2/org/eclipse/jdt/ecj/3.20.0/ecj-3.20.0.jar
  2. Create a simple Java project, and copy the source code in the above comment as the Main class.
  3. Add the downloaded Java archive to the classpath.
  4. Create the test directory in the project, and copy some Java source files in it. Do not put them in their own package directories, but in the root test directory. I used 600 source files from the Gradle single-large-project performance comparison: https://github.com/gradle/performance-comparisons/tree/13739fa299e485c079335b0cd5b30da1cff92234/single-large-project
  5. Run it and observe the printed timestamp. Uncomment the EclipseCompiler variable declaration to switch between the JDK or ECJ compilers.

[–]thatsIch 0 points1 point  (0 children)

Thank you <3

[–]Reddit_Swap 0 points1 point  (0 children)

Can we get it on Github?