001/*
002 * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.hotspot.test;
024
025import static com.oracle.graal.debug.internal.MemUseTrackerImpl.*;
026import jdk.internal.jvmci.hotspot.*;
027
028import com.oracle.graal.api.runtime.*;
029import com.oracle.graal.compiler.test.*;
030import com.oracle.graal.debug.*;
031import com.oracle.graal.debug.internal.*;
032import com.oracle.graal.hotspot.*;
033import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
034
035/**
036 * Used to benchmark memory usage during Graal compilation.
037 *
038 * To benchmark:
039 *
040 * <pre>
041 *     mx vm -XX:-UseJVMCIClassLoader -cp @com.oracle.graal.hotspot.test com.oracle.graal.hotspot.test.MemoryUsageBenchmark
042 * </pre>
043 *
044 * Memory analysis for a {@link CompileTheWorld} execution can also be performed. For example:
045 *
046 * <pre>
047 *     mx --vm server vm -XX:-UseJVMCIClassLoader -G:CompileTheWorldClasspath=$HOME/SPECjvm2008/SPECjvm2008.jar -cp @com.oracle.graal.hotspot.test com.oracle.graal.hotspot.test.MemoryUsageBenchmark
048 * </pre>
049 */
050public class MemoryUsageBenchmark extends HotSpotGraalCompilerTest {
051
052    public static int simple(int a, int b) {
053        return a + b;
054    }
055
056    public static synchronized int complex(CharSequence cs) {
057        if (cs instanceof String) {
058            return cs.hashCode();
059        }
060
061        if (cs instanceof StringBuilder) {
062            int[] hash = {0};
063            cs.chars().forEach(c -> hash[0] += c);
064            return hash[0];
065        }
066
067        int res = 0;
068
069        // Exercise lock elimination
070        synchronized (cs) {
071            res = cs.length();
072        }
073        synchronized (cs) {
074            res = cs.hashCode() ^ 31;
075        }
076
077        for (int i = 0; i < cs.length(); i++) {
078            res *= cs.charAt(i);
079        }
080
081        // A fixed length loop with some canonicalizable arithmetics will
082        // activate loop unrolling and more canonicalization
083        int sum = 0;
084        for (int i = 0; i < 5; i++) {
085            sum += i * 2;
086        }
087        res += sum;
088
089        // Activates escape-analysis
090        res += new String("asdf").length();
091
092        return res;
093    }
094
095    static class MemoryUsageCloseable implements AutoCloseable {
096
097        private final long start;
098        private final String name;
099
100        public MemoryUsageCloseable(String name) {
101            this.name = name;
102            this.start = getCurrentThreadAllocatedBytes();
103        }
104
105        @Override
106        public void close() {
107            long end = getCurrentThreadAllocatedBytes();
108            long allocated = end - start;
109            System.out.println(name + ": " + allocated);
110        }
111    }
112
113    public static void main(String[] args) {
114        // Ensure a Graal runtime is initialized prior to Debug being initialized as the former
115        // may include processing command line options used by the latter.
116        Graal.getRuntime();
117
118        // Ensure a debug configuration for this thread is initialized
119        if (Debug.isEnabled() && DebugScope.getConfig() == null) {
120            DebugEnvironment.initialize(System.out);
121        }
122        new MemoryUsageBenchmark().run();
123    }
124
125    private void doCompilation(String methodName, String label) {
126        HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) getResolvedJavaMethod(methodName);
127
128        // invalidate any existing compiled code
129        method.reprofile();
130
131        int id = method.allocateCompileId(jdk.internal.jvmci.compiler.Compiler.INVOCATION_ENTRY_BCI);
132        long graalEnv = 0L;
133
134        try (MemoryUsageCloseable c = label == null ? null : new MemoryUsageCloseable(label)) {
135            CompilationTask task = new CompilationTask(method, jdk.internal.jvmci.compiler.Compiler.INVOCATION_ENTRY_BCI, graalEnv, id, false);
136            task.runCompilation();
137        }
138    }
139
140    private void allocSpyCompilation(String methodName) {
141        if (AllocSpy.isEnabled()) {
142            HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) getResolvedJavaMethod(methodName);
143
144            // invalidate any existing compiled code
145            method.reprofile();
146
147            int id = method.allocateCompileId(jdk.internal.jvmci.compiler.Compiler.INVOCATION_ENTRY_BCI);
148            long graalEnv = 0L;
149            try (AllocSpy as = AllocSpy.open(methodName)) {
150                CompilationTask task = new CompilationTask(method, jdk.internal.jvmci.compiler.Compiler.INVOCATION_ENTRY_BCI, graalEnv, id, false);
151                task.runCompilation();
152            }
153        }
154    }
155
156    private static final boolean verbose = Boolean.getBoolean("verbose");
157
158    private void compileAndTime(String methodName) {
159
160        // Parse in eager mode to resolve methods/fields/classes
161        parseEager(methodName, AllowAssumptions.YES);
162
163        // Warm up and initialize compiler phases used by this compilation
164        for (int i = 0; i < 10; i++) {
165            doCompilation(methodName, verbose ? methodName + "[warmup-" + i + "]" : null);
166        }
167
168        doCompilation(methodName, methodName);
169    }
170
171    public void run() {
172        compileAndTime("simple");
173        compileAndTime("complex");
174        if (CompileTheWorld.Options.CompileTheWorldClasspath.getValue() != CompileTheWorld.SUN_BOOT_CLASS_PATH) {
175            CompileTheWorld ctw = new CompileTheWorld();
176            try {
177                ctw.compile();
178            } catch (Throwable e) {
179                e.printStackTrace();
180            }
181        }
182        allocSpyCompilation("simple");
183        allocSpyCompilation("complex");
184    }
185}