package org.graalvm.polybench;
import java.io.IOException;
import java.util.Collections;
import java.util.Map;
import java.util.Optional;
import java.util.logging.Level;
import java.util.logging.Logger;
final class CompilationTimeMetric implements Metric {
enum MetricType {
COMPILATION(null),
PARTIAL_EVALUATION("peTime");
private final String fieldName;
MetricType(String fieldName) {
this.fieldName = fieldName;
}
String getFieldName() {
return fieldName;
}
}
private static final Logger LOG = Logger.getLogger(CompilationTimeMetric.class.getName());
private static final String TRUFFLE_COMPILATION_EVENT = "org.graalvm.compiler.truffle.Compilation";
private final MetricType metricType;
private final boolean supported;
private Object recording;
private Object snapshot;
CompilationTimeMetric(MetricType metricType) {
this.metricType = metricType;
this.supported = JFRSupport.isAvailable();
}
@Override
public void validateConfig(Config config, Map<String, String> polyglotOptions) {
if (Boolean.parseBoolean(polyglotOptions.get("engine.BackgroundCompilation"))) {
throw new IllegalStateException("The Compile Time Metric cannot be used with a background compilation.\n" +
"Remove the 'engine.BackgroundCompilation=true' option.");
}
}
@Override
public Map<String, String> getEngineOptions(Config config) {
return Collections.singletonMap("engine.BackgroundCompilation", "false");
}
@Override
public String unit() {
return "ms";
}
@Override
public String name() {
return "compilation time";
}
@Override
public void beforeIteration(boolean warmup, int iteration, Config config) {
if (supported) {
if (recording == null) {
recording = JFRSupport.startRecording(TRUFFLE_COMPILATION_EVENT);
}
JFRSupport.disposeRecording(snapshot, false);
snapshot = null;
}
}
@Override
public void afterIteration(boolean warmup, int iteration, Config config) {
if (supported) {
if (recording == null) {
throw new IllegalStateException("Missing JFR recording.");
}
if (snapshot != null) {
throw new IllegalStateException("Existing JFR snapshot.");
}
snapshot = JFRSupport.snapshotRecording(recording);
}
}
@Override
public void reset() {
if (supported) {
JFRSupport.disposeRecording(recording, true);
recording = null;
JFRSupport.disposeRecording(snapshot, false);
snapshot = null;
}
}
@Override
public Optional<Double> reportAfterIteration(Config config) {
return supported ? computeCumulativeTime() : Optional.of(0.0);
}
@Override
public Optional<Double> reportAfterAll() {
return supported && recording != null ? computeCumulativeTime() : Optional.of(0.0);
}
private Optional<Double> computeCumulativeTime() {
if (snapshot == null) {
throw new IllegalStateException("No snapshot.");
}
try {
return Optional.of(1.0 * JFRSupport.computeCumulativeTime(snapshot, TRUFFLE_COMPILATION_EVENT, metricType.getFieldName()));
} catch (IOException ioe) {
LOG.log(Level.SEVERE, "Cannot write recording.", ioe);
return Optional.empty();
}
}
}