Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Truffle compiler control based on HotSpot's CompileBroker compilation activity #10135

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -358,5 +358,4 @@ default ResolvedJavaType resolveType(MetaAccessProvider metaAccess, String class
* silent.
*/
boolean isSuppressedFailure(TruffleCompilable compilable, Supplier<String> serializedException);

}
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,8 @@ public int getQueueSize() {

/**
* Return call targets waiting in queue. This does not include call targets currently being
* compiled.
* compiled. If {@code engine} is {@code null}, the call targets for all engines are returned,
* otherwise only the call targets belonging to {@code engine} will be returned.
*/
public Collection<OptimizedCallTarget> getQueuedTargets(EngineData engine) {
BlockingQueue<Runnable> queue = this.compilationQueue;
Expand All @@ -230,7 +231,7 @@ public Collection<OptimizedCallTarget> getQueuedTargets(EngineData engine) {
CompilationTask.ExecutorServiceWrapper[] array = queue.toArray(new CompilationTask.ExecutorServiceWrapper[0]);
for (CompilationTask.ExecutorServiceWrapper wrapper : array) {
OptimizedCallTarget target = wrapper.compileTask.targetRef.get();
if (target != null && target.engine == engine) {
if (target != null && (engine == null || target.engine == engine)) {
queuedTargets.add(target);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
import static com.oracle.truffle.runtime.OptimizedRuntimeOptions.SplittingMaxCalleeSize;
import static com.oracle.truffle.runtime.OptimizedRuntimeOptions.SplittingMaxPropagationDepth;
import static com.oracle.truffle.runtime.OptimizedRuntimeOptions.SplittingTraceEvents;
import static com.oracle.truffle.runtime.OptimizedRuntimeOptions.StoppedCompilationRetryDelay;
import static com.oracle.truffle.runtime.OptimizedRuntimeOptions.TraceCompilation;
import static com.oracle.truffle.runtime.OptimizedRuntimeOptions.TraceCompilationDetails;
import static com.oracle.truffle.runtime.OptimizedRuntimeOptions.TraceDeoptimizeFrame;
Expand Down Expand Up @@ -148,6 +149,7 @@ public final class EngineData {
@CompilationFinal public boolean traceDeoptimizeFrame;
@CompilationFinal public boolean compileAOTOnCreate;
@CompilationFinal public boolean firstTierOnly;
@CompilationFinal public long stoppedCompilationRetryDelay;

// compilation queue options
@CompilationFinal public boolean priorityQueue;
Expand Down Expand Up @@ -305,6 +307,7 @@ private void loadOptions(OptionValues options, SandboxPolicy sandboxPolicy) {
this.firstTierOnly = options.get(Mode) == EngineModeEnum.LATENCY;
this.propagateCallAndLoopCount = options.get(PropagateLoopCountToLexicalSingleCaller);
this.propagateCallAndLoopCountMaxDepth = options.get(PropagateLoopCountToLexicalSingleCallerMaxDepth);
this.stoppedCompilationRetryDelay = options.get(StoppedCompilationRetryDelay);

// compilation queue options
priorityQueue = options.get(PriorityQueue);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
Expand All @@ -51,7 +52,9 @@
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import java.util.function.Supplier;
import java.util.logging.Level;

import com.oracle.truffle.api.TruffleLogger;
import org.graalvm.options.OptionKey;
import org.graalvm.options.OptionValues;

Expand Down Expand Up @@ -855,6 +858,60 @@ final boolean isCompilationFailed() {
return compilationFailed;
}

final boolean isCompilationStopped() {
OptimizedTruffleRuntime.CompilationActivityMode compilationActivityMode = runtime().getCompilationActivityMode();
long sct = runtime().stoppedCompilationTime().get();
if (compilationActivityMode == OptimizedTruffleRuntime.CompilationActivityMode.STOP_COMPILATION) {
if (sct != 0 && System.currentTimeMillis() - sct > engine.stoppedCompilationRetryDelay) {
runtime().stoppedCompilationTime().compareAndSet(sct, 0);
// Try again every StoppedCompilationRetryDelay milliseconds to potentially trigger a code cache sweep.
compilationActivityMode = OptimizedTruffleRuntime.CompilationActivityMode.RUN_COMPILATION;
}
}

switch (compilationActivityMode) {
case RUN_COMPILATION : {
// This is the common case - compilations are not stopped.
return false;
}
case STOP_COMPILATION : {
if (sct == 0) {
runtime().stoppedCompilationTime().compareAndSet(0, System.currentTimeMillis());
}
// Flush the compilations queue for now. There's still a chance that compilation
// will be re-enabled eventually, if the hosts code cache can be cleaned up.
Collection<OptimizedCallTarget> targets = runtime().getCompileQueue().getQueuedTargets(null);
// If there's just a single compilation target in the queue, the chance is high that it is
// the one we've just added after the StoppedCompilationRetryDelay ran out, so keep it to
// potentially trigger a code cache sweep.
if (targets.size() > 1) {
for (OptimizedCallTarget target : targets) {
target.cancelCompilation("Compilation temporary disabled due to full code cache.");
}
}
return true;
}
case SHUTDOWN_COMPILATION : {
// Compilation was shut down permanently because the hosts code cache ran full and
// the host was configured without support for code cache sweeping.
TruffleLogger logger = engine.getLogger("engine");
// The logger can be null if the engine is closed.
if (logger != null && runtime().logShutdownCompilations().compareAndExchange(true, false)) {
logger.log(Level.WARNING, "Truffle compilations permanently disabled because of full code cache. " +
"Increase the code cache size using '-XX:ReservedCodeCacheSize=' and/or run with '-XX:+UseCodeCacheFlushing -XX:+MethodFlushing'.");
}
try {
runtime().getCompileQueue().shutdownAndAwaitTermination(100 /* milliseconds */);
} catch (RuntimeException re) {
// Best effort, ignore failure
}
return true;
}
default : CompilerDirectives.shouldNotReachHere("Invalid compilation activity mode: " + compilationActivityMode);
}
return false;
}

/**
* Returns <code>true</code> if the call target was already compiled or was compiled
* synchronously. Returns <code>false</code> if compilation was not scheduled or is happening in
Expand All @@ -866,6 +923,7 @@ public final boolean compile(boolean lastTierCompilation) {
if (!needsCompile(lastTier)) {
return true;
}

if (!isSubmittedForCompilation()) {
if (!acceptForCompilation()) {
// do not try to compile again
Expand All @@ -881,6 +939,10 @@ public final boolean compile(boolean lastTierCompilation) {
return true;
}

if (isCompilationStopped()) {
return false;
}

ensureInitialized();
if (!isSubmittedForCompilation()) {
if (lastTier) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,15 @@ public ExceptionAction apply(String s) {
// TODO: GR-29949
public static final OptionKey<Long> CompilerIdleDelay = new OptionKey<>(10000L);

@Option(help = "Before the Truffle runtime submits an OptimizedCallTarget for compilation, it checks for the " +
simonis marked this conversation as resolved.
Show resolved Hide resolved
"compilation activity mode in the host VM. If the activity mode indicates a full code " +
"cache, no new compilation requests are submitted and the compilation queue is flushed. " +
"After 'StoppedCompilationRetryDelay' milliseconds new compilations will be submitted again " +
"(which might trigger a sweep of the code cache and a reset of the compilation activity mode in the host JVM)." +
"The option is only supported on the HotSpot Truffle runtime. On runtimes which don't support it the option has no effect. default: 1000",
usageSyntax = "<ms>", category = OptionCategory.EXPERT)
simonis marked this conversation as resolved.
Show resolved Hide resolved
public static final OptionKey<Long> StoppedCompilationRetryDelay = new OptionKey<>(1000L);

@Option(help = "Manually set the number of compiler threads. By default, the number of compiler threads is scaled with the number of available cores on the CPU.", usageSyntax = "[1, inf)", category = OptionCategory.EXPERT, //
stability = OptionStability.STABLE, sandbox = SandboxPolicy.UNTRUSTED) //
public static final OptionKey<Integer> CompilerThreads = new OptionKey<>(-1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.logging.Level;
Expand Down Expand Up @@ -912,6 +914,19 @@ private void notifyCompilationFailure(OptimizedCallTarget callTarget, Throwable
protected void onEngineCreated(EngineData engine) {
}


private final AtomicLong stoppedCompilationTime = new AtomicLong(0);

public final AtomicLong stoppedCompilationTime() {
return stoppedCompilationTime;
}

private final AtomicBoolean logShutdownCompilations = new AtomicBoolean(true);

public final AtomicBoolean logShutdownCompilations() {
return logShutdownCompilations;
}

@SuppressWarnings("try")
public CompilationTask submitForCompilation(OptimizedCallTarget optimizedCallTarget, boolean lastTierCompilation) {
Priority priority = new Priority(optimizedCallTarget.getCallAndLoopCount(), lastTierCompilation ? Priority.Tier.LAST : Priority.Tier.FIRST);
Expand Down Expand Up @@ -1483,4 +1498,30 @@ static OptionCategory matchCategory(TruffleCompilerOptionDescriptor d) {
}
}

/**
* Represents HotSpot's compilation activity mode which is one of:
* {@code stop_compilation = 0}, {@code run_compilation = 1} or {@code shutdown_compilation = 2}
* Should be in sync with the {@code CompilerActivity} enum in {@code hotspot/share/compiler/compileBroker.hpp}
*/
public enum CompilationActivityMode {
STOP_COMPILATION,
RUN_COMPILATION,
SHUTDOWN_COMPILATION;

static public CompilationActivityMode fromInteger(int i) {
return switch (i) {
case 0 -> STOP_COMPILATION;
case 1 -> RUN_COMPILATION;
case 2 -> SHUTDOWN_COMPILATION;
default -> throw new RuntimeException("Invalid CompilationActivityMode " + i);
};
}
}

/**
* Returns the current host compilation activity mode. The default is to run compilations.
*/
public CompilationActivityMode getCompilationActivityMode() {
return CompilationActivityMode.RUN_COMPILATION;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@
*/
package com.oracle.truffle.runtime.hotspot;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.ref.Reference;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
Expand Down Expand Up @@ -692,4 +695,31 @@ public boolean isLibGraalCompilationEnabled() {
return compilationSupport instanceof LibGraalTruffleCompilationSupport;
}

static final MethodHandle getCompilationActivityMode;
static {
MethodHandle mHandle = null;
try {
MethodType mt = MethodType.methodType(int.class);
mHandle = MethodHandles.lookup().findVirtual(HotSpotJVMCIRuntime.class, "getCompilationActivityMode", mt);
} catch (NoSuchMethodException | IllegalAccessException e) {
// Older JVMCI runtimes might not support `getCompilationActivityMode()`
simonis marked this conversation as resolved.
Show resolved Hide resolved
}
getCompilationActivityMode = mHandle;
}

/**
* Returns the current host compilation activity mode based on HotSpot's code cache state.
*/
@Override
public CompilationActivityMode getCompilationActivityMode() {
int activityMode = 1; // Default is to run compilations
if (getCompilationActivityMode != null) {
try {
activityMode = (int) getCompilationActivityMode.invokeExact(HotSpotJVMCIRuntime.runtime());
} catch (Throwable t) {
throw new RuntimeException("Can't get HotSpot's compilation activity mode", t);
}
}
return CompilationActivityMode.fromInteger(activityMode);
}
}
Loading