changeset 993:a8f5b91bcefc

generators: merge the @State override classes together, yields massive decrease in generated code size and compilation time.
author shade
date Tue, 02 Sep 2014 23:04:40 +0400
parents e7f0bf479bcf
children 24f2032b147c
files jmh-core/src/main/java/org/openjdk/jmh/generators/core/BenchmarkGenerator.java jmh-core/src/main/java/org/openjdk/jmh/generators/core/BenchmarkGeneratorSession.java jmh-core/src/main/java/org/openjdk/jmh/generators/core/Identifiers.java jmh-core/src/main/java/org/openjdk/jmh/generators/core/StateObject.java jmh-core/src/main/java/org/openjdk/jmh/generators/core/StateObjectHandler.java
diffstat 5 files changed, 151 insertions(+), 78 deletions(-) [+]
line wrap: on
line diff
--- a/jmh-core/src/main/java/org/openjdk/jmh/generators/core/BenchmarkGenerator.java	Tue Sep 02 16:57:46 2014 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/generators/core/BenchmarkGenerator.java	Tue Sep 02 23:04:40 2014 +0400
@@ -86,11 +86,13 @@
     private final Set<BenchmarkInfo> benchmarkInfos;
     private final CompilerControlPlugin compilerControl;
     private final Set<String> processedBenchmarks;
