Mermaid's xychart-beta cannot draw grouped bars or a legend: two bar series overlap on the same axis position, so the paired GPU-vs-cairo comparison was unreadable. Render the charts as images with real grouped bars, value labels and a legend (bench/make-charts.py), and embed them from .github/assets/.
95 lines
3.1 KiB
Python
95 lines
3.1 KiB
Python
#!/usr/bin/env python3
|
|
"""Render the benchmark charts as grouped-bar images.
|
|
|
|
Mermaid's xychart-beta cannot draw grouped (side-by-side) bars or a
|
|
legend, so the README embeds these generated images instead. Run this
|
|
after updating the numbers in the README tables:
|
|
|
|
python3 bench/make-charts.py
|
|
|
|
Output PNGs go to .github/assets/.
|
|
"""
|
|
import os
|
|
import matplotlib
|
|
matplotlib.use("Agg")
|
|
import matplotlib.pyplot as plt
|
|
from matplotlib.ticker import MaxNLocator
|
|
|
|
GPU = "#43b97f"
|
|
CAIRO = "#4f81e5"
|
|
COCOA = "#4f81e5"
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
OUT = os.path.join(HERE, "..", ".github", "assets")
|
|
|
|
WORKLOADS = ["Line scroll", "Page scroll", "Full redraw", "Typing", "Image scroll"]
|
|
|
|
# (filename, title, gpu values, cairo values, x-axis label)
|
|
PAIRED = [
|
|
("bench-linux-1616.png",
|
|
"1616x912 frame: redisplays per second (higher is better)",
|
|
[487, 296, 294, 1311, 1239],
|
|
[530, 297, 247, 1857, 1359]),
|
|
("bench-linux-4k.png",
|
|
"4K frame: redisplays per second (higher is better)",
|
|
[240, 124, 121, 1766, 1328],
|
|
[117, 102, 66, 238, 115]),
|
|
]
|
|
|
|
|
|
def paired_chart(fname, title, gpu, cairo):
|
|
fig, ax = plt.subplots(figsize=(9, 4.5), dpi=140)
|
|
y = range(len(WORKLOADS))
|
|
h = 0.38
|
|
# GPU on top of each pair, cairo just below.
|
|
ax.barh([i + h / 2 for i in y], gpu, height=h, color=GPU, label="GPU (OpenGL)")
|
|
ax.barh([i - h / 2 for i in y], cairo, height=h, color=CAIRO, label="Stock (cairo)")
|
|
ax.set_yticks(list(y))
|
|
ax.set_yticklabels(WORKLOADS)
|
|
ax.invert_yaxis()
|
|
ax.set_xlabel("redisplays per second")
|
|
ax.set_title(title)
|
|
ax.legend(loc="lower right", frameon=False)
|
|
ax.spines[["top", "right"]].set_visible(False)
|
|
top = max(max(gpu), max(cairo))
|
|
ax.set_xlim(0, top * 1.12)
|
|
for i in y:
|
|
ax.text(gpu[i] + top * 0.01, i + h / 2, str(gpu[i]),
|
|
va="center", ha="left", fontsize=8, color="#2a2a2a")
|
|
ax.text(cairo[i] + top * 0.01, i - h / 2, str(cairo[i]),
|
|
va="center", ha="left", fontsize=8, color="#2a2a2a")
|
|
fig.tight_layout()
|
|
fig.savefig(os.path.join(OUT, fname), facecolor="white")
|
|
plt.close(fig)
|
|
print("wrote", fname)
|
|
|
|
|
|
def macos_chart():
|
|
fname = "bench-macos-cpu.png"
|
|
labels = ["Stock (Cocoa)", "GPU vsync on", "GPU vsync off"]
|
|
vals = [16.0, 10.5, 15.5]
|
|
colors = [COCOA, GPU, GPU]
|
|
fig, ax = plt.subplots(figsize=(9, 3.0), dpi=140)
|
|
y = range(len(labels))
|
|
ax.barh(list(y), vals, height=0.5, color=colors)
|
|
ax.set_yticks(list(y))
|
|
ax.set_yticklabels(labels)
|
|
ax.invert_yaxis()
|
|
ax.set_xlabel("CPU seconds")
|
|
ax.set_title("M1 Pro: CPU to render 15 s of flat-out scroll (lower is better)")
|
|
ax.spines[["top", "right"]].set_visible(False)
|
|
ax.set_xlim(0, max(vals) * 1.12)
|
|
for i in y:
|
|
ax.text(vals[i] + max(vals) * 0.01, i, f"{vals[i]:.1f} s",
|
|
va="center", ha="left", fontsize=8, color="#2a2a2a")
|
|
fig.tight_layout()
|
|
fig.savefig(os.path.join(OUT, fname), facecolor="white")
|
|
plt.close(fig)
|
|
print("wrote", fname)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
os.makedirs(OUT, exist_ok=True)
|
|
for args in PAIRED:
|
|
paired_chart(*args)
|
|
macos_chart()
|