diff --git a/src/main/java/org/gradle/profiler/BuildToolCommandLineScenarioDefinition.java b/src/main/java/org/gradle/profiler/BuildToolCommandLineScenarioDefinition.java index 07cf74fa..bd954886 100644 --- a/src/main/java/org/gradle/profiler/BuildToolCommandLineScenarioDefinition.java +++ b/src/main/java/org/gradle/profiler/BuildToolCommandLineScenarioDefinition.java @@ -53,7 +53,7 @@ public File getToolHome() { @Override public boolean createsMultipleProcesses() { - return false; + return true; } @Override diff --git a/src/main/java/org/gradle/profiler/CompositeProfiler.java b/src/main/java/org/gradle/profiler/CompositeProfiler.java index c6df0b89..d5a4a052 100644 --- a/src/main/java/org/gradle/profiler/CompositeProfiler.java +++ b/src/main/java/org/gradle/profiler/CompositeProfiler.java @@ -13,6 +13,11 @@ class CompositeProfiler extends Profiler { this.delegates = delegates; } + @Override + public boolean requiresGradle() { + return delegates.stream().anyMatch(Profiler::requiresGradle); + } + @Override public String toString() { return delegates.stream().map(Object::toString).collect(Collectors.joining(", ")); diff --git a/src/main/java/org/gradle/profiler/InstrumentingProfiler.java b/src/main/java/org/gradle/profiler/InstrumentingProfiler.java index def89933..6630ccfa 100644 --- a/src/main/java/org/gradle/profiler/InstrumentingProfiler.java +++ b/src/main/java/org/gradle/profiler/InstrumentingProfiler.java @@ -18,6 +18,12 @@ *

The profiler may support starting recording multiple times for a given JVM. The implementation should indicate this by overriding {@link #canRestartRecording(ScenarioSettings)}.

*/ public abstract class InstrumentingProfiler extends Profiler { + + @Override + public boolean requiresGradle() { + return false; + } + /** * Calculates the JVM args for all builds, including warm-ups. * @@ -67,7 +73,7 @@ public JvmArgsCalculator newInstrumentedBuildsJvmArgsCalculator(ScenarioSettings */ @Override public ProfilerController newController(String pid, ScenarioSettings settings) { - SnapshotCapturingProfilerController controller = doNewController(settings); + SnapshotCapturingProfilerController controller = newSnapshottingController(settings); if (settings.getScenario().getInvoker().isDoesNotUseDaemon()) { return new SessionOnlyController(pid, controller); } @@ -109,7 +115,7 @@ protected boolean canRestartRecording(ScenarioSettings settings) { */ protected abstract JvmArgsCalculator jvmArgsWithInstrumentation(ScenarioSettings settings, boolean startRecordingOnProcessStart, boolean captureSnapshotOnProcessExit); - protected abstract SnapshotCapturingProfilerController doNewController(ScenarioSettings settings); + public abstract SnapshotCapturingProfilerController newSnapshottingController(ScenarioSettings settings); public interface SnapshotCapturingProfilerController { void startRecording(String pid) throws IOException, InterruptedException; diff --git a/src/main/java/org/gradle/profiler/Profiler.java b/src/main/java/org/gradle/profiler/Profiler.java index 2f006905..7c0552a9 100644 --- a/src/main/java/org/gradle/profiler/Profiler.java +++ b/src/main/java/org/gradle/profiler/Profiler.java @@ -18,15 +18,25 @@ import java.io.File; import java.util.function.Consumer; -public class Profiler { +public abstract class Profiler { public static final Profiler NONE = new Profiler() { + @Override + public boolean requiresGradle() { + return false; + } + @Override public String toString() { return "none"; } }; + /** + * Whether this profiler supports only Gradle builds. + */ + public abstract boolean requiresGradle(); + public void validate(ScenarioSettings settings, Consumer reporter) { } diff --git a/src/main/java/org/gradle/profiler/ScenarioDefinition.java b/src/main/java/org/gradle/profiler/ScenarioDefinition.java index ee317744..d87c42d9 100644 --- a/src/main/java/org/gradle/profiler/ScenarioDefinition.java +++ b/src/main/java/org/gradle/profiler/ScenarioDefinition.java @@ -1,8 +1,12 @@ package org.gradle.profiler; +import org.apache.commons.io.FileUtils; + import javax.annotation.Nullable; import java.io.File; +import java.io.IOException; import java.io.PrintStream; +import java.io.UncheckedIOException; import java.util.List; import java.util.function.Consumer; @@ -28,6 +32,11 @@ public ScenarioDefinition( this.warmUpCount = warmUpCount; this.buildCount = buildCount; this.outputDir = outputDir; + try { + FileUtils.forceMkdir(outputDir); + } catch (IOException e) { + throw new UncheckedIOException(e); + } } public void validate() { @@ -98,6 +107,7 @@ public void printTo(PrintStream out) { } public void visitProblems(InvocationSettings settings, Consumer reporter) { + settings.getProfiler().validate(new ScenarioSettings(settings, this), reporter); } protected void printDetail(PrintStream out) { @@ -108,4 +118,8 @@ protected void printDetail(PrintStream out) { public abstract boolean doesCleanup(); public abstract BuildConfiguration getBuildConfiguration(); + + public static String safeFileName(String name) { + return name.replace("/", "-"); + } } diff --git a/src/main/java/org/gradle/profiler/ScenarioLoader.java b/src/main/java/org/gradle/profiler/ScenarioLoader.java index aad08fb7..bea3d10d 100644 --- a/src/main/java/org/gradle/profiler/ScenarioLoader.java +++ b/src/main/java/org/gradle/profiler/ScenarioLoader.java @@ -237,7 +237,7 @@ static List loadScenarios(File scenarioFile, InvocationSetti String title = scenario.hasPath(TITLE) ? scenario.getString(TITLE) : null; int buildCount = getBuildCount(settings, scenario); - File scenarioBaseDir = selectedScenarios.size() == 1 ? settings.getOutputDir() : new File(settings.getOutputDir(), GradleScenarioDefinition.safeFileName(scenarioName)); + File scenarioBaseDir = selectedScenarios.size() == 1 ? settings.getOutputDir() : new File(settings.getOutputDir(), ScenarioDefinition.safeFileName(scenarioName)); if (scenario.hasPath(BAZEL) && settings.isBazel()) { Config executionInstructions = getConfig(scenarioFile, settings, scenarioName, scenario, BAZEL, BAZEL_KEYS); @@ -330,8 +330,8 @@ private static List getMutators(Config scenario, String scenarioNa } private static Config getConfig(File scenarioFile, InvocationSettings settings, String scenarioName, Config scenario, String toolName, List toolKeys) { - if (settings.isProfile()) { - throw new IllegalArgumentException("Can only profile scenario '" + scenarioName + "' when building using Gradle."); + if (settings.getProfiler().requiresGradle()) { + throw new IllegalArgumentException("Profiler " + settings.getProfiler() + " is not compatible with " + toolName + " scenarios."); } Config executionInstructions = scenario.getConfig(toolName); for (String key : scenario.getObject(toolName).keySet()) { diff --git a/src/main/java/org/gradle/profiler/asyncprofiler/AsyncProfiler.java b/src/main/java/org/gradle/profiler/asyncprofiler/AsyncProfiler.java index 051f321f..032cce1f 100644 --- a/src/main/java/org/gradle/profiler/asyncprofiler/AsyncProfiler.java +++ b/src/main/java/org/gradle/profiler/asyncprofiler/AsyncProfiler.java @@ -24,7 +24,7 @@ protected JvmArgsCalculator jvmArgsWithInstrumentation(ScenarioSettings settings } @Override - protected SnapshotCapturingProfilerController doNewController(ScenarioSettings settings) { + public SnapshotCapturingProfilerController newSnapshottingController(ScenarioSettings settings) { return new AsyncProfilerController(config, settings); } diff --git a/src/main/java/org/gradle/profiler/bazel/BazelScenarioInvoker.java b/src/main/java/org/gradle/profiler/bazel/BazelScenarioInvoker.java index 1581ef8c..9a630329 100644 --- a/src/main/java/org/gradle/profiler/bazel/BazelScenarioInvoker.java +++ b/src/main/java/org/gradle/profiler/bazel/BazelScenarioInvoker.java @@ -12,6 +12,10 @@ public class BazelScenarioInvoker extends BuildToolCommandLineInvoker { @Override public void run(BazelScenarioDefinition scenario, InvocationSettings settings, Consumer resultConsumer) { + if (settings.isProfile()) { + throw new IllegalArgumentException("Profiling is not supported for Buck builds"); + } + List targets = scenario.getTargets(); List commandLine = new ArrayList<>(); diff --git a/src/main/java/org/gradle/profiler/buck/BuckScenarioInvoker.java b/src/main/java/org/gradle/profiler/buck/BuckScenarioInvoker.java index 8ed25779..45e45b49 100644 --- a/src/main/java/org/gradle/profiler/buck/BuckScenarioInvoker.java +++ b/src/main/java/org/gradle/profiler/buck/BuckScenarioInvoker.java @@ -16,6 +16,10 @@ public class BuckScenarioInvoker extends BuildToolCommandLineInvoker { @Override public void run(BuckScenarioDefinition scenario, InvocationSettings settings, Consumer resultConsumer) { + if (settings.isProfile()) { + throw new IllegalArgumentException("Profiling is not supported for Buck builds"); + } + String buckwExe = settings.getProjectDir() + "/buckw"; List targets = new ArrayList<>(scenario.getTargets()); if (scenario.getType() != null) { diff --git a/src/main/java/org/gradle/profiler/buildscan/BuildScanProfiler.java b/src/main/java/org/gradle/profiler/buildscan/BuildScanProfiler.java index 5a438a1d..967c89a1 100644 --- a/src/main/java/org/gradle/profiler/buildscan/BuildScanProfiler.java +++ b/src/main/java/org/gradle/profiler/buildscan/BuildScanProfiler.java @@ -33,6 +33,11 @@ public static String defaultBuildScanVersion(GradleVersion gradleVersion) { this.buildScanVersion = buildScanVersion; } + @Override + public boolean requiresGradle() { + return true; + } + @Override public String toString() { return "buildscan"; diff --git a/src/main/java/org/gradle/profiler/chrometrace/ChromeTraceProfiler.java b/src/main/java/org/gradle/profiler/chrometrace/ChromeTraceProfiler.java index da490476..d5db686e 100644 --- a/src/main/java/org/gradle/profiler/chrometrace/ChromeTraceProfiler.java +++ b/src/main/java/org/gradle/profiler/chrometrace/ChromeTraceProfiler.java @@ -13,6 +13,12 @@ public String toString() { return "chrome-trace"; } + @Override + public boolean requiresGradle() { + return true; + } + + @Override public void summarizeResultFile(File resultFile, Consumer consumer) { if (resultFile.getName().endsWith("-trace.json")) { diff --git a/src/main/java/org/gradle/profiler/gradle/GradleScenarioDefinition.java b/src/main/java/org/gradle/profiler/gradle/GradleScenarioDefinition.java index 5cb0485f..8977f18a 100644 --- a/src/main/java/org/gradle/profiler/gradle/GradleScenarioDefinition.java +++ b/src/main/java/org/gradle/profiler/gradle/GradleScenarioDefinition.java @@ -1,8 +1,11 @@ package org.gradle.profiler.gradle; -import org.gradle.profiler.*; +import org.gradle.profiler.BuildAction; +import org.gradle.profiler.BuildMutator; +import org.gradle.profiler.GradleBuildConfiguration; +import org.gradle.profiler.InvocationSettings; +import org.gradle.profiler.ScenarioDefinition; import org.gradle.profiler.buildops.BuildOperationUtil; -import org.gradle.profiler.gradle.GradleBuildInvoker; import org.gradle.util.GradleVersion; import java.io.File; @@ -60,10 +63,6 @@ public String getProfileName() { return safeFileName(getName()) + "-" + buildConfiguration.getGradleVersion().getVersion(); } - public static String safeFileName(String name) { - return name.replace("/", "-"); - } - @Override public String getBuildToolDisplayName() { return buildConfiguration.getGradleVersion().toString(); @@ -133,7 +132,7 @@ public void visitProblems(InvocationSettings settings, Consumer reporter if (settings.isMeasureConfigTime() && isBuildServiceUnsupported()) { reporter.accept("Measuring build configuration is only supported for Gradle 6.1-milestone-3 and later"); } - settings.getProfiler().validate(new ScenarioSettings(settings, this), reporter); + super.visitProblems(settings, reporter); } private boolean isBuildServiceUnsupported() { diff --git a/src/main/java/org/gradle/profiler/heapdump/HeapDumpProfiler.java b/src/main/java/org/gradle/profiler/heapdump/HeapDumpProfiler.java index a1aa38e5..9232b309 100644 --- a/src/main/java/org/gradle/profiler/heapdump/HeapDumpProfiler.java +++ b/src/main/java/org/gradle/profiler/heapdump/HeapDumpProfiler.java @@ -10,6 +10,11 @@ import java.util.function.Consumer; public class HeapDumpProfiler extends Profiler { + @Override + public boolean requiresGradle() { + return true; + } + @Override public GradleArgsCalculator newGradleArgsCalculator(ScenarioSettings settings) { return new GradleInstrumentation() { diff --git a/src/main/java/org/gradle/profiler/jfr/JfrProfiler.java b/src/main/java/org/gradle/profiler/jfr/JfrProfiler.java index be08e85e..9d04b894 100644 --- a/src/main/java/org/gradle/profiler/jfr/JfrProfiler.java +++ b/src/main/java/org/gradle/profiler/jfr/JfrProfiler.java @@ -29,7 +29,7 @@ public void summarizeResultFile(File resultFile, Consumer consumer) { } @Override - protected SnapshotCapturingProfilerController doNewController(ScenarioSettings settings) { + public SnapshotCapturingProfilerController newSnapshottingController(ScenarioSettings settings) { return new JFRControl(jfrArgs, settings.computeJfrProfilerOutputLocation()); } diff --git a/src/main/java/org/gradle/profiler/jprofiler/JProfilerProfiler.java b/src/main/java/org/gradle/profiler/jprofiler/JProfilerProfiler.java index 3c4ad27a..8498614f 100644 --- a/src/main/java/org/gradle/profiler/jprofiler/JProfilerProfiler.java +++ b/src/main/java/org/gradle/profiler/jprofiler/JProfilerProfiler.java @@ -32,7 +32,7 @@ protected boolean canRestartRecording(ScenarioSettings settings) { } @Override - protected SnapshotCapturingProfilerController doNewController(ScenarioSettings settings) { + public SnapshotCapturingProfilerController newSnapshottingController(ScenarioSettings settings) { return new JProfilerController(settings, jProfilerConfig); } diff --git a/src/main/java/org/gradle/profiler/maven/MavenScenarioDefinition.java b/src/main/java/org/gradle/profiler/maven/MavenScenarioDefinition.java index 1619e6f5..b4630cc3 100644 --- a/src/main/java/org/gradle/profiler/maven/MavenScenarioDefinition.java +++ b/src/main/java/org/gradle/profiler/maven/MavenScenarioDefinition.java @@ -36,7 +36,7 @@ public String getDisplayName() { @Override public String getProfileName() { - throw new UnsupportedOperationException(); + return safeFileName(getName()) + "-mvn"; } @Override diff --git a/src/main/java/org/gradle/profiler/maven/MavenScenarioInvoker.java b/src/main/java/org/gradle/profiler/maven/MavenScenarioInvoker.java index dc8851bb..630f2dde 100644 --- a/src/main/java/org/gradle/profiler/maven/MavenScenarioInvoker.java +++ b/src/main/java/org/gradle/profiler/maven/MavenScenarioInvoker.java @@ -2,22 +2,50 @@ import com.google.common.collect.ImmutableMap; import org.gradle.profiler.BuildToolCommandLineInvoker; +import org.gradle.profiler.InstrumentingProfiler; +import org.gradle.profiler.InstrumentingProfiler.SnapshotCapturingProfilerController; import org.gradle.profiler.InvocationSettings; +import org.gradle.profiler.ScenarioSettings; import org.gradle.profiler.result.BuildInvocationResult; +import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.function.Consumer; public class MavenScenarioInvoker extends BuildToolCommandLineInvoker { @Override - public void run(MavenScenarioDefinition scenario, InvocationSettings settings, Consumer resultConsumer) { + public void run(MavenScenarioDefinition scenario, InvocationSettings settings, Consumer resultConsumer) throws IOException, InterruptedException { List commandLine = new ArrayList<>(); commandLine.add(scenario.getExecutablePath()); commandLine.addAll(scenario.getTargets()); scenario.getSystemProperties().forEach((key, value) -> commandLine.add(String.format("-D%s=%s", key, value))); - doRun(scenario, settings, resultConsumer, commandLine, ImmutableMap.of()); + + Map environment; + SnapshotCapturingProfilerController controller; + if (settings.getProfiler() instanceof InstrumentingProfiler) { + InstrumentingProfiler profiler = (InstrumentingProfiler) settings.getProfiler(); + ScenarioSettings scenarioSettings = new ScenarioSettings(settings, scenario); + List mavenOpts = new ArrayList<>(); + profiler.newInstrumentedBuildsJvmArgsCalculator(scenarioSettings) + .calculateJvmArgs(mavenOpts); + environment = ImmutableMap.of( + "MAVEN_OPTS", String.join(" ", mavenOpts) + ); + + controller = profiler.newSnapshottingController(scenarioSettings); + } else { + environment = ImmutableMap.of(); + controller = null; + } + + doRun(scenario, settings, resultConsumer, commandLine, environment); + + if (controller != null) { + controller.stopSession(); + } } } diff --git a/src/main/java/org/gradle/profiler/yourkit/YourKitProfiler.java b/src/main/java/org/gradle/profiler/yourkit/YourKitProfiler.java index 0b0ce528..666c8ea5 100644 --- a/src/main/java/org/gradle/profiler/yourkit/YourKitProfiler.java +++ b/src/main/java/org/gradle/profiler/yourkit/YourKitProfiler.java @@ -32,7 +32,7 @@ protected boolean canRestartRecording(ScenarioSettings settings) { } @Override - protected SnapshotCapturingProfilerController doNewController(ScenarioSettings settings) { + public SnapshotCapturingProfilerController newSnapshottingController(ScenarioSettings settings) { return new YourKitProfilerController(yourKitConfig); }