/*
 * Copyright (c) 2011, 2015, 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.
 *
 * 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.graalvm.compiler.hotspot.test;

import static org.graalvm.compiler.debug.internal.MemUseTrackerImpl.getCurrentThreadAllocatedBytes;

import org.graalvm.compiler.api.test.Graal;
import org.graalvm.compiler.core.test.AllocSpy;
import org.graalvm.compiler.debug.Debug;
import org.graalvm.compiler.debug.DebugEnvironment;
import org.graalvm.compiler.debug.internal.DebugScope;
import org.graalvm.compiler.hotspot.CompilationTask;
import org.graalvm.compiler.hotspot.CompileTheWorld;
import org.graalvm.compiler.hotspot.CompileTheWorldOptions;
import org.graalvm.compiler.hotspot.HotSpotGraalCompiler;
import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;

import jdk.vm.ci.hotspot.HotSpotCompilationRequest;
import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider;
import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
import jdk.vm.ci.runtime.JVMCICompiler;

Used to benchmark memory usage during Graal compilation. To benchmark:
    mx vm -XX:-UseJVMCIClassLoader -cp @org.graalvm.compiler.hotspot.test org.graalvm.compiler.hotspot.test.MemoryUsageBenchmark
Memory analysis for a CompileTheWorld execution can also be performed. For example:
    mx --vm server vm -XX:-UseJVMCIClassLoader -Dgraal.CompileTheWorldClasspath=$HOME/SPECjvm2008/SPECjvm2008.jar -cp @org.graalvm.compiler.hotspot.test org.graalvm.compiler.hotspot.test.MemoryUsageBenchmark
/** * Used to benchmark memory usage during Graal compilation. * * To benchmark: * * <pre> * mx vm -XX:-UseJVMCIClassLoader -cp @org.graalvm.compiler.hotspot.test org.graalvm.compiler.hotspot.test.MemoryUsageBenchmark * </pre> * * Memory analysis for a {@link CompileTheWorld} execution can also be performed. For example: * * <pre> * mx --vm server vm -XX:-UseJVMCIClassLoader -Dgraal.CompileTheWorldClasspath=$HOME/SPECjvm2008/SPECjvm2008.jar -cp @org.graalvm.compiler.hotspot.test org.graalvm.compiler.hotspot.test.MemoryUsageBenchmark * </pre> */
public class MemoryUsageBenchmark extends HotSpotGraalCompilerTest { public static int simple(int a, int b) { return a + b; } public static synchronized int complex(CharSequence cs) { if (cs instanceof String) { return cs.hashCode(); } if (cs instanceof StringBuilder) { int[] hash = {0}; cs.chars().forEach(c -> hash[0] += c); return hash[0]; } int res = 0; // Exercise lock elimination synchronized (cs) { res = cs.length(); } synchronized (cs) { res = cs.hashCode() ^ 31; } for (int i = 0; i < cs.length(); i++) { res *= cs.charAt(i); } // A fixed length loop with some canonicalizable arithmetics will // activate loop unrolling and more canonicalization int sum = 0; for (int i = 0; i < 5; i++) { sum += i * 2; } res += sum; // Activates escape-analysis res += new String("asdf").length(); return res; } static class MemoryUsageCloseable implements AutoCloseable { private final long start; private final String name; MemoryUsageCloseable(String name) { this.name = name; this.start = getCurrentThreadAllocatedBytes(); } @Override public void close() { long end = getCurrentThreadAllocatedBytes(); long allocated = end - start; System.out.println(name + ": " + allocated); } } public static void main(String[] args) { // Ensure a Graal runtime is initialized prior to Debug being initialized as the former // may include processing command line options used by the latter. Graal.getRuntime(); // Ensure a debug configuration for this thread is initialized if (Debug.isEnabled() && DebugScope.getConfig() == null) { DebugEnvironment.initialize(System.out); } new MemoryUsageBenchmark().run(); } @SuppressWarnings("try") private void doCompilation(String methodName, String label) { HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) getResolvedJavaMethod(methodName); // invalidate any existing compiled code method.reprofile(); long jvmciEnv = 0L; try (MemoryUsageCloseable c = label == null ? null : new MemoryUsageCloseable(label)) { HotSpotJVMCIRuntimeProvider runtime = HotSpotJVMCIRuntime.runtime(); int entryBCI = JVMCICompiler.INVOCATION_ENTRY_BCI; HotSpotCompilationRequest request = new HotSpotCompilationRequest(method, entryBCI, jvmciEnv); CompilationTask task = new CompilationTask(runtime, (HotSpotGraalCompiler) runtime.getCompiler(), request, true, false); task.runCompilation(); } } @SuppressWarnings("try") private void allocSpyCompilation(String methodName) { if (AllocSpy.isEnabled()) { HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) getResolvedJavaMethod(methodName); // invalidate any existing compiled code method.reprofile(); long jvmciEnv = 0L; try (AllocSpy as = AllocSpy.open(methodName)) { HotSpotJVMCIRuntimeProvider runtime = HotSpotJVMCIRuntime.runtime(); HotSpotCompilationRequest request = new HotSpotCompilationRequest(method, JVMCICompiler.INVOCATION_ENTRY_BCI, jvmciEnv); CompilationTask task = new CompilationTask(runtime, (HotSpotGraalCompiler) runtime.getCompiler(), request, true, false); task.runCompilation(); } } } private static final boolean verbose = Boolean.getBoolean("verbose"); private void compileAndTime(String methodName) { // Parse in eager mode to resolve methods/fields/classes parseEager(methodName, AllowAssumptions.YES); // Warm up and initialize compiler phases used by this compilation for (int i = 0; i < 10; i++) { doCompilation(methodName, verbose ? methodName + "[warmup-" + i + "]" : null); } doCompilation(methodName, methodName); } public void run() { compileAndTime("simple"); compileAndTime("complex"); if (CompileTheWorldOptions.CompileTheWorldClasspath.getValue() != CompileTheWorld.SUN_BOOT_CLASS_PATH) { HotSpotJVMCIRuntimeProvider runtime = HotSpotJVMCIRuntime.runtime(); CompileTheWorld ctw = new CompileTheWorld(runtime, (HotSpotGraalCompiler) runtime.getCompiler()); try { ctw.compile(); } catch (Throwable e) { e.printStackTrace(); } } allocSpyCompilation("simple"); allocSpyCompilation("complex"); } }