import json
import math
import os
import platform
import sys
CODEC_ORDER = ["C zstd", "zrip", "structured-zstd", "ruzstd"]
COLORS = {
"C zstd": ("#60a5fa", "#4680c4"),
"zrip": ("#f87171", "#c45050"),
"structured-zstd": ("#f59e0b", "#c47d08"),
"ruzstd": ("#4ade80", "#3aaf60"),
}
LABELS = {
"C zstd": "C zstd 1.5.7 (libzstd)",
"zrip": "zrip (safe Rust)",
"structured-zstd": "structured-zstd 0.0.40 (unsafe Rust)",
"ruzstd": "ruzstd 0.8.2 (safe Rust)",
}
LEVEL = 1
MIN_FILE_SIZE = 10_000
TRANSFER_RATE = 100e6
def detect_hardware():
try:
for line in open("/proc/cpuinfo"):
if line.startswith("model name"):
cpu = line.split(":", 1)[1].strip()
cpu = cpu.replace("(R)", "").replace("(TM)", "").replace("CPU ", "")
extras = []
try:
gov = open("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor").read().strip()
if gov == "performance":
extras.append("performance governor")
except OSError:
pass
for path, off_val in [
("/sys/devices/system/cpu/intel_pstate/no_turbo", "1"),
("/sys/devices/system/cpu/cpufreq/boost", "0"),
]:
try:
if open(path).read().strip() == off_val:
extras.append("turbo off")
break
except OSError:
continue
if not extras:
hw = os.environ.get("ZRIP_HW_EXTRAS")
if hw:
extras.extend(hw.split(","))
if extras:
cpu += ", " + ", ".join(extras)
return cpu
except OSError:
pass
return None
def nice_step(max_val, target_lines):
raw = max_val / target_lines
mag = 10 ** int(f"{raw:.0e}".split("e")[1])
for s in [1, 2, 5, 10]:
step = s * mag
if max_val / step <= target_lines + 1:
return step
return mag * 10
def load_all_data():
cache_dir = os.path.join(os.environ.get("HOME", "."), ".cache", "zrip")
data = {}
if not os.path.isdir(cache_dir):
return data
for entry in os.listdir(cache_dir):
level_dir = os.path.join(cache_dir, entry)
if not os.path.isdir(level_dir) or not entry.startswith("L"):
continue
for codec in CODEC_ORDER:
fname = codec.replace(" ", "_") + ".jsonl"
path = os.path.join(level_dir, fname)
if not os.path.exists(path):
continue
if codec not in data:
data[codec] = {}
with open(path) as f:
for line in f:
line = line.strip()
if not line:
continue
r = json.loads(line)
if r.get("input_size", 0) < MIN_FILE_SIZE:
continue
data[codec][(r["input"], r["level"])] = r
return {codec: list(seen.values()) for codec, seen in data.items()}
def compute_geomean(data):
results = {}
for codec in CODEC_ORDER:
rows = data.get(codec, [])
level_rows = [r for r in rows if r["level"] == LEVEL]
comp_log = []
xfer_log = []
decomp_log = []
for r in level_rows:
cns = r.get("compress_ns", 0)
if cns is None or (isinstance(cns, float) and math.isnan(cns)):
continue
sz = r["input_size"]
per_gb = 1e9 / sz
comp_log.append(math.log(cns / 1e9 * per_gb))
xfer_log.append(math.log((r["compressed_size"] / sz) * (1e9 / TRANSFER_RATE)))
decomp_log.append(math.log(r["decompress_ns"] / 1e9 * per_gb))
if comp_log:
n = len(comp_log)
results[codec] = (
math.exp(sum(comp_log) / n),
math.exp(sum(xfer_log) / n),
math.exp(sum(decomp_log) / n),
)
return results
def generate_svg(data):
stacks = compute_geomean(data)
hw_label = detect_hardware()
codecs = [c for c in CODEC_ORDER if c in stacks]
n = len(codecs)
if n == 0:
return None
svg_w = 700
x_left, x_right = 70, 680
plot_w = x_right - x_left
top_margin = 55 if hw_label else 45
plot_h = 250
p_top = top_margin
p_bot = p_top + plot_h
y_max = max(sum(stacks[c]) for c in codecs) * 1.15
def y(v):
return p_bot - (v / y_max) * plot_h
bar_w = min(plot_w * 0.7 / n, 80)
gap = bar_w * 0.4
total_bars_w = n * bar_w + (n - 1) * gap
bar_start = x_left + (plot_w - total_bars_w) / 2
mid_x = svg_w / 2
legend_items = [(k, LABELS[k]) for k in CODEC_ORDER if k in stacks]
leg_row_h = 18
leg_cols = 2
leg_rows = math.ceil(len(legend_items) / leg_cols)
svg_h = int(p_bot + 40 + leg_rows * leg_row_h + 30)
L = []
L.append(
f'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 {svg_w} {svg_h}"'
f' font-family="system-ui, -apple-system, sans-serif">'
)
L.append(f' <rect width="{svg_w}" height="{svg_h}" fill="#0d1117"/>')
L.append(
f' <text x="{mid_x}" y="22" text-anchor="middle" fill="#e6edf3"'
f' font-size="14" font-weight="700">'
f'zstd Pipeline @100 MB/s: Corpus geomean, Level 1 (lower is better)'
f'</text>'
)
if hw_label:
L.append(
f' <text x="{mid_x}" y="38" text-anchor="middle" fill="#7d8590"'
f' font-size="10">{hw_label}</text>'
)
y_mid = (p_top + p_bot) / 2
L.append(
f' <text x="22" y="{y_mid}" text-anchor="middle" fill="#e6edf3"'
f' font-size="11" font-weight="600"'
f' transform="rotate(-90,22,{y_mid})">seconds / GB</text>'
)
step = nice_step(y_max, 5)
v = step
while v <= y_max:
yy = y(v)
L.append(
f' <line x1="{x_left}" y1="{yy:.1f}" x2="{x_right}" y2="{yy:.1f}"'
f' stroke="#21262d" stroke-width="1"/>'
)
L.append(
f' <text x="{x_left - 8}" y="{yy:.1f}" text-anchor="end"'
f' dominant-baseline="middle" fill="#7d8590" font-size="10">'
f'{v:.1f}</text>'
)
v += step
L.append(
f' <line x1="{x_left}" y1="{p_bot}" x2="{x_right}" y2="{p_bot}"'
f' stroke="#30363d" stroke-width="1.5"/>'
)
for i, codec in enumerate(codecs):
comp, transfer, decomp = stacks[codec]
main_c, xfer_c = COLORS[codec]
bx = bar_start + i * (bar_w + gap)
h_comp = (comp / y_max) * plot_h
L.append(
f' <rect x="{bx:.1f}" y="{y(comp):.1f}"'
f' width="{bar_w:.1f}" height="{h_comp:.1f}"'
f' fill="{main_c}" rx="1"/>'
)
h_transfer = (transfer / y_max) * plot_h
L.append(
f' <rect x="{bx:.1f}" y="{y(comp + transfer):.1f}"'
f' width="{bar_w:.1f}" height="{h_transfer:.1f}"'
f' fill="{xfer_c}" rx="1"/>'
)
h_decomp = (decomp / y_max) * plot_h
L.append(
f' <rect x="{bx:.1f}" y="{y(comp + transfer + decomp):.1f}"'
f' width="{bar_w:.1f}" height="{h_decomp:.1f}"'
f' fill="{main_c}" rx="1"/>'
)
cx = bx + bar_w / 2
L.append(
f' <text x="{cx:.1f}" y="{p_bot + 16}" text-anchor="middle"'
f' fill="#e6edf3" font-size="10" font-weight="600">{codec}</text>'
)
leg_y = p_bot + 35
leg_col_x = [mid_x - 200, mid_x + 10]
for i, (key, label) in enumerate(legend_items):
col = i // leg_rows
row = i % leg_rows
if col >= leg_cols:
break
lx = leg_col_x[col]
ly = leg_y + row * leg_row_h
main_c, _ = COLORS[key]
L.append(
f' <rect x="{lx:.0f}" y="{ly - 5}" width="12" height="12"'
f' fill="{main_c}" rx="2"/>'
)
L.append(
f' <text x="{lx + 18:.0f}" y="{ly + 5}" fill="#e6edf3"'
f' font-size="10" font-weight="500">{label}</text>'
)
seg_y = leg_y + leg_rows * leg_row_h + 8
seg_items = [
("bright = compress + decompress", "#e6edf3"),
("dim = transfer @100 MB/s", "#7d8590"),
]
seg_total = 420
seg_start = mid_x - seg_total / 2
for i, (label, fill) in enumerate(seg_items):
sx = seg_start + i * 240
L.append(
f' <text x="{sx:.0f}" y="{seg_y + 4}" fill="{fill}"'
f' font-size="9">{label}</text>'
)
L.append("</svg>")
return "\n".join(L) + "\n"
def main():
data = load_all_data()
if not data:
print("No cached data in ~/.cache/zrip/", file=sys.stderr)
sys.exit(1)
svg = generate_svg(data)
if svg is None:
print("No Level 1 data found", file=sys.stderr)
sys.exit(1)
arch = platform.machine() or "x86_64"
output_dir = sys.argv[1] if len(sys.argv) > 1 else f"doc/charts/{arch}"
os.makedirs(output_dir, exist_ok=True)
path = os.path.join(output_dir, "summary.svg")
with open(path, "w") as f:
f.write(svg)
print(f"wrote {path}")
if __name__ == "__main__":
main()