long classpaths and JDK-8162492

Liam Miller-Cushon cushon at google.com
Tue Dec 13 04:18:17 UTC 2016


I noticed a performance regression with long classpaths and large numbers
of sources. This is related to JDK-8162492, but the benchmarks in that bug
are for long classpaths with a single source file, and my proposed fix
doesn't address that.

Under JDK 9 I'm seeing compilation time scale as the product of the
classpath length and the number of calls to getFileObject or list. The
example below takes 17s with JDK 8 and 8m40s with JDK 9.

I think the issue is with the cache strategy in ArchiveContainer.
ArchiveContainer calls Files.exists for each path and caches the result,
but if it's queried for a large number of distinct paths it doesn't get
cache hits, and ends up doing a lot of work.

I'd like to propose bringing back the cache strategy that was used in
ZipArchive:
http://hg.openjdk.java.net/jdk8/jdk8/langtools/file/1ff9d5118aae/src/share/classes/com/sun/tools/javac/file/ZipArchive.java#l73.
ZipArchive scans all entries in the zip once, and puts the directory names
in a cache. If getFileObject/list are called many times with paths that
aren't in the archive it doesn't have to do any work, and the cache stays
small.

I have a couple of question about how to proceed:

- does bringing back the ZipArchive-style cache sound reasonable, or are
there other advantages to the new approach used in ArchiveContainer?

- should I add this to JDK-8162492, or does it deserve a separate bug?


Here's the repro -

generate the test inputs (start in a fresh directory):

$ javac -cp asm.jar Test.java && java -cp asm.jar:. Test

compile:

$ $JAVAC8 -fullversion
javac full version "1.8.0_122-ea-b04"
$ time $JAVAC8 @params.txt
real 0m17.385s
user 0m40.855s
sys 0m1.305s

$ $JAVAC9 -fullversion
javac full version "9-ea+148"
$ time $JAVAC9 @params.txt
real 8m40.530s
user 32m8.614s
sys 0m57.024s

=== Test.java ===
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
import static org.objectweb.asm.Opcodes.ACC_SUPER;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import org.objectweb.asm.ClassWriter;

class Test {

    static final int JARS = 1000;
    static final int CLASSES = 100;
    static final int SOURCES = 1000;

    public static void main(String[] args) throws Exception {
        List<String> jars = new ArrayList<>();
        for (int i = 0; i < JARS; i++) {
            String jarName = "lib" + i + ".jar";
            jars.add(jarName);
            try (JarOutputStream jos =
                    new
JarOutputStream(Files.newOutputStream(Paths.get(jarName)))) {
                for (int j = 0; j < CLASSES; j++) {
                    String name = String.format("b%d%d/B%d%d", i, j, i, j);
                    jos.putNextEntry(new JarEntry(name + ".class"));
                    ClassWriter cw = new ClassWriter(0);
                    cw.visit(52, ACC_PUBLIC | ACC_SUPER, name, null,
"java/lang/Object", null);
                    jos.write(cw.toByteArray());
                }
            }
        }
        List<String> sources = new ArrayList<>();
        for (int i = 0; i < SOURCES; i++) {
            StringBuilder sb = new StringBuilder();
            sb.append(String.format("package a%d;\n", i));
            sb.append(String.format("class A%d {\n", i));
            for (int j = 0; j < CLASSES; j++) {
                String name = String.valueOf((i + j) % JARS) + j;
                sb.append(String.format("b%s.B%s x%d;\n", name, name, j));
            }
            sb.append(" }\n");
            String file = String.format("A%d.java", i, i);
            sources.add(file);
            Files.write(Paths.get(file), sb.toString().getBytes(UTF_8));
        }
        List<String> params = new ArrayList<>();
        params.addAll(sources);
        params.add("-cp");
        params.add(String.join(File.pathSeparator, jars));
        Files.write(Paths.get("params.txt"), params, UTF_8);
    }
}
===
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20161212/48943a24/attachment-0001.html>


More information about the compiler-dev mailing list