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