1 /*
   2  * Copyright (c) 2011, 2015, 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 package org.graalvm.compiler.hotspot.test;
  24 
  25 import static org.graalvm.compiler.debug.MemUseTrackerKey.getCurrentThreadAllocatedBytes;
  26 
  27 import org.graalvm.compiler.api.test.Graal;
  28 import org.graalvm.compiler.core.test.AllocSpy;
  29 import org.graalvm.compiler.hotspot.CompilationTask;
  30 import org.graalvm.compiler.hotspot.HotSpotGraalCompiler;
  31 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
  32 import org.graalvm.compiler.options.OptionValues;
  33 
  34 import jdk.vm.ci.hotspot.HotSpotCompilationRequest;
  35 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
  36 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider;
  37 import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
  38 import jdk.vm.ci.runtime.JVMCICompiler;
  39 
  40 /**
  41  * Used to benchmark memory usage during Graal compilation.
  42  *
  43  * To benchmark:
  44  *
  45  * <pre>
  46  *     mx vm -XX:-UseJVMCIClassLoader -cp @org.graalvm.compiler.hotspot.test org.graalvm.compiler.hotspot.test.MemoryUsageBenchmark
  47  * </pre>
  48  *
  49  * Memory analysis for a {@link CompileTheWorld} execution can also be performed. For example:
  50  *
  51  * <pre>
  52  *     mx vm -XX:-UseJVMCIClassLoader -DCompileTheWorld.Classpath=$HOME/SPECjvm2008/SPECjvm2008.jar -cp @org.graalvm.compiler.hotspot.test org.graalvm.compiler.hotspot.test.MemoryUsageBenchmark
  53  * </pre>
  54  */
  55 public class MemoryUsageBenchmark extends HotSpotGraalCompilerTest {
  56 
  57     public static int simple(int a, int b) {
  58         return a + b;
  59     }
  60 
  61     public static synchronized int complex(CharSequence cs) {
  62         if (cs instanceof String) {
  63             return cs.hashCode();
  64         }
  65 
  66         if (cs instanceof StringBuilder) {
  67             int[] hash = {0};
  68             cs.chars().forEach(c -> hash[0] += c);
  69             return hash[0];
  70         }
  71 
  72         int res = 0;
  73 
  74         // Exercise lock elimination
  75         synchronized (cs) {
  76             res = cs.length();
  77         }
  78         synchronized (cs) {
  79             res = cs.hashCode() ^ 31;
  80         }
  81 
  82         for (int i = 0; i < cs.length(); i++) {
  83             res *= cs.charAt(i);
  84         }
  85 
  86         // A fixed length loop with some canonicalizable arithmetics will
  87         // activate loop unrolling and more canonicalization
  88         int sum = 0;
  89         for (int i = 0; i < 5; i++) {
  90             sum += i * 2;
  91         }
  92         res += sum;
  93 
  94         // Activates escape-analysis
  95         res += new String("asdf").length();
  96 
  97         return res;
  98     }
  99 
 100     static class MemoryUsageCloseable implements AutoCloseable {
 101 
 102         private final long start;
 103         private final String name;
 104 
 105         MemoryUsageCloseable(String name) {
 106             this.name = name;
 107             this.start = getCurrentThreadAllocatedBytes();
 108         }
 109 
 110         @Override
 111         public void close() {
 112             long end = getCurrentThreadAllocatedBytes();
 113             long allocated = end - start;
 114             System.out.println(name + ": " + allocated);
 115         }
 116     }
 117 
 118     public static void main(String[] args) {
 119         // Ensure a Graal runtime is initialized prior to Debug being initialized as the former
 120         // may include processing command line options used by the latter.
 121         Graal.getRuntime();
 122 
 123         new MemoryUsageBenchmark().run();
 124     }
 125 
 126     @SuppressWarnings("try")
 127     private void doCompilation(String methodName, String label) {
 128         HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) getResolvedJavaMethod(methodName);
 129 
 130         // invalidate any existing compiled code
 131         method.reprofile();
 132 
 133         long jvmciEnv = 0L;
 134 
 135         try (MemoryUsageCloseable c = label == null ? null : new MemoryUsageCloseable(label)) {
 136             HotSpotJVMCIRuntimeProvider runtime = HotSpotJVMCIRuntime.runtime();
 137             int entryBCI = JVMCICompiler.INVOCATION_ENTRY_BCI;
 138             HotSpotCompilationRequest request = new HotSpotCompilationRequest(method, entryBCI, jvmciEnv);
 139             CompilationTask task = new CompilationTask(runtime, (HotSpotGraalCompiler) runtime.getCompiler(), request, true, false, getInitialOptions());
 140             task.runCompilation();
 141         }
 142     }
 143 
 144     @SuppressWarnings("try")
 145     private void allocSpyCompilation(String methodName) {
 146         if (AllocSpy.isEnabled()) {
 147             HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) getResolvedJavaMethod(methodName);
 148 
 149             // invalidate any existing compiled code
 150             method.reprofile();
 151 
 152             long jvmciEnv = 0L;
 153             try (AllocSpy as = AllocSpy.open(methodName)) {
 154                 HotSpotJVMCIRuntimeProvider runtime = HotSpotJVMCIRuntime.runtime();
 155                 HotSpotCompilationRequest request = new HotSpotCompilationRequest(method, JVMCICompiler.INVOCATION_ENTRY_BCI, jvmciEnv);
 156                 HotSpotGraalCompiler compiler = (HotSpotGraalCompiler) runtime.getCompiler();
 157                 OptionValues options = getInitialOptions();
 158                 CompilationTask task = new CompilationTask(runtime, compiler, request, true, false, options);
 159                 task.runCompilation();
 160             }
 161         }
 162     }
 163 
 164     private static final boolean verbose = Boolean.getBoolean("verbose");
 165 
 166     private void compileAndTime(String methodName) {
 167 
 168         // Parse in eager mode to resolve methods/fields/classes
 169         parseEager(methodName, AllowAssumptions.YES);
 170 
 171         // Warm up and initialize compiler phases used by this compilation
 172         for (int i = 0; i < 10; i++) {
 173             doCompilation(methodName, verbose ? methodName + "[warmup-" + i + "]" : null);
 174         }
 175 
 176         doCompilation(methodName, methodName);
 177     }
 178 
 179     public void run() {
 180         compileAndTime("simple");
 181         compileAndTime("complex");
 182         OptionValues options = CompileTheWorld.loadOptions(getInitialOptions());
 183         if (CompileTheWorld.Options.Classpath.getValue(options) != CompileTheWorld.SUN_BOOT_CLASS_PATH) {
 184             HotSpotJVMCIRuntimeProvider runtime = HotSpotJVMCIRuntime.runtime();
 185             CompileTheWorld ctw = new CompileTheWorld(runtime, (HotSpotGraalCompiler) runtime.getCompiler(), options);
 186             try {
 187                 ctw.compile();
 188             } catch (Throwable e) {
 189                 e.printStackTrace();
 190             }
 191         }
 192         allocSpyCompilation("simple");
 193         allocSpyCompilation("complex");
 194     }
 195 }