datum-core 0.6.0

Rust stream-processing library mirroring Akka/Pekko Streams Typed, built on Ractor actors
Documentation
#!/usr/bin/env python3
import csv
import json
import sys


def load_datum(path):
    rows = {}
    with open(path, newline="") as handle:
        reader = csv.DictReader(handle, delimiter="\t")
        for row in reader:
            cpu_ns = row.get("cpu_ns_per_op")
            rows[row["scenario"]] = {
                "us": float(row["ns_per_op"]) / 1_000.0,
                # 0 means CPU sampling is unavailable (non-Linux /proc); show n/a.
                "cpu_us": float(cpu_ns) / 1_000.0 if cpu_ns and float(cpu_ns) > 0.0 else None,
                "alloc": float(row["allocated_bytes_per_op"]),
            }
    return rows


def load_akka(path):
    with open(path) as handle:
        data = json.load(handle)

    rows = {}
    for item in data:
        scenario = item["benchmark"].split(".")[-1]
        alloc_metric = item.get("secondaryMetrics", {}).get("gc.alloc.rate.norm")
        rows[scenario] = {
            "us": float(item["primaryMetric"]["score"]),
            "alloc": float(alloc_metric["score"]) if alloc_metric else None,
        }
    return rows


def fmt(value, suffix=""):
    if value is None:
        return "n/a"
    if value >= 100:
        return f"{value:,.0f}{suffix}"
    if value >= 10:
        return f"{value:,.1f}{suffix}"
    return f"{value:,.2f}{suffix}"


def main():
    if len(sys.argv) != 3:
        raise SystemExit("usage: render_table.py <datum.tsv> <akka-jmh.json>")

    datum = load_datum(sys.argv[1])
    akka = load_akka(sys.argv[2])

    print(
        "| Scenario | Datum us/op | Datum CPU us/op | Akka us/op | Speedup | "
        "Datum alloc B/op | Akka alloc B/op | Alloc ratio |"
    )
    print("| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: |")
    for scenario in datum:
        if scenario not in akka:
            continue
        datum_us = datum[scenario]["us"]
        datum_cpu = datum[scenario].get("cpu_us")
        akka_us = akka[scenario]["us"]
        datum_alloc = datum[scenario]["alloc"]
        akka_alloc = akka[scenario]["alloc"]
        speedup = akka_us / datum_us if datum_us else None
        alloc_ratio = akka_alloc / datum_alloc if datum_alloc and akka_alloc is not None else None
        print(
            f"| `{scenario}` | {fmt(datum_us)} | {fmt(datum_cpu)} | {fmt(akka_us)} | "
            f"{fmt(speedup, 'x')} | {fmt(datum_alloc)} | {fmt(akka_alloc)} | {fmt(alloc_ratio, 'x')} |"
        )


if __name__ == "__main__":
    main()