1 /*
   2  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test VTBufferTest
  26  * @summary Value Type interpreter value buffering test
  27  * @library /test/lib
  28  * @build ValueTypeGenerator
  29  * @run main/othervm -Xint -XX:+EnableValhalla VTBufferTest generate-and-run
  30  * @run main/othervm -Xint -XX:+EnableValhalla -XX:ValueTypesBufferMaxMemory=0 VTBufferTest generate-and-run
  31  * @run main/othervm -Xint -XX:+EnableValhalla -XX:BigValueTypeThreshold=196 VTBufferTest generate-and-run
  32  */
  33 
  34 /* This test generates its source code.
  35  * To reproduce a run (for instance to investigate a failure), look at
  36  * the test output and search for a line starting with "Seed=". The value
  37  * at the end of the line is the seed used to generate the test.
  38  * It possible to re-generate the same test with the following commande
  39  * line:
  40  *  $ java <VMOptions> VTBufferTest generate-and-run -seed <seed>
  41  * where <seed> is the seed value from the test output.
  42  * The test source code is generated in the current directory with
  43  * names Value[0-9][0-9].java and Loop.java.
  44  * Once generated, the test can be run again without going through
  45  * the generation phase with the following commande line:
  46  *  $ java <VMOptions> VTBufferTest run
  47  */
  48 
  49 import javax.management.*;
  50 import javax.tools.JavaCompiler;
  51 import javax.tools.JavaFileObject;
  52 import javax.tools.StandardJavaFileManager;
  53 import javax.tools.ToolProvider;
  54 import java.io.File;
  55 import java.io.IOException;
  56 import java.io.PrintWriter;
  57 import java.lang.management.*;
  58 import java.lang.reflect.InvocationTargetException;
  59 import java.lang.reflect.Method;
  60 import java.util.Arrays;
  61 import java.util.List;
  62 import java.util.Random;
  63 import java.net.URL;
  64 import java.net.URLClassLoader;
  65 import java.util.ArrayList;
  66 
  67 public class VTBufferTest implements Runnable {
  68     static Random random;
  69     static boolean generate;
  70     static boolean execute;
  71     static long seed = 0;
  72     long startTime;
  73     boolean verbose = false;
  74     String[] valueNames;
  75     File[] valueSources;
  76     File[] loopSource;
  77 
  78 
  79     static void usage() {
  80         System.out.println("Usage:\n");
  81         System.out.println("\tVTBufferTest <command> [options]...\n");
  82         System.out.println("\nWhere <command> is one of the following: generate | generate-and-run | run\n");
  83         System.out.println("Where [options] can be: -seed <long value>\n");
  84     }
  85 
  86     public static void main(String[] args) {
  87         if (args.length < 1) {
  88             usage();
  89             System.exit(-1);
  90         }
  91 
  92         if (args[0].compareTo("generate") == 0) {
  93             generate = true;
  94             execute = false;
  95         } else if (args[0].compareTo("generate-and-run") == 0) {
  96             generate = true;
  97             execute = true;
  98         } else if (args[0].compareTo("run") == 0) {
  99             generate = false;
 100             execute = true;
 101         } else {
 102             System.out.println("Unknown command\n");
 103             usage();
 104             System.exit(-1);
 105         }
 106 
 107         if (args.length > 1) {
 108             int cursor = 1;
 109             if (args[cursor].compareTo("-seed") == 0) {
 110                 if (args.length < 3) {
 111                     usage();
 112                     System.exit(-1);
 113                 }
 114                 seed = Long.valueOf(args[cursor+1]);
 115                 cursor++;
 116             } else {
 117                 System.out.println("Unknown option\n");
 118                 usage();
 119                 System.exit(-1);
 120             }
 121         }
 122 
 123         if (generate) {
 124             if (seed == 0) {
 125                 seed = System.nanoTime();
 126             }
 127             random = new Random(seed);
 128             System.out.println("Seed= " + seed);
 129         }
 130 
 131         VTBufferTest test = new VTBufferTest(true);
 132         test.run();
 133     }
 134 
 135     public VTBufferTest(boolean verbose) {
 136         this.verbose = verbose;
 137     }
 138 
 139     static private String[] generateValueNames() {
 140         int nvalues = random.nextInt(16) + 4;
 141         String[] names = new String[nvalues];
 142         for (int i = 0; i < nvalues; i++) {
 143             names[i] = new String("Value"+i);
 144         }
 145         return names;
 146     }
 147 
 148     static private File writeSource(String filename, String source) {
 149         try{
 150             PrintWriter writer = new PrintWriter(filename, "UTF-8");
 151             writer.println(source);
 152             writer.close();
 153         } catch (IOException e) {
 154             throw new RuntimeException("Writing source file failed");
 155         }
 156         return new File(filename);
 157     }
 158 
 159     static private File[] generateValueSources(String[] valueNames) {
 160         File[] sources = new File[valueNames.length];
 161         for (int i = 0; i < valueNames.length; i++) {
 162             int nfields = random.nextInt(6) + 1;
 163             String s = ValueTypeGenerator.generateValueType(random, valueNames[i], nfields);
 164             String filename = valueNames[i]+".java";
 165             sources[i] = writeSource(filename, s);
 166         }
 167         return sources;
 168     }
 169 
 170     static private File[] generateLoopSource(String[] names) {
 171         StringBuilder sb = new StringBuilder();
 172         sb.append("// Seed = ").append(seed).append("\n");
 173         // class declaration
 174         sb.append("public final class Loop {\n");
 175         sb.append("\n");
 176 
 177         sb.append("\tstatic {\n");
 178         int i = 0;
 179         for (String name : names) {
 180             sb.append("\t\t").append(names[i]).append(" lv").append(i).append(" = ");
 181             sb.append(names[i]).append(".make").append(names[i]).append("();\n");
 182             sb.append("\t\tlv").append(i).append(".printLayout(System.out);\n");
 183             i++;
 184         }
 185         sb.append("\t}\n\n");
 186 
 187         // loop method
 188         sb.append("\tstatic public void loop(int iterations) { \n");
 189         i = 0;
 190         for (String name : names) {
 191             sb.append("\t\t").append(names[i]).append(" lv").append(i).append(" = ");
 192             sb.append(names[i]).append(".make").append(names[i]).append("();\n");
 193             i++;
 194         }
 195         sb.append("\t\tfor (int i = 0; i < iterations; i++) {\n");
 196         i = 0;
 197         for (String name : names) {
 198             sb.append("\t\t\tif (!").append(names[i]).append(".verify(lv").append(i).append("))\n");
 199             sb.append("\t\t\t\tthrow new RuntimeException(\"Error in ").append(names[i]).append("\");\n");
 200             i++;
 201         }
 202         i = 0;
 203         for (String name : names) {
 204             if (i != 0) {
 205                 sb.append("\t\t\tif (i % ").append(i).append(" != 0) {\n");
 206                 sb.append("\t\t\t\tlv").append(i).append(" = ");
 207                 sb.append(names[i]).append(".make").append(names[i]).append("();\n");
 208                 sb.append("\t\t\t}\n");
 209             }
 210             i++;
 211         }
 212         sb.append("\t\t}\n");
 213         sb.append("\t}\n");
 214         sb.append("}\n");
 215 
 216         String source = sb.toString();
 217 
 218         File[] files = new File[1];
 219         files[0] = writeSource("Loop.java", source);
 220         return files;
 221     }
 222 
 223     public void run() {
 224         if (generate) {
 225             valueNames = generateValueNames();
 226             valueSources = generateValueSources(valueNames);
 227             loopSource = generateLoopSource(valueNames);
 228 
 229             JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
 230             StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
 231             List<String> optionList = new ArrayList<String>();
 232             optionList.addAll(Arrays.asList("-classpath",".","-XDenableValueTypes"));
 233 
 234             Iterable<? extends JavaFileObject> compilationUnits1 =
 235                     fileManager.getJavaFileObjectsFromFiles(Arrays.asList(valueSources));
 236             compiler.getTask(null, fileManager, null, optionList, null, compilationUnits1).call();
 237 
 238             Iterable<? extends JavaFileObject> compilationUnits2 =
 239                     fileManager.getJavaFileObjectsFromFiles(Arrays.asList(loopSource));
 240             compiler.getTask(null, fileManager, null, optionList, null, compilationUnits2).call();
 241         }
 242 
 243         if (execute) {
 244             startTime = ManagementFactory.getRuntimeMXBean().getUptime();
 245 
 246             ClassLoader cl = createClassLoader();
 247             try {
 248                 iterate(100, 5000, cl);
 249             } catch(InvocationTargetException e) {
 250                 e.getCause().printStackTrace();
 251                 System.exit(-1);
 252             }
 253 
 254             if (verbose) {
 255                 printVTBufferStats();
 256 
 257                 System.out.println("\nGC Statistics:");
 258                 List<GarbageCollectorMXBean> gcs = ManagementFactory.getGarbageCollectorMXBeans();
 259                 for (GarbageCollectorMXBean gc : gcs) {
 260                     System.out.println("Name=" + gc.getName());
 261                     System.out.println("GC counts=" + gc.getCollectionCount());
 262                     System.out.println("GC time=" + gc.getCollectionTime() + "ms");
 263                 }
 264 
 265                 System.out.println("\nHeap Statistics");
 266                 List<MemoryPoolMXBean> memPools = ManagementFactory.getMemoryPoolMXBeans();
 267                 for (MemoryPoolMXBean memPool : memPools) {
 268                     if (memPool.getType() == MemoryType.HEAP) {
 269                         System.out.println("\nName: " + memPool.getName());
 270                         System.out.println("Usage: " + memPool.getUsage());
 271                         System.out.println("Collection Usage: " + memPool.getCollectionUsage());
 272                         System.out.println("Peak Usage: " + memPool.getPeakUsage());
 273                     }
 274                 }
 275             }
 276         }
 277     }
 278 
 279 
 280     ClassLoader createClassLoader() {
 281         try{
 282             File file = new File(".");
 283             URL url = file.toURI().toURL();
 284             URL[] urls = new URL[]{url};
 285             ClassLoader cl = new URLClassLoader(urls);
 286             return cl;
 287         } catch(Exception ex){
 288             ex.printStackTrace();
 289         }
 290         return null;
 291     }
 292 
 293     public void iterate(int n, int m, ClassLoader cl) throws InvocationTargetException {
 294         for (int i = 0; i < n; i++) {
 295             Class loop = null;
 296             try {
 297                 loop = Class.forName("Loop", true, cl);
 298             } catch (ClassNotFoundException e) {
 299                 e.printStackTrace();
 300             }
 301             Method method = null;
 302             try {
 303                 method = loop.getMethod("loop", int.class);
 304             } catch (NoSuchMethodException e) {
 305                 e.printStackTrace();
 306                 return;
 307             }
 308             try {
 309                 method.invoke(null, m);
 310             } catch (IllegalAccessException e) {
 311                 e.printStackTrace();
 312                 return;
 313             } catch (InvocationTargetException e) {
 314                 throw e;
 315             }
 316         }
 317     }
 318 
 319     public void printVTBufferStats() {
 320         MBeanServerConnection mbs = ManagementFactory.getPlatformMBeanServer();
 321         String MBeanName = "com.sun.management:type=DiagnosticCommand";
 322         ObjectName beanName;
 323         try {
 324             beanName = new ObjectName(MBeanName);
 325         } catch (MalformedObjectNameException e) {
 326             String message = "MBean not found: " + MBeanName;
 327             throw new RuntimeException(message, e);
 328         }
 329         String result = null;
 330         try {
 331             result = (String)mbs.invoke(beanName,"vtbufferStats",new Object[0],new String[0]);
 332         } catch(Exception e) {
 333             e.printStackTrace();
 334         }
 335         System.out.println(result);
 336     }
 337 }