Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import io.quarkus.infra.performance.graphics.charts.BarChart;
import io.quarkus.infra.performance.graphics.charts.Chart;
import io.quarkus.infra.performance.graphics.charts.CubeChart;
import io.quarkus.infra.performance.graphics.model.BenchmarkData;
import picocli.CommandLine.Command;
import picocli.CommandLine.Parameters;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,21 @@
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.function.BiFunction;

import jakarta.enterprise.context.ApplicationScoped;

import org.apache.batik.anim.dom.SAXSVGDocumentFactory;
import org.apache.batik.anim.dom.SVGDOMImplementation;
import org.apache.batik.svggen.SVGGraphics2D;
import org.apache.batik.util.XMLResourceDescriptor;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import io.quarkus.infra.performance.graphics.charts.Chart;
import io.quarkus.infra.performance.graphics.charts.InlinedSVG;
import io.quarkus.infra.performance.graphics.model.BenchmarkData;

@ApplicationScoped
Expand All @@ -34,10 +38,11 @@ public void generate(BiFunction<SVGGraphics2D, Theme, Chart> chartConstructor, B
svgGenerator.setSVGCanvasSize(new Dimension(1200, 600));

Chart chart = chartConstructor.apply(svgGenerator, theme);
chart.draw(plotDefinition.title(), data.results().getDatasets(plotDefinition.fun()));
chart.draw(plotDefinition.title(), data.results().getDatasets(plotDefinition.fun()), data.config());

Element root = svgGenerator.getRoot();
initialiseFonts(doc, root);
inlineGraphics(doc, root, chart.getInlinedSVGs());

outFile.getParentFile().mkdirs();
try (Writer out = new OutputStreamWriter(new FileOutputStream(outFile), StandardCharsets.UTF_8)) {
Expand All @@ -46,6 +51,15 @@ public void generate(BiFunction<SVGGraphics2D, Theme, Chart> chartConstructor, B
}
}

private void inlineGraphics(Document doc, Element root, Collection<InlinedSVG> inlinedSVGs) {
String parser = XMLResourceDescriptor.getXMLParserClassName();
SAXSVGDocumentFactory factory = new SAXSVGDocumentFactory(parser);

for (InlinedSVG inlinedSVG : inlinedSVGs) {
inlinedSVG.draw(factory, root, doc);
}
}

private static void initialiseFonts(Document doc, Element root) {
Element style = doc.createElementNS(svgNS, "style");
style.setTextContent(Theme.FONT.getCss());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@

import java.awt.Font;
import java.awt.geom.Rectangle2D;
import java.util.Collection;
import java.util.List;

import org.apache.batik.svggen.SVGGraphics2D;

import io.quarkus.infra.performance.graphics.Theme;
import io.quarkus.infra.performance.graphics.model.Config;

public class BarChart implements Chart {
private static final int BAR_THICKNESS = 44;
Expand All @@ -19,6 +21,7 @@ public class BarChart implements Chart {
private final int canvasHeight;
private final int canvasWidth;
private final Theme theme;
private FinePrint fineprint;

public BarChart(SVGGraphics2D g, Theme theme) {
this.g = g;
Expand All @@ -29,12 +32,11 @@ public BarChart(SVGGraphics2D g, Theme theme) {
}

@Override
public void draw(String title, List<Datapoint> data) {
public void draw(String title, List<Datapoint> data, Config metadata) {

g.setPaint(theme.background());
g.fill(new Rectangle2D.Double(0, 0, canvasWidth, canvasWidth));

// --- Draw section titles ---
g.setPaint(theme.text());

double maxValue = data.stream().map(d -> d.value().getValue()).max(Double::compare).orElse(1.0);
Expand All @@ -48,7 +50,8 @@ public void draw(String title, List<Datapoint> data) {
new Label(title, 0, titleTextSize).setTargetHeight(titleTextSize).setStyle(Font.BOLD).draw(titleCanvas);

int plotWidth = canvasWidth - 2 * leftMargin;
int plotHeight = canvasHeight - titleCanvas.getHeight();
int finePrintHeight = 80;
int plotHeight = canvasHeight - titleCanvas.getHeight() - finePrintHeight;
Subcanvas chartArea = new Subcanvas(g, plotWidth, plotHeight, leftMargin, titleCanvas.getHeight());

int y = 0;
Expand All @@ -57,6 +60,9 @@ public void draw(String title, List<Datapoint> data) {
int fudge = 40;
Subcanvas labelArea = new Subcanvas(chartArea, labelAllowance - fudge, plotHeight, 0, 0);
Subcanvas barArea = new Subcanvas(chartArea, barWidth, plotHeight, labelArea.getWidth(), 0);
int finePrintPadding = 300;
Subcanvas finePrintArea = new Subcanvas(chartArea, barWidth - 2 * finePrintPadding, finePrintHeight, finePrintPadding,
barArea.getHeight() - 50); // TODO Arbitrary fudge padding, remove when scaling work is done

for (Datapoint d : data) {
// If this framework isn't found, it will just be the text colour, which is fine
Expand All @@ -79,6 +85,14 @@ public void draw(String title, List<Datapoint> data) {
y += BAR_THICKNESS + barSpacing;

}

this.fineprint = new FinePrint(finePrintArea, theme);
fineprint.draw(metadata);
}

@Override
public Collection<InlinedSVG> getInlinedSVGs() {
return fineprint.getInlinedSVGs();
}

}
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
package io.quarkus.infra.performance.graphics.charts;

import java.util.Collection;
import java.util.Collections;
import java.util.List;

import io.quarkus.infra.performance.graphics.model.Config;

public interface Chart {

void draw(String title, List<Datapoint> datasets);
void draw(String title, List<Datapoint> datasets, Config metadata);

// SVGs after to be done *after* the main drawing, because getting the document root before drawing causes all subsequent draws to be dropped.
// This seems to be a characteristic of the Batik streaming model.
default Collection<InlinedSVG> getInlinedSVGs() {
return Collections.emptyList();
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
package io.quarkus.infra.performance.graphics;
package io.quarkus.infra.performance.graphics.charts;

import static java.lang.Math.round;

import java.awt.Font;
import java.awt.geom.Rectangle2D;
import java.util.Collection;
import java.util.List;

import org.apache.batik.svggen.SVGGraphics2D;

import io.quarkus.infra.performance.graphics.charts.Alignment;
import io.quarkus.infra.performance.graphics.charts.Chart;
import io.quarkus.infra.performance.graphics.charts.Datapoint;
import io.quarkus.infra.performance.graphics.charts.Label;
import io.quarkus.infra.performance.graphics.charts.Subcanvas;
import io.quarkus.infra.performance.graphics.Theme;
import io.quarkus.infra.performance.graphics.VAlignment;
import io.quarkus.infra.performance.graphics.model.Config;

public class CubeChart implements Chart {
private static final int BAR_THICKNESS = 44;
Expand All @@ -23,6 +22,7 @@ public class CubeChart implements Chart {
private final int canvasHeight;
private final int canvasWidth;
private final Theme theme;
private FinePrint fineprint;

public CubeChart(SVGGraphics2D g, Theme theme) {
this.g = g;
Expand All @@ -33,7 +33,7 @@ public CubeChart(SVGGraphics2D g, Theme theme) {
}

@Override
public void draw(String title, List<Datapoint> data) {
public void draw(String title, List<Datapoint> data, Config metadata) {

g.setPaint(theme.background());
g.fill(new Rectangle2D.Double(0, 0, canvasWidth, canvasWidth));
Expand All @@ -53,6 +53,11 @@ public void draw(String title, List<Datapoint> data) {
int plotHeight = canvasHeight - titleCanvas.getHeight();

Subcanvas plotArea = new Subcanvas(g, plotWidth, plotHeight, leftMargin, titleCanvas.getHeight());
int finePrintHeight = 80;
int finePrintPadding = 300;
Subcanvas finePrintArea = new Subcanvas(g, plotArea.getWidth() - 2 * finePrintPadding, finePrintHeight,
finePrintPadding,
plotArea.getHeight() - 50); // TODO Arbitrary fudge padding, remove when scaling work is done);

int cubePadding = 1;

Expand Down Expand Up @@ -107,6 +112,12 @@ public void draw(String title, List<Datapoint> data) {
x += dataArea.getWidth() + dataPadding;

}
this.fineprint = new FinePrint(finePrintArea, theme);
fineprint.draw(metadata);
}

@Override
public Collection<InlinedSVG> getInlinedSVGs() {
return fineprint.getInlinedSVGs();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package io.quarkus.infra.performance.graphics.charts;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import io.quarkus.infra.performance.graphics.Theme;
import io.quarkus.infra.performance.graphics.VAlignment;
import io.quarkus.infra.performance.graphics.model.Config;

public class FinePrint {

private static final int padding = 60;

private final Subcanvas g;
private final int canvasHeight;
private final int canvasWidth;
private final Theme theme;
private InlinedSVG svg;

public FinePrint(Subcanvas g, Theme theme) {
this.g = g;
this.theme = theme;
this.canvasHeight = g.getHeight();
this.canvasWidth = g.getWidth();

}

public void draw(Config metadata) {

g.setPaint(theme.background());

g.setPaint(theme.text());

List<String> leftColumn = new ArrayList<>();
List<String> rightColumn = new ArrayList();

if (metadata.quarkus() != null) {
leftColumn.add("Quarkus: "
+ metadata.quarkus().version());
}
if (metadata.springboot() != null) {
leftColumn.add("Spring: "
+ metadata.springboot().version());
}
if (metadata.jvm() != null) {

if (metadata.jvm().graalVM() != null) {
leftColumn.add("JVM: "
+ metadata.jvm().graalVM().version());
}
leftColumn.add("GraalVM: "
+ metadata.jvm().version());

if (metadata.jvm().memory() != null) {
rightColumn.add("Memory: "
+ metadata.jvm().memory());
}

if (metadata.jvm().args() != null && metadata.jvm().args().contains("-XX:ActiveProcessorCount=")) {
// TODO risky calculation, what if the core is a cgroup or something else and not an arg?
rightColumn.add("CPUs: "
+ metadata.jvm().args().replace("-XX:ActiveProcessorCount=", ""));
}
}

if (metadata.repo() != null) {
rightColumn.add("Source code: "
+ metadata.repo().url().replace("https://github.com/", " ").replaceAll(".git$", ""));
// Use a few spaces to leave room for a logo
}

if (!"main".equals(metadata.repo().branch())) {
rightColumn.add("Branch: " + metadata.repo().branch());

}

// Make sure font sizes are the same
// TODO this can go away when we have label groups
while (rightColumn.size() < leftColumn.size()) {
// Put the padding before the last source control line
rightColumn.add(Math.max(0, rightColumn.size() - 1), " ");
}

Label leftLabel = new Label(leftColumn.toArray(String[]::new), 0, 0)
.setHorizontalAlignment(Alignment.LEFT)
.setVerticalAlignment(VAlignment.TOP)
.setTargetHeight(g.getHeight());
leftLabel.draw(g);

int leftLabelWidth = leftLabel
.calculateWidth(leftColumn.stream().max(Comparator.comparingInt(String::length)).orElse(""));
int rightLabelX = leftLabelWidth
+ padding;
Label rightLabel = new Label(rightColumn.toArray(String[]::new), rightLabelX, 0)
.setHorizontalAlignment(Alignment.LEFT)
.setVerticalAlignment(VAlignment.TOP)
.setTargetHeight(g.getHeight());
rightLabel.draw(g);
int sw = rightLabel.calculateWidth("Source code:");

if (metadata.repo() != null) {
int logoSize = rightLabel.getAscent();
int logoX = g.getXOffset() + rightLabelX + sw + 2;
int logoY = g.getYOffset() + (rightColumn.size()) * rightLabel.getLineHeight() - rightLabel.getAscent()
+ rightLabel.getDescent() / 2;
this.svg = new InlinedSVG(getPath(theme), logoSize,
logoX,
logoY);
}
}

private static String getPath(Theme theme) {
if (theme == Theme.DARK) {
return "/github-mark-dark.svg";
} else {
return "/github-mark-light.svg";
}
}

public Collection<InlinedSVG> getInlinedSVGs() {
if (svg == null) {
return Collections.emptyList();
}
return List.of(svg);
}
}
Loading