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

Detect compilation while benchmarking #10574

Merged
merged 9 commits into from
Jul 18, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
import com.oracle.truffle.api.library.CachedLibrary;
import com.oracle.truffle.api.library.ExportLibrary;
import com.oracle.truffle.api.library.ExportMessage;
import com.oracle.truffle.api.nodes.ExplodeLoop;
import com.oracle.truffle.api.nodes.Node;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
Expand Down Expand Up @@ -157,21 +159,54 @@ private Type getSupertype() {
return supertype;
}

/**
* All types this type represents including super types.
*
* @param ctx contexts to get Any type (common super class) from
* @return a compilation constant array with all types this type represents
*/
public final Type[] allTypes(EnsoContext ctx) {
if (supertype == null) {
if (builtin) {
return new Type[] {this};
var types = new Type[3];
var realCount = fillInTypes(this, types, ctx);
return Arrays.copyOf(types, realCount);
}

/**
* Fills the provided {@code fill} array with all types the {@code self} type can represent. E.g.
* including super classes.
*
* @param self the type to "enroll"
* @param fill the array to fill
* @param ctx context to obtain Any type from
* @return number of types put into the {@code fill} array
*/
@ExplodeLoop
private static int fillInTypes(Type self, Type[] fill, EnsoContext ctx) {
var at = 0;
while (at < fill.length) {
fill[at++] = self;
if (self.supertype == null) {
if (self.builtin) {
return at;
}
fill[at++] = ctx.getBuiltins().any();
return at;
}
return new Type[] {this, ctx.getBuiltins().any()};
}
if (supertype == ctx.getBuiltins().any()) {
return new Type[] {this, ctx.getBuiltins().any()};
if (self.supertype == ctx.getBuiltins().any()) {
fill[at++] = ctx.getBuiltins().any();
return at;
}
if (self == self.supertype) {
return at;
}
self = self.supertype;
}
var superTypes = supertype.allTypes(ctx);
var allTypes = new Type[superTypes.length + 1];
System.arraycopy(superTypes, 0, allTypes, 1, superTypes.length);
allTypes[0] = this;
return allTypes;
throw CompilerDirectives.shouldNotReachHere(invalidInTypes(self));
}

@CompilerDirectives.TruffleBoundary
private static String invalidInTypes(Type self) {
return "Cannot compute allTypes for " + self;
}

public void generateGetters(EnsoLanguage language) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,21 @@ public class BenchProcessor extends AbstractProcessor {
"import java.util.Objects;",
"import java.util.concurrent.TimeUnit;",
"import java.util.logging.Level;",
"import java.util.logging.LogRecord;",
"import java.util.logging.Handler;",
"import org.openjdk.jmh.annotations.Benchmark;",
"import org.openjdk.jmh.annotations.BenchmarkMode;",
"import org.openjdk.jmh.annotations.Mode;",
"import org.openjdk.jmh.annotations.Fork;",
"import org.openjdk.jmh.annotations.Measurement;",
"import org.openjdk.jmh.annotations.OutputTimeUnit;",
"import org.openjdk.jmh.annotations.Setup;",
"import org.openjdk.jmh.annotations.TearDown;",
"import org.openjdk.jmh.annotations.State;",
"import org.openjdk.jmh.annotations.Scope;",
"import org.openjdk.jmh.annotations.Warmup;",
"import org.openjdk.jmh.infra.BenchmarkParams;",
"import org.openjdk.jmh.infra.IterationParams;",
"import org.openjdk.jmh.infra.Blackhole;",
"import org.graalvm.polyglot.Context;",
"import org.graalvm.polyglot.Value;",
Expand Down Expand Up @@ -210,6 +214,13 @@ private void generateClassForGroup(
out.println("public class " + className + " {");

// Field definitions
out.println(" private int warmupCounter = 0;");
out.println(" private int measurementCounter = 0;");
out.println(" private boolean compilationMessagesFound;");
out.println(" private final StringBuilder compilationLog = new StringBuilder();");
out.println(
" private final List<LogRecord> messages = new"
+ " java.util.concurrent.CopyOnWriteArrayList<>();");
out.println(" private Value groupInputArg;");
for (var specJavaName : specJavaNames) {
out.println(" private Value benchFunc_" + specJavaName + ";");
Expand Down Expand Up @@ -237,7 +248,7 @@ private void generateClassForGroup(
out.println(" .allowExperimentalOptions(true)");
out.println(" .allowIO(IOAccess.ALL)");
out.println(" .allowAllAccess(true)");
out.println(" .option(RuntimeOptions.LOG_LEVEL, Level.WARNING.getName())");
out.println(" .option(RuntimeOptions.LOG_LEVEL, Level.FINE.getName())");
out.println(" .logHandler(System.err)");
out.println(" .option(");
out.println(" RuntimeOptions.LANGUAGE_HOME_OVERRIDE,");
Expand All @@ -247,6 +258,20 @@ private void generateClassForGroup(
out.println(" RuntimeOptions.PROJECT_ROOT,");
out.println(" projectRootDir.getAbsolutePath()");
out.println(" )");
out.println(
"""
.option("engine.TraceCompilation", "true")
.logHandler(new java.util.logging.Handler() {
@Override
public void publish(LogRecord lr) {
if ("engine".equals(lr.getLoggerName())) {
messages.add(lr);
}
}
@Override public void flush() {}
@Override public void close() {}
})
""");
out.println(" .build();");
out.println(" ");
out.println(" Value bindings = ctx.getBindings(LanguageInfo.ID);");
Expand Down Expand Up @@ -278,6 +303,55 @@ private void generateClassForGroup(
out.println(" } "); // end of setup method
out.println(" ");

out.println(
"""
@Setup(org.openjdk.jmh.annotations.Level.Iteration)
public void clearCompilationMessages(IterationParams it) {
var round = round(it);
if (!messages.isEmpty()) {
compilationLog.append("Before " + it.getType() + "#" + round + ". ");
compilationLog.append("Cleaning " + messages.size() + " compilation messages\\n");
messages.clear();
}
}

private int round(IterationParams it) {
return switch (it.getType()) {
case WARMUP -> ++warmupCounter;
case MEASUREMENT -> ++measurementCounter;
};
}

private void dumpMessages() {
for (var lr : messages) {
compilationLog.append(lr.getMessage() + "\\n");
compilationMessagesFound = true;
}
}

@TearDown(org.openjdk.jmh.annotations.Level.Iteration)
public void dumpCompilationMessages(IterationParams it) {
switch (it.getType()) {
case MEASUREMENT -> {
compilationLog.append("After " + it.getType() + "#" + measurementCounter + ". ");
if (!messages.isEmpty()) {
compilationLog.append("Dumping " + messages.size() + " compilation messages:\\n");
dumpMessages();
} else {
compilationLog.append("No compilation messages.\\n");
}
}
}
}

@TearDown
public void checkNoTruffleCompilation(BenchmarkParams params) {
if (compilationMessagesFound) {
System.err.println(compilationLog.toString());
}
}

""");
// Benchmark methods
for (var specJavaName : specJavaNames) {
out.println();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,12 @@
import org.openjdk.jmh.runner.RunnerException;

/**
* The only purpose for this class is to enable the {@link org.enso.benchmarks.processor.BenchProcessor}
* to generate JMH sources for the benchmarks in {@code test/Benchmarks} project.
* For more information see {@code docs/infrastructure/benchmarks.md#Standard-library-benchmarks}.
* The only purpose for this class is to enable the {@link
* org.enso.benchmarks.processor.BenchProcessor} to generate JMH sources for the benchmarks in
* {@code test/Benchmarks} project. For more information see {@code
* docs/infrastructure/benchmarks.md#Standard-library-benchmarks}.
*/
@GenerateBenchSources(
projectRootPath = "test/Benchmarks",
moduleName = "local.Benchmarks.Main"
)
@GenerateBenchSources(projectRootPath = "test/Benchmarks", moduleName = "local.Benchmarks.Main")
public class LibBenchRunner {

public static void main(String[] args) throws RunnerException {
Expand Down
2 changes: 1 addition & 1 deletion test/Benchmarks/src/Vector/Operations.enso
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import project.Vector.Utils
polyglot java import java.util.Random as Java_Random


options = Bench.options . set_warmup (Bench.phase_conf 2 5) . set_measure (Bench.phase_conf 1 5)
options = Bench.options . set_warmup (Bench.phase_conf 5 5) . set_measure (Bench.phase_conf 1 5)


collect_benches = Bench.build builder->
Expand Down
Loading