Skip to content

Commit

Permalink
Capture Async profiler output from Maven builds
Browse files Browse the repository at this point in the history
  • Loading branch information
lptr committed Sep 2, 2024
1 parent 52e0d51 commit 34acf35
Show file tree
Hide file tree
Showing 18 changed files with 107 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public File getToolHome() {

@Override
public boolean createsMultipleProcesses() {
return false;
return true;
}

@Override
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/org/gradle/profiler/CompositeProfiler.java
Original file line number Diff line number Diff line change
Expand Up @@ -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(", "));
Expand Down
10 changes: 8 additions & 2 deletions src/main/java/org/gradle/profiler/InstrumentingProfiler.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@
* <p>The profiler may support starting recording multiple times for a given JVM. The implementation should indicate this by overriding {@link #canRestartRecording(ScenarioSettings)}.</p>
*/
public abstract class InstrumentingProfiler extends Profiler {

@Override
public boolean requiresGradle() {
return false;
}

/**
* Calculates the JVM args for all builds, including warm-ups.
*
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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;
Expand Down
12 changes: 11 additions & 1 deletion src/main/java/org/gradle/profiler/Profiler.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<String> reporter) {
}

Expand Down
14 changes: 14 additions & 0 deletions src/main/java/org/gradle/profiler/ScenarioDefinition.java
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -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() {
Expand Down Expand Up @@ -98,6 +107,7 @@ public void printTo(PrintStream out) {
}

public void visitProblems(InvocationSettings settings, Consumer<String> reporter) {
settings.getProfiler().validate(new ScenarioSettings(settings, this), reporter);
}

protected void printDetail(PrintStream out) {
Expand All @@ -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("/", "-");
}
}
6 changes: 3 additions & 3 deletions src/main/java/org/gradle/profiler/ScenarioLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ static List<ScenarioDefinition> 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);
Expand Down Expand Up @@ -330,8 +330,8 @@ private static List<BuildMutator> getMutators(Config scenario, String scenarioNa
}

private static Config getConfig(File scenarioFile, InvocationSettings settings, String scenarioName, Config scenario, String toolName, List<String> 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()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
public class BazelScenarioInvoker extends BuildToolCommandLineInvoker<BazelScenarioDefinition, BuildInvocationResult> {
@Override
public void run(BazelScenarioDefinition scenario, InvocationSettings settings, Consumer<BuildInvocationResult> resultConsumer) {
if (settings.isProfile()) {
throw new IllegalArgumentException("Profiling is not supported for Buck builds");
}

List<String> targets = scenario.getTargets();

List<String> commandLine = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
public class BuckScenarioInvoker extends BuildToolCommandLineInvoker<BuckScenarioDefinition, BuildInvocationResult> {
@Override
public void run(BuckScenarioDefinition scenario, InvocationSettings settings, Consumer<BuildInvocationResult> resultConsumer) {
if (settings.isProfile()) {
throw new IllegalArgumentException("Profiling is not supported for Buck builds");
}

String buckwExe = settings.getProjectDir() + "/buckw";
List<String> targets = new ArrayList<>(scenario.getTargets());
if (scenario.getType() != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ public String toString() {
return "chrome-trace";
}

@Override
public boolean requiresGradle() {
return true;
}


@Override
public void summarizeResultFile(File resultFile, Consumer<String> consumer) {
if (resultFile.getName().endsWith("-trace.json")) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -133,7 +132,7 @@ public void visitProblems(InvocationSettings settings, Consumer<String> 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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/gradle/profiler/jfr/JfrProfiler.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public void summarizeResultFile(File resultFile, Consumer<String> consumer) {
}

@Override
protected SnapshotCapturingProfilerController doNewController(ScenarioSettings settings) {
public SnapshotCapturingProfilerController newSnapshottingController(ScenarioSettings settings) {
return new JFRControl(jfrArgs, settings.computeJfrProfilerOutputLocation());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public String getDisplayName() {

@Override
public String getProfileName() {
throw new UnsupportedOperationException();
return safeFileName(getName()) + "-mvn";
}

@Override
Expand Down
32 changes: 30 additions & 2 deletions src/main/java/org/gradle/profiler/maven/MavenScenarioInvoker.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<MavenScenarioDefinition, BuildInvocationResult> {
@Override
public void run(MavenScenarioDefinition scenario, InvocationSettings settings, Consumer<BuildInvocationResult> resultConsumer) {
public void run(MavenScenarioDefinition scenario, InvocationSettings settings, Consumer<BuildInvocationResult> resultConsumer) throws IOException, InterruptedException {
List<String> 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<String, String> environment;
SnapshotCapturingProfilerController controller;
if (settings.getProfiler() instanceof InstrumentingProfiler) {
InstrumentingProfiler profiler = (InstrumentingProfiler) settings.getProfiler();
ScenarioSettings scenarioSettings = new ScenarioSettings(settings, scenario);
List<String> 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();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ protected boolean canRestartRecording(ScenarioSettings settings) {
}

@Override
protected SnapshotCapturingProfilerController doNewController(ScenarioSettings settings) {
public SnapshotCapturingProfilerController newSnapshottingController(ScenarioSettings settings) {
return new YourKitProfilerController(yourKitConfig);
}

Expand Down

0 comments on commit 34acf35

Please sign in to comment.