Mercurial > hg > truffle
diff graal/com.oracle.jvmci.hotspot/src/com/oracle/jvmci/hotspot/CompilationTask.java @ 21780:3d15183f3c93
Introduce Compiler interface in jvmci. Use it from jvmci.hotspot.CompilationTask
author | Gilles Duboscq <gilles.m.duboscq@oracle.com> |
---|---|
date | Wed, 03 Jun 2015 15:47:54 +0200 |
parents | graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java@77acf6ba2fc0 |
children | 5b9adb645217 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.jvmci.hotspot/src/com/oracle/jvmci/hotspot/CompilationTask.java Wed Jun 03 15:47:54 2015 +0200 @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2012, 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 com.oracle.jvmci.hotspot; + +import static com.oracle.jvmci.common.UnsafeAccess.*; +import static com.oracle.jvmci.debug.Debug.*; +import static com.oracle.jvmci.compiler.Compiler.*; + +import java.lang.management.*; +import java.util.concurrent.*; + +import com.oracle.jvmci.code.*; +import com.oracle.jvmci.compiler.Compiler; +import com.oracle.jvmci.debug.*; +import com.oracle.jvmci.debug.Debug.Scope; +import com.oracle.jvmci.debug.internal.*; +import com.oracle.jvmci.hotspot.events.*; +import com.oracle.jvmci.hotspot.events.EventProvider.CompilationEvent; +import com.oracle.jvmci.hotspot.events.EventProvider.CompilerFailureEvent; +import com.oracle.jvmci.meta.*; +import com.oracle.jvmci.service.*; + +//JaCoCo Exclude + +public class CompilationTask { + + private static final DebugMetric BAILOUTS = Debug.metric("Bailouts"); + + private static final EventProvider eventProvider; + static { + EventProvider provider = Services.loadSingle(EventProvider.class, false); + if (provider == null) { + eventProvider = new EmptyEventProvider(); + } else { + eventProvider = provider; + } + } + private static final Compiler compiler = Services.loadSingle(Compiler.class, true); + + private final HotSpotResolvedJavaMethod method; + private final int entryBCI; + private final int id; + + /** + * Specifies whether the compilation result is installed as the + * {@linkplain HotSpotNmethod#isDefault() default} nmethod for the compiled method. + */ + private final boolean installAsDefault; + + /** + * A {@link com.sun.management.ThreadMXBean} to be able to query some information about the + * current compiler thread, e.g. total allocated bytes. + */ + private static final com.sun.management.ThreadMXBean threadMXBean = (com.sun.management.ThreadMXBean) ManagementFactory.getThreadMXBean(); + + /** + * The address of the GraalEnv associated with this compilation or 0L if no such object exists. + */ + private final long graalEnv; + + public CompilationTask(HotSpotResolvedJavaMethod method, int entryBCI, long graalEnv, int id, boolean installAsDefault) { + this.method = method; + this.entryBCI = entryBCI; + this.id = id; + this.graalEnv = graalEnv; + this.installAsDefault = installAsDefault; + } + + public ResolvedJavaMethod getMethod() { + return method; + } + + /** + * Returns the compilation id of this task. + * + * @return compile id + */ + public int getId() { + return id; + } + + public int getEntryBCI() { + return entryBCI; + } + + /** + * Time spent in compilation. + */ + private static final DebugTimer CompilationTime = Debug.timer("CompilationTime"); + + /** + * Meters the {@linkplain CompilationResult#getBytecodeSize() bytecodes} compiled. + */ + private static final DebugMetric CompiledBytecodes = Debug.metric("CompiledBytecodes"); + + public static final DebugTimer CodeInstallationTime = Debug.timer("CodeInstallation"); + + public void runCompilation() { + HotSpotVMConfig config = HotSpotJVMCIRuntime.runtime().getConfig(); + final long threadId = Thread.currentThread().getId(); + long startCompilationTime = System.nanoTime(); + HotSpotInstalledCode installedCode = null; + final boolean isOSR = entryBCI != Compiler.INVOCATION_ENTRY_BCI; + + // Log a compilation event. + CompilationEvent compilationEvent = eventProvider.newCompilationEvent(); + + // If there is already compiled code for this method on our level we simply return. + // Graal compiles are always at the highest compile level, even in non-tiered mode so we + // only need to check for that value. + if (method.hasCodeAtLevel(entryBCI, config.compilationLevelFullOptimization)) { + return; + } + + CompilationResult result = null; + try (DebugCloseable a = CompilationTime.start()) { + CompilationStatistics stats = CompilationStatistics.create(method, isOSR); + final boolean printCompilation = PrintCompilation.getValue() && !TTY.isSuppressed(); + if (printCompilation) { + TTY.println(getMethodDescription() + "..."); + } + + TTY.Filter filter = new TTY.Filter(PrintFilter.getValue(), method); + final long start = System.currentTimeMillis(); + final long allocatedBytesBefore = threadMXBean.getThreadAllocatedBytes(threadId); + + try (Scope s = Debug.scope("Compiling", new DebugDumpScope(String.valueOf(id), true))) { + // Begin the compilation event. + compilationEvent.begin(); + + result = compiler.compile(method, entryBCI, mustRecordMethodInlining(config)); + + result.setId(getId()); + } catch (Throwable e) { + throw Debug.handle(e); + } finally { + // End the compilation event. + compilationEvent.end(); + + filter.remove(); + final boolean printAfterCompilation = PrintAfterCompilation.getValue() && !TTY.isSuppressed(); + + if (printAfterCompilation || printCompilation) { + final long stop = System.currentTimeMillis(); + final int targetCodeSize = result != null ? result.getTargetCodeSize() : -1; + final long allocatedBytesAfter = threadMXBean.getThreadAllocatedBytes(threadId); + final long allocatedBytes = (allocatedBytesAfter - allocatedBytesBefore) / 1024; + + if (printAfterCompilation) { + TTY.println(getMethodDescription() + String.format(" | %4dms %5dB %5dkB", stop - start, targetCodeSize, allocatedBytes)); + } else if (printCompilation) { + TTY.println(String.format("%-6d Graal %-70s %-45s %-50s | %4dms %5dB %5dkB", id, "", "", "", stop - start, targetCodeSize, allocatedBytes)); + } + } + } + + try (DebugCloseable b = CodeInstallationTime.start()) { + installedCode = (HotSpotInstalledCode) installMethod(result); + } + stats.finish(method, installedCode); + } catch (BailoutException bailout) { + BAILOUTS.increment(); + if (ExitVMOnBailout.getValue()) { + TTY.cachedOut.println(method.format("Bailout in %H.%n(%p)")); + bailout.printStackTrace(TTY.cachedOut); + System.exit(-1); + } else if (PrintBailout.getValue()) { + TTY.cachedOut.println(method.format("Bailout in %H.%n(%p)")); + bailout.printStackTrace(TTY.cachedOut); + } + } catch (Throwable t) { + if (PrintStackTraceOnException.getValue() || ExitVMOnException.getValue()) { + t.printStackTrace(TTY.cachedOut); + } + + // Log a failure event. + CompilerFailureEvent event = eventProvider.newCompilerFailureEvent(); + if (event.shouldWrite()) { + event.setCompileId(getId()); + event.setMessage(t.getMessage()); + event.commit(); + } + + if (ExitVMOnException.getValue()) { + System.exit(-1); + } + } finally { + int compiledBytecodes = 0; + int codeSize = 0; + if (result != null) { + compiledBytecodes = result.getBytecodeSize(); + } + if (installedCode != null) { + codeSize = installedCode.getSize(); + } + CompiledBytecodes.add(compiledBytecodes); + + // Log a compilation event. + if (compilationEvent.shouldWrite()) { + compilationEvent.setMethod(method.format("%H.%n(%p)")); + compilationEvent.setCompileId(getId()); + compilationEvent.setCompileLevel(config.compilationLevelFullOptimization); + compilationEvent.setSucceeded(result != null && installedCode != null); + compilationEvent.setIsOsr(isOSR); + compilationEvent.setCodeSize(codeSize); + compilationEvent.setInlinedBytes(compiledBytecodes); + compilationEvent.commit(); + } + + if (graalEnv != 0) { + long ctask = unsafe.getAddress(graalEnv + config.jvmciEnvTaskOffset); + assert ctask != 0L; + unsafe.putInt(ctask + config.compileTaskNumInlinedBytecodesOffset, compiledBytecodes); + } + long compilationTime = System.nanoTime() - startCompilationTime; + if ((config.ciTime || config.ciTimeEach) && installedCode != null) { + long timeUnitsPerSecond = TimeUnit.NANOSECONDS.convert(1, TimeUnit.SECONDS); + CompilerToVM c2vm = HotSpotJVMCIRuntime.runtime().getCompilerToVM(); + c2vm.notifyCompilationStatistics(id, method, entryBCI != Compiler.INVOCATION_ENTRY_BCI, compiledBytecodes, compilationTime, timeUnitsPerSecond, installedCode); + } + } + } + + /** + * Determines whether to disable method inlining recording for the method being compiled. + */ + private boolean mustRecordMethodInlining(HotSpotVMConfig config) { + if (config.ciTime || config.ciTimeEach || CompiledBytecodes.isEnabled()) { + return true; + } + if (graalEnv == 0 || unsafe.getByte(graalEnv + config.jvmciEnvJvmtiCanHotswapOrPostBreakpointOffset) != 0) { + return true; + } + return false; + } + + private String getMethodDescription() { + return String.format("%-6d Graal %-70s %-45s %-50s %s", id, method.getDeclaringClass().getName(), method.getName(), method.getSignature().toMethodDescriptor(), + entryBCI == Compiler.INVOCATION_ENTRY_BCI ? "" : "(OSR@" + entryBCI + ") "); + } + + private InstalledCode installMethod(final CompilationResult compResult) { + final HotSpotCodeCacheProvider codeCache = (HotSpotCodeCacheProvider) HotSpotJVMCIRuntime.runtime().getHostJVMCIBackend().getCodeCache(); + InstalledCode installedCode = null; + try (Scope s = Debug.scope("CodeInstall", new DebugDumpScope(String.valueOf(id), true), codeCache, method)) { + installedCode = codeCache.installMethod(method, compResult, graalEnv, installAsDefault); + } catch (Throwable e) { + throw Debug.handle(e); + } + return installedCode; + } + + @Override + public String toString() { + return "Compilation[id=" + id + ", " + method.format("%H.%n(%p)") + (entryBCI == Compiler.INVOCATION_ENTRY_BCI ? "" : "@" + entryBCI) + "]"; + } + + /** + * Compiles a method to machine code. + */ + public static void compileMethod(HotSpotResolvedJavaMethod method, int entryBCI, long graalEnv, int id) { + // Ensure a debug configuration for this thread is initialized + if (Debug.isEnabled() && DebugScope.getConfig() == null) { + DebugEnvironment.initialize(TTY.cachedOut); + } + + CompilationTask task = new CompilationTask(method, entryBCI, graalEnv, id, true); + try (DebugConfigScope dcs = setConfig(new TopLevelDebugConfig())) { + task.runCompilation(); + } + return; + } +}