Skip to content

Commit

Permalink
Merge pull request #26537 from mkouba/build-step-dependency-graph
Browse files Browse the repository at this point in the history
Dev UI build steps view improvements
  • Loading branch information
gsmet authored Jul 7, 2022
2 parents c95c4a0 + 25d8a12 commit 91ba399
Show file tree
Hide file tree
Showing 12 changed files with 687 additions and 81 deletions.
6 changes: 6 additions & 0 deletions build-parent/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@
<!-- we don't add mermaid as a dependency as it brings a ton of things we don't use -->
<webjar.mermaid.version>8.9.1</webjar.mermaid.version>
<webjar.d3js.version>6.6.0</webjar.d3js.version>
<webjar.chartjs.version>3.7.1</webjar.chartjs.version>

<!-- revapi API check -->
<revapi-maven-plugin.version>0.14.6</revapi-maven-plugin.version>
Expand Down Expand Up @@ -321,6 +322,11 @@
<artifactId>d3js</artifactId>
<version>${webjar.d3js.version}</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>chartjs</artifactId>
<version>${webjar.chartjs.version}</version>
</dependency>

<dependency>
<groupId>com.github.davidmoten</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ void run() {
}
} finally {
long duration = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
execution.getMetrics().buildStepFinished(buildStep.getId(), currentThread.getName(), started, duration);
execution.getMetrics().buildStepFinished(stepInfo, currentThread.getName(), started, duration);
log.tracef("Finished step \"%s\" in %s ms", buildStep, duration);
execution.removeBuildContext(stepInfo, this);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.quarkus.builder.metrics;
package io.quarkus.builder;

import java.io.BufferedWriter;
import java.io.FileWriter;
Expand All @@ -19,20 +19,22 @@

import org.jboss.logging.Logger;

import io.quarkus.builder.metrics.Json.JsonArrayBuilder;
import io.quarkus.builder.metrics.Json.JsonObjectBuilder;
import io.quarkus.builder.Json.JsonArrayBuilder;
import io.quarkus.builder.Json.JsonObjectBuilder;

public class BuildMetrics {

static final Logger LOG = Logger.getLogger(BuildMetrics.class.getName());

private volatile LocalDateTime started;
private volatile long duration;
private final String buildTargetName;
private final ConcurrentMap<String, BuildStepRecord> records = new ConcurrentHashMap<>();
private final AtomicInteger duplicates = new AtomicInteger();
private final AtomicInteger idGenerator;

public BuildMetrics(String buildTargetName) {
this.buildTargetName = buildTargetName;
this.idGenerator = new AtomicInteger();
}

public Collection<BuildStepRecord> getRecords() {
Expand All @@ -43,13 +45,13 @@ public void buildStarted() {
this.started = LocalDateTime.now().truncatedTo(ChronoUnit.MILLIS);
}

public void buildStepFinished(String stepId, String thread, LocalTime started, long duration) {
BuildStepRecord prev = records.putIfAbsent(stepId, new BuildStepRecord(stepId, thread, started, duration));
if (prev != null) {
String newName = stepId + "_d#" + duplicates.incrementAndGet();
LOG.debugf("A build step with the same identifier already exists - added a generated suffix: %s", newName);
buildStepFinished(newName, thread, started, duration);
}
public void buildFinished(long duration) {
this.duration = duration;
}

public void buildStepFinished(StepInfo stepInfo, String thread, LocalTime started, long duration) {
records.put(stepInfo.getBuildStep().getId(),
new BuildStepRecord(idGenerator.incrementAndGet(), stepInfo, thread, started, duration));
}

public void dumpTo(Path file) throws IOException {
Expand All @@ -66,16 +68,28 @@ public int compare(BuildStepRecord o1, BuildStepRecord o2) {
JsonObjectBuilder json = Json.object();
json.put("buildTarget", buildTargetName);
json.put("started", started.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
json.put("duration", duration);

JsonArrayBuilder steps = Json.array();
json.put("steps", steps);
json.put("records", steps);
for (BuildStepRecord rec : sorted) {
JsonObjectBuilder recJson = Json.object();
recJson.put("stepId", rec.stepId);
recJson.put("thread", rec.thread);
recJson.put("started", rec.started.format(formatter));
recJson.put("duration", rec.duration);
steps.add(recJson);
JsonObjectBuilder recObject = Json.object();
recObject.put("id", rec.id);
recObject.put("stepId", rec.stepInfo.getBuildStep().getId());
recObject.put("thread", rec.thread);
recObject.put("started", rec.started.format(formatter));
recObject.put("duration", rec.duration);
JsonArrayBuilder dependentsArray = Json.array();
for (StepInfo dependent : rec.stepInfo.getDependents()) {
BuildStepRecord dependentRecord = records.get(dependent.getBuildStep().getId());
if (dependentRecord != null) {
dependentsArray.add(dependentRecord.id);
} else {
LOG.warnf("Dependent record not found for stepId: %s", dependent.getBuildStep().getId());
}
}
recObject.put("dependents", dependentsArray);
steps.add(recObject);
}
try (BufferedWriter writer = new BufferedWriter(new FileWriter(file.toFile(), StandardCharsets.UTF_8))) {
json.appendTo(writer);
Expand All @@ -85,9 +99,11 @@ public int compare(BuildStepRecord o1, BuildStepRecord o2) {
public static class BuildStepRecord {

/**
* The identifier of the build step.
* A unique record id.
*/
public final String stepId;
public final int id;

public final StepInfo stepInfo;

/**
* The name of the thread this build step was executed on.
Expand All @@ -104,8 +120,9 @@ public static class BuildStepRecord {
*/
public final long duration;

BuildStepRecord(String stepId, String thread, LocalTime started, long duration) {
this.stepId = stepId;
BuildStepRecord(int id, StepInfo stepInfo, String thread, LocalTime started, long duration) {
this.id = id;
this.stepInfo = stepInfo;
this.thread = thread;
this.started = started;
this.duration = duration;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import io.quarkus.builder.item.BuildItem;
import io.quarkus.builder.item.MultiBuildItem;
import io.quarkus.builder.item.SimpleBuildItem;
import io.quarkus.builder.metrics.BuildMetrics;

/**
* The final result of a successful deployment operation.
Expand Down
5 changes: 3 additions & 2 deletions core/builder/src/main/java/io/quarkus/builder/Execution.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@

import io.quarkus.builder.diag.Diagnostic;
import io.quarkus.builder.item.BuildItem;
import io.quarkus.builder.metrics.BuildMetrics;

/**
*/
Expand Down Expand Up @@ -133,8 +132,10 @@ BuildResult run() throws BuildException {
if (lastStepCount.get() > 0)
throw new BuildException("Extra steps left over", Collections.emptyList());

long duration = max(0, System.nanoTime() - start);
metrics.buildFinished(TimeUnit.NANOSECONDS.toMillis(duration));
return new BuildResult(singles, multis, finalIds, Collections.unmodifiableList(diagnostics),
max(0, System.nanoTime() - start), metrics);
duration, metrics);
}

EnhancedQueueExecutor getExecutor() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.quarkus.builder.metrics;
package io.quarkus.builder;

import java.io.IOException;
import java.util.ArrayList;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,17 @@ public static Consumer<BuildChainBuilder> loadStepsFrom(ClassLoader classLoader,

Consumer<BuildChainBuilder> result = Functions.discardingConsumer();
// BooleanSupplier factory
result = result.andThen(bcb -> bcb.addBuildStep(bc -> {
bc.produce(bsf);
result = result.andThen(bcb -> bcb.addBuildStep(new io.quarkus.builder.BuildStep() {

@Override
public void execute(BuildContext context) {
context.produce(bsf);
}

@Override
public String getId() {
return ExtensionLoader.class.getName() + "#booleanSupplierFactory";
}
}).produces(BooleanSupplierFactoryBuildItem.class).build());

// the proxy objects used for run time config in the recorders
Expand Down Expand Up @@ -226,40 +235,49 @@ public static Consumer<BuildChainBuilder> loadStepsFrom(ClassLoader classLoader,

throw new IllegalStateException("No config found for " + entry.getKey());
}
result = result.andThen(bcb -> bcb.addBuildStep(bc -> {
bc.produce(new ConfigurationBuildItem(readResult));
bc.produce(new RunTimeConfigurationProxyBuildItem(proxies));
result = result.andThen(bcb -> bcb.addBuildStep(new io.quarkus.builder.BuildStep() {

ObjectLoader rootLoader = new ObjectLoader() {
public ResultHandle load(final BytecodeCreator body, final Object obj, final boolean staticInit) {
return body.readStaticField(rootFields.get(obj));
}
@Override
public void execute(BuildContext bc) {
bc.produce(new ConfigurationBuildItem(readResult));
bc.produce(new RunTimeConfigurationProxyBuildItem(proxies));

public boolean canHandleObject(final Object obj, final boolean staticInit) {
return rootFields.containsKey(obj);
}
};
ObjectLoader rootLoader = new ObjectLoader() {
public ResultHandle load(final BytecodeCreator body, final Object obj, final boolean staticInit) {
return body.readStaticField(rootFields.get(obj));
}

ObjectLoader mappingLoader = new ObjectLoader() {
@Override
public ResultHandle load(final BytecodeCreator body, final Object obj, final boolean staticInit) {
ConfigClassWithPrefix mapping = mappingClasses.get(obj);
MethodDescriptor getConfig = MethodDescriptor.ofMethod(ConfigProvider.class, "getConfig", Config.class);
ResultHandle config = body.invokeStaticMethod(getConfig);
MethodDescriptor getMapping = MethodDescriptor.ofMethod(SmallRyeConfig.class, "getConfigMapping",
Object.class, Class.class, String.class);
return body.invokeVirtualMethod(getMapping, config, body.loadClass(mapping.getKlass()),
body.load(mapping.getPrefix()));
}
public boolean canHandleObject(final Object obj, final boolean staticInit) {
return rootFields.containsKey(obj);
}
};

@Override
public boolean canHandleObject(final Object obj, final boolean staticInit) {
return mappingClasses.containsKey(obj);
}
};
ObjectLoader mappingLoader = new ObjectLoader() {
@Override
public ResultHandle load(final BytecodeCreator body, final Object obj, final boolean staticInit) {
ConfigClassWithPrefix mapping = mappingClasses.get(obj);
MethodDescriptor getConfig = MethodDescriptor.ofMethod(ConfigProvider.class, "getConfig", Config.class);
ResultHandle config = body.invokeStaticMethod(getConfig);
MethodDescriptor getMapping = MethodDescriptor.ofMethod(SmallRyeConfig.class, "getConfigMapping",
Object.class, Class.class, String.class);
return body.invokeVirtualMethod(getMapping, config, body.loadClass(mapping.getKlass()),
body.load(mapping.getPrefix()));
}

bc.produce(new BytecodeRecorderObjectLoaderBuildItem(rootLoader));
bc.produce(new BytecodeRecorderObjectLoaderBuildItem(mappingLoader));
@Override
public boolean canHandleObject(final Object obj, final boolean staticInit) {
return mappingClasses.containsKey(obj);
}
};

bc.produce(new BytecodeRecorderObjectLoaderBuildItem(rootLoader));
bc.produce(new BytecodeRecorderObjectLoaderBuildItem(mappingLoader));
}

@Override
public String getId() {
return ExtensionLoader.class.getName() + "#config";
}

}).produces(ConfigurationBuildItem.class)
.produces(RunTimeConfigurationProxyBuildItem.class)
Expand Down
18 changes: 18 additions & 0 deletions extensions/vertx-http/deployment/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@
<artifactId>d3js</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>chartjs</artifactId>
<scope>provided</scope>
</dependency>
<!-- Test dependencies -->
<dependency>
<groupId>io.quarkus</groupId>
Expand Down Expand Up @@ -316,6 +321,19 @@
<org.codehaus.plexus.components.io.filemappers.FlattenFileMapper/>
</fileMappers>
</artifactItem>
<!-- chart.js -->
<artifactItem>
<groupId>org.webjars</groupId>
<artifactId>chartjs</artifactId>
<version>${webjar.chartjs.version}</version>
<type>jar</type>
<overWrite>true</overWrite>
<outputDirectory>${project.build.directory}/classes/dev-static/js/</outputDirectory>
<includes>**/chart.min.js</includes>
<fileMappers>
<org.codehaus.plexus.components.io.filemappers.FlattenFileMapper/>
</fileMappers>
</artifactItem>
</artifactItems>
</configuration>
</execution>
Expand Down
Loading

0 comments on commit 91ba399

Please sign in to comment.