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 jvm.internal.value.*;
  50 
  51 import javax.management.*;
  52 import javax.tools.JavaCompiler;
  53 import javax.tools.JavaFileObject;
  54 import javax.tools.StandardJavaFileManager;
  55 import javax.tools.ToolProvider;
  56 import java.io.File;
  57 import java.io.IOException;
  58 import java.io.PrintWriter;
  59 import java.lang.management.*;
  60 import java.lang.reflect.InvocationTargetException;
  61 import java.lang.reflect.Method;
  62 import java.util.Arrays;
  63 import java.util.List;
  64 import java.util.Random;
  65 import java.net.URL;
  66 import java.net.URLClassLoader;
  67 import java.util.ArrayList;
  68 
  69 public class VTBufferTest implements Runnable {
  70     static Random random;
  71     static boolean generate;
  72     static boolean execute;
  73     static long seed = 0;
  74     long startTime;
  75     boolean verbose = false;
  76     String[] valueNames;
  77     File[] valueSources;
  78     File[] loopSource;
  79 
  80 
  81     static void usage() {
  82         System.out.println("Usage:\n");
  83         System.out.println("\tVTBufferTest <command> [options]...\n");
  84         System.out.println("\nWhere <command> is one of the following: generate | generate-and-run | run\n");
  85         System.out.println("Where [options] can be: -seed <long value>\n");
  86     }
  87 
  88     public static void main(String[] args) {
  89         if (args.length < 1) {
  90             usage();
  91             System.exit(-1);
  92         }
  93 
  94         if (args[0].compareTo("generate") == 0) {
  95             generate = true;
  96             execute = false;
  97         } else if (args[0].compareTo("generate-and-run") == 0) {
  98             generate = true;
  99             execute = true;
 100         } else if (args[0].compareTo("run") == 0) {
 101             generate = false;
 102             execute = true;
 103         } else {
 104             System.out.println("Unknown command\n");
 105             usage();
 106             System.exit(-1);
 107         }
 108 
 109         if (args.length > 1) {
 110             int cursor = 1;
 111             if (args[cursor].compareTo("-seed") == 0) {
 112                 if (args.length < 3) {
 113                     usage();
 114                     System.exit(-1);
 115                 }
 116                 seed = Long.valueOf(args[cursor+1]);
 117                 cursor++;
 118             } else {
 119                 System.out.println("Unknown option\n");
 120                 usage();
 121                 System.exit(-1);
 122             }
 123         }
 124 
 125         if (generate) {
 126             if (seed == 0) {
 127                 seed = System.nanoTime();
 128             }
 129             random = new Random(seed);
 130             System.out.println("Seed= " + seed);
 131         }
 132 
 133         VTBufferTest test = new VTBufferTest(true);
 134         test.run();
 135     }
 136 
 137     public VTBufferTest(boolean verbose) {
 138         this.verbose = verbose;
 139     }
 140 
 141     static private String[] generateValueNames() {
 142         int nvalues = random.nextInt(16) + 4;
 143         String[] names = new String[nvalues];
 144         for (int i = 0; i < nvalues; i++) {
 145             names[i] = new String("Value"+i);
 146         }
 147         return names;
 148     }
 149 
 150     static private File writeSource(String filename, String source) {
 151         try{
 152             PrintWriter writer = new PrintWriter(filename, "UTF-8");
 153             writer.println(source);
 154             writer.close();
 155         } catch (IOException e) {
 156             throw new RuntimeException("Writing source file failed");
 157         }
 158         return new File(filename);
 159     }
 160 
 161     static private File[] generateValueSources(String[] valueNames) {
 162         File[] sources = new File[valueNames.length];
 163         for (int i = 0; i < valueNames.length; i++) {
 164             int nfields = random.nextInt(6) + 1;
 165             String s = ValueTypeGenerator.generateValueTypeNoObjectRef(random, valueNames[i], nfields);
 166             String filename = valueNames[i]+".java";
 167             sources[i] = writeSource(filename, s);
 168         }
 169         return sources;
 170     }
 171 
 172     static private File[] generateLoopSource(String[] names) {
 173         StringBuilder sb = new StringBuilder();
 174         sb.append("// Seed = ").append(seed).append("\n");
 175         // class declaration
 176         sb.append("public final class Loop {\n");
 177         sb.append("\n");
 178 
 179         sb.append("\tstatic {\n");
 180         int i = 0;
 181         for (String name : names) {
 182             sb.append("\t\t").append(names[i]).append(" lv").append(i).append(" = ");
 183             sb.append(names[i]).append(".make").append(names[i]).append("();\n");
 184             sb.append("\t\tlv").append(i).append(".printLayout(System.out);\n");
 185             i++;
 186         }
 187         sb.append("\t}\n\n");
 188 
 189         // loop method
 190         sb.append("\tstatic public void loop(int iterations) { \n");
 191         i = 0;
 192         for (String name : names) {
 193             sb.append("\t\t").append(names[i]).append(" lv").append(i).append(" = ");
 194             sb.append(names[i]).append(".make").append(names[i]).append("();\n");
 195             i++;
 196         }
 197         sb.append("\t\tfor (int i = 0; i < iterations; i++) {\n");
 198         i = 0;
 199         for (String name : names) {
 200             sb.append("\t\t\tif (!").append(names[i]).append(".verify(lv").append(i).append("))\n");
 201             sb.append("\t\t\t\tthrow new RuntimeException(\"Error in ").append(names[i]).append("\");\n");
 202             i++;
 203         }
 204         i = 0;
 205         for (String name : names) {
 206             if (i != 0) {
 207                 sb.append("\t\t\tif (i % ").append(i).append(" != 0) {\n");
 208                 sb.append("\t\t\t\tlv").append(i).append(" = ");
 209                 sb.append(names[i]).append(".make").append(names[i]).append("();\n");
 210                 sb.append("\t\t\t}\n");
 211             }
 212             i++;
 213         }
 214         sb.append("\t\t}\n");
 215         sb.append("\t}\n");
 216         sb.append("}\n");
 217 
 218         String source = sb.toString();
 219 
 220         File[] files = new File[1];
 221         files[0] = writeSource("Loop.java", source);
 222         return files;
 223     }
 224 
 225     public void run() {
 226         if (generate) {
 227             valueNames = generateValueNames();
 228             valueSources = generateValueSources(valueNames);
 229             loopSource = generateLoopSource(valueNames);
 230 
 231             JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
 232             StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
 233             List<String> optionList = new ArrayList<String>();
 234             optionList.addAll(Arrays.asList("-classpath",".","-XDenableValueTypes"));
 235 
 236             Iterable<? extends JavaFileObject> compilationUnits1 =
 237                     fileManager.getJavaFileObjectsFromFiles(Arrays.asList(valueSources));
 238             compiler.getTask(null, fileManager, null, optionList, null, compilationUnits1).call();
 239 
 240             Iterable<? extends JavaFileObject> compilationUnits2 =
 241                     fileManager.getJavaFileObjectsFromFiles(Arrays.asList(loopSource));
 242             compiler.getTask(null, fileManager, null, optionList, null, compilationUnits2).call();
 243         }
 244 
 245         if (execute) {
 246             startTime = ManagementFactory.getRuntimeMXBean().getUptime();
 247 
 248             ClassLoader cl = createClassLoader();
 249             try {
 250                 iterate(100, 5000, cl);
 251             } catch(InvocationTargetException e) {
 252                 e.getCause().printStackTrace();
 253                 System.exit(-1);
 254             }
 255 
 256             if (verbose) {
 257                 printVTBufferStats();
 258 
 259                 System.out.println("\nGC Statistics:");
 260                 List<GarbageCollectorMXBean> gcs = ManagementFactory.getGarbageCollectorMXBeans();
 261                 for (GarbageCollectorMXBean gc : gcs) {
 262                     System.out.println("Name=" + gc.getName());
 263                     System.out.println("GC counts=" + gc.getCollectionCount());
 264                     System.out.println("GC time=" + gc.getCollectionTime() + "ms");
 265                 }
 266 
 267                 System.out.println("\nHeap Statistics");
 268                 List<MemoryPoolMXBean> memPools = ManagementFactory.getMemoryPoolMXBeans();
 269                 for (MemoryPoolMXBean memPool : memPools) {
 270                     if (memPool.getType() == MemoryType.HEAP) {
 271                         System.out.println("\nName: " + memPool.getName());
 272                         System.out.println("Usage: " + memPool.getUsage());
 273                         System.out.println("Collection Usage: " + memPool.getCollectionUsage());
 274                         System.out.println("Peak Usage: " + memPool.getPeakUsage());
 275                     }
 276                 }
 277             }
 278         }
 279     }
 280 
 281 
 282     ClassLoader createClassLoader() {
 283         try{
 284             File file = new File(".");
 285             URL url = file.toURI().toURL();
 286             URL[] urls = new URL[]{url};
 287             ClassLoader cl = new URLClassLoader(urls);
 288             return cl;
 289         } catch(Exception ex){
 290             ex.printStackTrace();
 291         }
 292         return null;
 293     }
 294 
 295     public void iterate(int n, int m, ClassLoader cl) throws InvocationTargetException {
 296         for (int i = 0; i < n; i++) {
 297             Class loop = null;
 298             try {
 299                 loop = Class.forName("Loop", true, cl);
 300             } catch (ClassNotFoundException e) {
 301                 e.printStackTrace();
 302             }
 303             Method method = null;
 304             try {
 305                 method = loop.getMethod("loop", int.class);
 306             } catch (NoSuchMethodException e) {
 307                 e.printStackTrace();
 308                 return;
 309             }
 310             try {
 311                 method.invoke(null, m);
 312             } catch (IllegalAccessException e) {
 313                 e.printStackTrace();
 314                 return;
 315             } catch (InvocationTargetException e) {
 316                 throw e;
 317             }
 318         }
 319     }
 320 
 321     public void printVTBufferStats() {
 322         MBeanServerConnection mbs = ManagementFactory.getPlatformMBeanServer();
 323         String MBeanName = "com.sun.management:type=DiagnosticCommand";
 324         ObjectName beanName;
 325         try {
 326             beanName = new ObjectName(MBeanName);
 327         } catch (MalformedObjectNameException e) {
 328             String message = "MBean not found: " + MBeanName;
 329             throw new RuntimeException(message, e);
 330         }
 331         String result = null;
 332         try {
 333             result = (String)mbs.invoke(beanName,"vtbufferStats",new Object[0],new String[0]);
 334         } catch(Exception e) {
 335             e.printStackTrace();
 336         }
 337         System.out.println(result);
 338     }
 339 }