+    private final BenchmarkGeneratorSession session;
 
     public BenchmarkGenerator() {
         benchmarkInfos = new HashSet<BenchmarkInfo>();
         processedBenchmarks = new HashSet<String>();
         compilerControl = new CompilerControlPlugin();
+        session = new BenchmarkGeneratorSession();
     }
 
     /**
@@ -485,6 +487,17 @@
      * Create and generate Java code for a class and it's methods
      */
     private void generateClass(GeneratorSource source, GeneratorDestination destination, ClassInfo classInfo, BenchmarkInfo info) throws IOException {
+        StateObjectHandler states = new StateObjectHandler(compilerControl);
+
+        // benchmark instance is implicit
+        states.bindImplicit(classInfo, "bench", Scope.Thread);
+
+        // default blackhole is implicit
+        states.bindImplicit(source.resolveClass(Blackhole.class.getCanonicalName()), "blackhole", Scope.Thread);
+
+        // bind all methods
+        states.bindMethodGroup(info.methodGroup);
+
         // Create file and open an outputstream
         PrintWriter writer = new PrintWriter(destination.newClass(info.generatedName), false);
 
@@ -493,6 +506,7 @@
         writer.println();
 
         generateImport(writer);
+        states.addImports(writer);
 
         // Write class header
         writer.println("@Generated(\"" + BenchmarkGenerator.class.getCanonicalName() + "\")");
@@ -504,17 +518,6 @@
 
         writer.println(ident(1) + "int startRndMask;");
 
-        StateObjectHandler states = new StateObjectHandler(compilerControl);
-
-        // benchmark instance is implicit
-        states.bindImplicit(classInfo, "bench", Scope.Thread);
-
-        // default blackhole is implicit
-        states.bindImplicit(source.resolveClass(Blackhole.class.getCanonicalName()), "blackhole", Scope.Thread);
-
-        // bind all methods
-        states.bindMethodGroup(info.methodGroup);
-
         // write all methods
         for (Mode benchmarkKind : Mode.values()) {
             if (benchmarkKind == Mode.All) continue;
@@ -534,10 +537,7 @@
         writer.println();
 
         // Write out the required objects
-        for (String s : states.getStateOverrides()) {
-            writer.println(ident(1) + s);
-        }
-        writer.println();
+        states.writeStateOverrides(session, destination);
 
         // Finish class
         writer.println("}");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jmh-core/src/main/java/org/openjdk/jmh/generators/core/BenchmarkGeneratorSession.java	Tue Sep 02 23:04:40 2014 +0400
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jmh.generators.core;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class BenchmarkGeneratorSession {
+    public final Set<String> generatedStateOverrides = new HashSet<String>();
+}
--- a/jmh-core/src/main/java/org/openjdk/jmh/generators/core/Identifiers.java	Tue Sep 02 16:57:46 2014 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/generators/core/Identifiers.java	Tue Sep 02 23:04:40 2014 +0400
@@ -39,23 +39,20 @@
     private final Set<String> claimedJmhTypes = new HashSet<String>();
     private final Map<String, String> jmhTypes = new HashMap<String, String>();
 
-    public String getJMHtype(String type) {
-        String jmhType = jmhTypes.get(type);
+    public String getJMHtype(ClassInfo type) {
+        String id = BenchmarkGeneratorUtils.getGeneratedName(type);
+        String jmhType = jmhTypes.get(id);
         if (jmhType == null) {
             int v = 0;
             do {
-                jmhType = getBaseType(type) + (v == 0 ? "" : "_"+ v) + "_jmh";
+                jmhType = id + (v == 0 ? "" : "_" + v) + "_jmh";
                 v++;
             } while (!claimedJmhTypes.add(jmhType));
-            jmhTypes.put(type, jmhType);
+            jmhTypes.put(id, jmhType);
         }
         return jmhType;
     }
 
-    private String getBaseType(String type) {
-        return type.substring(type.lastIndexOf(".") + 1);
-    }
-
     public String collapseTypeName(String e) {
         if (collapsedTypes.containsKey(e)) {
             return collapsedTypes.get(e);
--- a/jmh-core/src/main/java/org/openjdk/jmh/generators/core/StateObject.java	Tue Sep 02 16:57:46 2014 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/generators/core/StateObject.java	Tue Sep 02 23:04:40 2014 +0400
@@ -42,6 +42,7 @@
         }
     };
 
+    public final String packageName;
     public final String userType;
     public final String type;
     public final Scope scope;
@@ -50,9 +51,10 @@
     public final Map<String, FieldInfo> params;
     public final SortedSet<HelperMethodInvocation> helpers;
 
-    public StateObject(Identifiers identifiers, String userType, Scope scope) {
-        this.userType = userType;
-        this.type = identifiers.getJMHtype(userType);
+    public StateObject(Identifiers identifiers, ClassInfo info, Scope scope) {
+        this.packageName = info.getPackageName() + ".generated";
+        this.userType = info.getQualifiedName();
+        this.type = identifiers.getJMHtype(info);
         this.scope = scope;
 
         String id = identifiers.collapseTypeName(userType) + identifiers.identifier(scope);
--- a/jmh-core/src/main/java/org/openjdk/jmh/generators/core/StateObjectHandler.java	Tue Sep 02 16:57:46 2014 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/generators/core/StateObjectHandler.java	Tue Sep 02 23:04:40 2014 +0400
@@ -38,6 +38,9 @@
 import org.openjdk.jmh.util.HashMultimap;
 import org.openjdk.jmh.util.Multimap;
 
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Writer;
 import java.lang.annotation.Annotation;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -50,6 +53,7 @@
 import java.util.Set;
 import java.util.SortedSet;
 import java.util.TreeSet;
+import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
 
 class StateObjectHandler {
 
@@ -91,7 +95,7 @@
             for (ParameterInfo ppi : method.getParameters()) {
                 ClassInfo pci = ppi.getType();
 
-                StateObject pso = new StateObject(identifiers, pci.getQualifiedName(), getState(pci, ppi).value());
+                StateObject pso = new StateObject(identifiers, pci, getState(pci, ppi).value());
                 stateObjects.add(pso);
                 args.put(method.getName(), pso);
                 bindState(method, pso, pci);
@@ -113,7 +117,7 @@
                 for (ParameterInfo pi : mi.getParameters()) {
                     ClassInfo ci = pi.getType();
 
-                    StateObject so = new StateObject(identifiers, ci.getQualifiedName(), getState(ci, pi).value());
+                    StateObject so = new StateObject(identifiers, ci, getState(ci, pi).value());
 
                     if (!seen.add(so)) {
                         throw new GenerationException("@" + State.class.getSimpleName() + " dependency cycle is detected.", pi);
@@ -133,7 +137,7 @@
 
     public void bindImplicit(ClassInfo ci, String label, Scope scope) {
         State ann = BenchmarkGeneratorUtils.getAnnSuper(ci, State.class);
-        StateObject so = new StateObject(identifiers, ci.getQualifiedName(), (ann != null) ? ann.value() : scope);
+        StateObject so = new StateObject(identifiers, ci, (ann != null) ? ann.value() : scope);
         stateObjects.add(so);
         implicits.put(label, so);
         bindState(null, so, ci);
@@ -730,73 +734,106 @@
         return new LinkedHashSet<StateObject>(linearOrder);
     }
 
-    public void addSuperCall(List<String> result, StateObject so, String suffix) {
+    public void addSuperCall(PrintWriter writer, StateObject so, String suffix) throws IOException {
         // These classes have copying constructor:
         if (so.userType.equals(BenchmarkParams.class.getCanonicalName()) ||
             so.userType.equals(IterationParams.class.getCanonicalName()) ||
             so.userType.equals(ThreadParams.class.getCanonicalName())) {
-            result.add("    public " + so.type + suffix + "(" + so.userType + " other) {");
-            result.add("        super(other);");
-            result.add("    }");
+            writer.println("    public " + so.type + suffix + "(" + so.userType + " other) {");
+            writer.println("        super(other);");
+            writer.println("    }");
         }
     }
 
-    public List<String> getStateOverrides() {
-        Set<String> visited = new HashSet<String>();
+    public void writeStateOverrides(BenchmarkGeneratorSession sess, GeneratorDestination dst) throws IOException {
 
-        List<String> result = new ArrayList<String>();
         for (StateObject so : cons(stateObjects)) {
-            if (!visited.add(so.userType)) continue;
+            if (!sess.generatedStateOverrides.add(so.userType)) continue;
 
-            result.add("static class " + so.type + "_B1 extends " + so.userType + " {");
-            Paddings.padding(result, "b1");
-            addSuperCall(result, so, "_B1");
-            result.add("}");
-            result.add("");
-            result.add("static class " + so.type + "_B2 extends " + so.type + "_B1 {");
+            {
+                PrintWriter pw = new PrintWriter(dst.newClass(so.packageName + "." + so.type + "_B1"));
 
+                pw.println("package " + so.packageName + ";");
 
-            for (Level level : Level.values()) {
-                result.add("    public volatile int setup" + level + "Mutex;");
-                result.add("    public volatile int tear" + level + "Mutex;");
-                result.add("    public final static AtomicIntegerFieldUpdater setup" + level + "MutexUpdater = " +
-                        "AtomicIntegerFieldUpdater.newUpdater(" + so.type + "_B2.class, \"setup" + level + "Mutex\");");
-                result.add("    public final static AtomicIntegerFieldUpdater tear" + level + "MutexUpdater = " +
-                        "AtomicIntegerFieldUpdater.newUpdater(" + so.type + "_B2.class, \"tear" + level + "Mutex\");");
-                result.add("");
+                pw.println("import " + so.userType + ";");
+
+                pw.println("public class " + so.type + "_B1 extends " + so.userType + " {");
+                Paddings.padding(pw, "b1");
+                addSuperCall(pw, so, "_B1");
+                pw.println("}");
+
+                pw.close();
             }
 
-            switch (so.scope) {
-                case Benchmark:
-                case Group:
-                    for (Level level : Level.values()) {
-                        result.add("    public volatile boolean ready" + level + ";");
-                    }
-                    break;
-                case Thread:
-                    for (Level level : Level.values()) {
-                        result.add("    public boolean ready" + level + ";");
-                    }
-                    break;
-                default:
-                    throw new IllegalStateException("Unknown state scope: " + so.scope);
+            {
+                PrintWriter pw = new PrintWriter(dst.newClass(so.packageName + "." + so.type + "_B2"));
+
+                pw.println("package " + so.packageName + ";");
+
+                pw.println("import " + AtomicIntegerFieldUpdater.class.getCanonicalName() + ";");
+
+                pw.println("public class " + so.type + "_B2 extends " + so.type + "_B1 {");
+
+                for (Level level : Level.values()) {
+                    pw.println("    public volatile int setup" + level + "Mutex;");
+                    pw.println("    public volatile int tear" + level + "Mutex;");
+                    pw.println("    public final static AtomicIntegerFieldUpdater setup" + level + "MutexUpdater = " +
+                            "AtomicIntegerFieldUpdater.newUpdater(" + so.type + "_B2.class, \"setup" + level + "Mutex\");");
+                    pw.println("    public final static AtomicIntegerFieldUpdater tear" + level + "MutexUpdater = " +
+                            "AtomicIntegerFieldUpdater.newUpdater(" + so.type + "_B2.class, \"tear" + level + "Mutex\");");
+                    pw.println("");
+                }
+
+                switch (so.scope) {
+                    case Benchmark:
+                    case Group:
+                        for (Level level : Level.values()) {
+                            pw.println("    public volatile boolean ready" + level + ";");
+                        }
+                        break;
+                    case Thread:
+                        for (Level level : Level.values()) {
+                            pw.println("    public boolean ready" + level + ";");
+                        }
+                        break;
+                    default:
+                        throw new IllegalStateException("Unknown state scope: " + so.scope);
+                }
+
+                addSuperCall(pw, so, "_B2");
+
+                pw.println("}");
+
+                pw.close();
             }
 
-            addSuperCall(result, so, "_B2");
+            {
+                PrintWriter pw = new PrintWriter(dst.newClass(so.packageName + "." + so.type + "_B3"));
 
-            result.add("}");
-            result.add("");
-            result.add("static class " + so.type + "_B3 extends " + so.type + "_B2 {");
-            Paddings.padding(result, "b3");
-            addSuperCall(result, so, "_B3");
-            result.add("}");
-            result.add("");
-            result.add("static final class " + so.type + " extends " + so.type + "_B3 {");
-            addSuperCall(result, so, "");
-            result.add("}");
-            result.add("");
+                pw.println("package " + so.packageName + ";");
+
+                pw.println("public class " + so.type + "_B3 extends " + so.type + "_B2 {");
+                Paddings.padding(pw, "b3");
+                addSuperCall(pw, so, "_B3");
+                pw.println("}");
+                pw.println("");
+
+                pw.close();
+            }
+
+            {
+                PrintWriter pw = new PrintWriter(dst.newClass(so.packageName + "." + so.type));
+
+                pw.println("package " + so.packageName + ";");
+
+                pw.println("public class " + so.type + " extends " + so.type + "_B3 {");
+                addSuperCall(pw, so, "");
+                pw.println("}");
+                pw.println("");
+
+                pw.close();
+            }
         }
-        return result;
     }
 
     public Collection<String> getFields() {
@@ -825,4 +862,9 @@
         return auxAccessors.get(method.getName() + name);
     }
 
+    public void addImports(PrintWriter writer) {
+        for (StateObject so : cons(stateObjects)) {
+            writer.println("import " + so.packageName + "." + so.type + ";");
+        }
+    }
 }