From 0cb418544f4f378195f3f8f4dcd30c4fce6c3bb9 Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Thu, 15 Oct 2026 19:46:50 -0700 Subject: [PATCH] docs: publish the v2026.10.7-alpha ingest benchmark On a Hetzner Cloud ccx33 (8 dedicated vCPUs, 32 GB RAM), with telemetrygen on a separate ccx33, Fanout v2026.10.7-alpha accepted 422,408 mixed OpenTelemetry items/s for five minutes: 51,358 spans, 184,883 log records and 186,178 metric points per second. Every gate passed. - The landing page shows the sustained result with its composition, a mixed sweep chart (median, min-max band across three repetitions, the sustained point and the generator-limited region) and median-peak tiles for each workload. - The performance page gives setup, method, sustained composition, median peaks with ranges and CPU, the full mixed sweep, small-multiple sweep charts, evidence links and reproduction steps. - One shared data module, derived from the run's report, feeds both components. - README, the home page and the capability status point to the published result and its raw evidence in fanout-bench. Claude-Session: https://claude.ai/code/session_01XA52nWyQ3R5f5kK8kjpAQW --- README.md | 10 +- site/src/components/landing/Benchmark.astro | 654 ++---------------- .../components/landing/BenchmarkSweep.astro | 128 ++++ .../content/docs/explanation/performance.mdx | 240 +++---- site/src/content/docs/index.mdx | 23 +- site/src/content/docs/status/capabilities.mdx | 2 +- site/src/data/benchmark.ts | 289 ++++++++ 7 files changed, 619 insertions(+), 727 deletions(-) create mode 100644 site/src/components/landing/BenchmarkSweep.astro create mode 100644 site/src/data/benchmark.ts diff --git a/README.md b/README.md index ee4c2cfd..8c97eab1 100644 --- a/README.md +++ b/README.md @@ -163,10 +163,12 @@ runbook](docs/operations.md). ## Performance -[Fanout Bench](https://github.com/labstack/fanout-bench) measures authenticated ingest and optional -dashboard read load on your hardware; the [performance -methodology](https://fanout.run/explanation/performance) covers reproducible evidence and -publication requirements. +Fanout v2026.10.7-alpha accepted **422,408 mixed OpenTelemetry items/s for five minutes** +on a Hetzner Cloud ccx33 (8 dedicated vCPUs, 32 GB RAM), with telemetrygen on a separate +ccx33 over a private network. The run measured ingest only. See the [performance +methodology](https://fanout.run/explanation/performance) and [raw +evidence](https://github.com/labstack/fanout-bench/tree/main/published/2026-10-16-ccx33x2-v2026.10.7-alpha). +[Fanout Bench](https://github.com/labstack/fanout-bench) reproduces the measurement on your hardware. ## Build from source diff --git a/site/src/components/landing/Benchmark.astro b/site/src/components/landing/Benchmark.astro index e5f2d448..6f211320 100644 --- a/site/src/components/landing/Benchmark.astro +++ b/site/src/components/landing/Benchmark.astro @@ -1,154 +1,58 @@ --- -/* A publication-candidate benchmark rendered as an instrument, not a claim card. - * - * Every number in this component comes from the same fanout-bench report and is - * also published in /explanation/performance, so no figure lives only in - * markup. The status line is deliberately impossible to miss: this branch - * previews the presentation before the required clean, repeated run replaces - * the candidate. Green remains a health/status colour, matching the product; - * throughput uses the site's violet interaction accent instead. - * - * The per-signal rates below are three separate saturation runs, not a - * breakdown of the sustained three-signal figure — they sum to roughly twice - * it, so the strip says so in text rather than leaving the reader to guess. +/* Published v2026.10.7-alpha ingest result. The shared report data drives the + * sustained composition, peak ranges, and the reusable sweep charts here and + * on the methodology page. Green marks passed gates; throughput uses violet. */ -const signals = [ - { name: "Traces", unit: "spans/s", value: "220,324" }, - { name: "Logs", unit: "records/s", value: "187,303" }, - { name: "Metrics", unit: "points/s", value: "209,638" }, -]; +import BenchmarkSweep from "./BenchmarkSweep.astro"; +import { acceptedTotal, benchmark, composition, formatRate, peak, signalNames, type Signal } from "../../data/benchmark"; -const gates = ["server drops 0", "no restarts", "Parquet verified"]; +const signals: Signal[] = ["mixed", "traces", "logs", "metrics"]; +const gates = ["generators exited successfully", "dropped rows 0", "no restarts", "Parquet verified"]; +const compositionTotal = composition.reduce((sum, signal) => sum + signal.rate, 0); --- -
+
- - Publication candidate - measured on one machine · methodology + + Published benchmark · {benchmark.release} + methodology
- +

Hetzner ccx33 · 8 dedicated vCPUs · 32 GB RAM · separate ccx33 generators

-

Sustained three-signal ingest

-

- 296,196 items/s -

-

- Fanout's accepted-row counter over five minutes—not the load - generator's requested rate. -

- - - -
-
- Accepted throughput - items/s -
- - Accepted three-signal throughput by generator process count - Throughput rose from 38,853 items per second with one generator process per signal to a 355,938 short peak with sixteen. The five-minute sustained rate at sixteen processes, the headline figure, was 296,196. The horizontal axis doubles at every step, so its points are evenly spaced. - - - 400k - 300k - 200k - 100k - 0 - - - - - - - - - - - - - - 1 - 2 - 4 - 8 - 16 - - generator processes per signal · doubling, evenly spaced - 355,938/s short peak - 296,196/s sustained over five minutes - -
+
- -
-

- Each signal was also saturated on its own. These three runs are separate - measurements, not a breakdown of the sustained three-signal rate above. -

-
- {signals.map((signal) => ( -
- {signal.name} alone - {signal.value} - {signal.unit} -
- ))} -
- Whole suite - 153.8M - items accepted, cumulative -
-
+
+ {signals.map((signal) => { + const point = peak(signal); + return
+ {signalNames[signal]} median peak + {formatRate(point.median)} items/s + {formatRate(point.min)}–{formatRate(point.max)} + {point.processes_per_signal} processes per signal +
; + })}
-
-
- {gates.map((gate) => ( - {gate} - ))} -
-

v2026.8.11 · 8 logical CPUs · 15.6 GiB · same-host generators · OTLP/gRPC

+
{gates.map((gate) => {gate})}
+

{(acceptedTotal / 1e6).toFixed(1)}M items accepted across the suite · raw evidence

- - diff --git a/site/src/components/landing/BenchmarkSweep.astro b/site/src/components/landing/BenchmarkSweep.astro new file mode 100644 index 00000000..0f7cff30 --- /dev/null +++ b/site/src/components/landing/BenchmarkSweep.astro @@ -0,0 +1,128 @@ +--- +/* Shared published sweeps: a log2 process axis, median, and repetition range. + * All four plots share a zero-based 600k scale for direct visual comparison. + */ +import { benchmark, formatRate, signalNames, type Signal } from "../../data/benchmark"; + +interface Props { + id: string; + signals?: Signal[]; +} + +const { id, signals = ["traces", "logs", "metrics", "mixed"] } = Astro.props; +const multiple = signals.length > 1; +// Small multiples need room for the same screen-sized labels as the landing plot. +const left = multiple ? 64 : 52, right = 452, top = 60, bottom = 240; +const x = (processes: number) => left + Math.log2(processes) / 6 * (right - left); +const y = (rate: number) => bottom - rate / 600000 * (bottom - top); +const ticks = [0, 200000, 400000, 600000]; +const { sustained } = benchmark; +--- + +
1 }]}> + {signals.map((signal) => { + const points = benchmark.sweeps[signal]; + const chartId = `${id}-${signal}`; + const line = points.map((point) => `${x(point.processes_per_signal)},${y(point.median)}`).join(" "); + const band = [...points.map((point) => `${x(point.processes_per_signal)},${y(point.max)}`), + ...[...points].reverse().map((point) => `${x(point.processes_per_signal)},${y(point.min)}`)].join(" "); + const limited = points.filter((point) => point.generator_cpu_median >= 7); + const limitedStart = limited.length ? x(limited[0].processes_per_signal) : right; + return ( +
+
{signalNames[signal]} sweepaccepted items/s
+ + {signalNames[signal]} accepted throughput by processes per signal + + Median line and minimum-to-maximum band across {benchmark.repeat} repetitions at 1, 2, 4, 8, 16, 32 and 64 processes per signal. + The horizontal axis is evenly spaced on a log2 scale; the vertical axis runs from zero to 600,000 accepted items per second. + {points.map((point) => ` At ${point.processes_per_signal} processes: ${formatRate(point.median)} items/s, range ${formatRate(point.min)} to ${formatRate(point.max)}.`).join("")} + {signal === "mixed" && ` The diamond marks the single sustained phase: ${formatRate(sustained.accepted_per_second)} items/s at ${sustained.processes_per_signal} processes per signal over ${sustained.seconds} seconds. Shading at 32–64 processes marks generator CPU of at least 7 cores.`} + + + +
+ median + min–max + {signal === "mixed" && {formatRate(sustained.accepted_per_second)}/s sustained at {sustained.processes_per_signal}} +
+
+ ); + })} +
+ + diff --git a/site/src/content/docs/explanation/performance.mdx b/site/src/content/docs/explanation/performance.mdx index dbe2b62c..5ffc0f71 100644 --- a/site/src/content/docs/explanation/performance.mdx +++ b/site/src/content/docs/explanation/performance.mdx @@ -1,143 +1,125 @@ --- title: Performance -description: Fanout's benchmark candidate, its limits, and how to reproduce the measurement on your hardware. -summary: A qualified preview of Fanout's measured three-signal ingest, plus the evidence required before it becomes a published result. +description: Published v2026.10.7-alpha ingest results, hardware, methodology and raw evidence. +summary: Sustained mixed ingest at 422,408 items/s on a Hetzner ccx33, with three sweep repetitions, ranges, generator CPU and reproduction commands. read_when: - You want to understand the performance figure on the landing page. - - You need to size an instance for your own load. -status: preview + - You need to measure an instance for your own load. +status: shipped --- -Fanout has a publication candidate, not an official throughput claim yet. The -distinction is visible beside the number because provenance is part of a -benchmark result, not a footnote added after it. - -## Candidate result - -On a machine with eight logical CPUs and 15.6 GiB of memory, Fanout v2026.8.11 -accepted **296,196 OpenTelemetry items per second** for five minutes. The load -contained traces, logs and metrics at the same time, and Fanout and the load -generators shared the host. - -| Workload | Fanout accepted/s | Offered/s | Average Fanout CPU | Peak RSS | -|---|---:|---:|---:|---:| -| Traces, spans | 220,324 | 320,000 | 2.45 cores | 1.2 GiB | -| Logs, records | 187,303 | 320,000 | 3.04 cores | 1.3 GiB | -| Metrics, data points | 209,638 | 320,000 | 1.69 cores | 1.1 GiB | -| Three-signal short peak | 355,938 | 960,000 | 4.57 cores | 3.0 GiB | -| Three-signal sustained | 296,196 | 960,000 | 4.90 cores | 9.4 GiB | - -Accepted throughput is the change in Fanout's own -`fanout_ingest_rows_total` counter over the measured phase. It is not the rate -requested or reported by the generator. Across the complete saturation suite, -Fanout accepted 153.8 million items. - -The run passed its functional quality gates: every generator exited -successfully, Fanout reported zero dropped rows and no restart, and `fanout -repair verify` validated the authoritative Parquet store. - -### Generator load, not a Fanout scaling curve - -The chart on the landing page plots the same run's generator sweep: one, two, -four, eight and sixteen `telemetrygen` processes per signal, doubling at every -step. Accepted throughput rose from 38,853 items per second at one process per -signal to the 355,938 short peak at sixteen. That is a 9.2x gain for a 16x -increase in generators, and the shape is the point—below sixteen processes the -load generators, not Fanout, set the rate. Read it as evidence that the -saturating configuration was reached, not as a scaling law for Fanout itself. -The intermediate process counts are plotted from the same run and their exact -values ship with the raw artifacts. - -:::caution[Why this is not published evidence yet] -This was one repetition, and the benchmark harness it ran from carried -uncommitted local changes, so no commit identifies the code that produced it. -The result is a useful design and capacity preview, but it will not become the -official headline until the clean harness produces at least three passing -repetitions and the raw artifacts are published together. -::: - -## What this number does—and does not—measure - -This is a **three-signal ingest** result: spans, log records and metric data -points were written concurrently. It is not a read/write result. Calling it a -mixed workload would imply that dashboard queries ran beside ingest, which -they did not. - -The official read-under-write result will separately report requested, -completed, failed and shed query rates plus p50, p95 and p99 latency. Until that -result passes, Fanout makes no claim about interactive query capacity at the -headline write rate. - -The generators shared the Fanout host, so generator CPU and memory contention -can make the observed result lower than an isolated-server ceiling. Synthetic -`telemetrygen` payloads are also highly compressible, so this run is not a -storage-sizing formula for production data. - -## What the official result must carry - -Before the candidate becomes Fanout's official headline, it has to ship with: - -- the Fanout release artifact and checksum plus the benchmark-driver commit; -- complete machine, network, container and Fanout configuration; -- the raw `report.json`, `report.md` and `samples.jsonl` from that same run; -- an authenticated OTLP path matching the current release; -- at least three publish-preset repetitions and their variability; -- separate ingest-only and read-under-write results; -- the query completion rate and latency distribution beside any read claim; -- limitations stated next to the result rather than hidden at the bottom. - -## Reproduce it on your hardware - -The independent -[Fanout Bench](https://github.com/labstack/fanout-bench) project drives the -official OpenTelemetry `telemetrygen` client, counts rows accepted by Fanout, -and emits raw JSON plus a publication-ready report. It can add authenticated -dashboard reads on top, which is the part that matters. -Parquet ingest, indexed trace reads, and DuckDB analytics have separate -coordination paths, but they still compete for the same CPU, memory bandwidth, -filesystem cache, and disk. Maintenance adds native Parquet merge work and -short reader-exclusive namespace changes. An ingest-only number therefore -still overstates what an instance does while anyone is looking at it. - -Obtain the ingest token through first-admin setup, configure Fanout -with a dedicated `FANOUT_METRICS_TOKEN`, then expose that same metrics token to -the harness as `FANOUT_BENCH_METRICS_TOKEN`. Metrics are private by default. A -local run starts with: +import BenchmarkSweep from "../../../components/landing/BenchmarkSweep.astro"; -```sh -export FANOUT_BENCH_INGEST_TOKEN='…' -export FANOUT_BENCH_METRICS_TOKEN='…' -fanout-bench run \ - --endpoint localhost:7520 \ - --metrics-url http://localhost:7520/metrics \ - --insecure \ - --same-host +On a Hetzner Cloud ccx33 (8 dedicated vCPUs, 32 GB RAM), with telemetrygen +on a separate ccx33 (8 dedicated vCPUs, 32 GB RAM) in the same location over +a private network, Fanout v2026.10.7-alpha accepted **422,408 mixed +OpenTelemetry items/s for five minutes**. The composition was 51,358 spans, +184,883 log records and 186,178 metric points per second. Every generator +exited successfully, there were zero dropped rows and no restarts, and +`fanout repair verify` validated the Parquet store. The run measured ingest only. + +## Setup and measurement + +Fanout ran alone on its ccx33 with dedicated AMD EPYC-Milan vCPUs. Both VMs +ran Ubuntu 24.04 in Hetzner's fsn1 location. telemetrygen v0.157.0 sent +plaintext OTLP/gRPC over the private network, using 1,000-item batches and +8 workers per process. + +The `publish` preset swept 1, 2, 4, 8, 16, 32 and 64 processes per signal +for traces, logs, metrics and mixed ingest, with three repetitions at each +process count. It then ran one five-minute mixed phase at 32 processes per +signal. Accepted throughput is the change in Fanout's +`fanout_ingest_rows_total` counter over each measured phase. + +The suite accepted **584.1 million items** in total: 131,484,819 spans, +217,735,381 log records and 234,835,485 metric points. + +## Sustained mixed ingest + +The sustained phase ran once for **302.9 seconds**. Fanout averaged +**7.33 CPU cores** and reached **13.5 GiB peak RSS**. The generator host +averaged **7.01 of 8 CPU cores**. + +| Signal | Accepted items/s | +|---|---:| +| Spans | 51,358 | +| Log records | 184,883 | +| Metric points | 186,178 | +| Mixed total | 422,408 | + +telemetrygen keeps one trace export in flight per process, while log and +metric processes keep eight, producing the measured composition. + +The run measured ingest only, using synthetic, highly compressible +telemetrygen payloads. Results describe this hardware. + +## Median peaks + +Each peak is the highest median accepted rate in that workload's sweep. +Ranges cover all three repetitions at the listed process count. CPU columns +are median average cores at that count; each host has 8 cores. + +| Workload | Median peak items/s | Processes per signal | Range items/s | Fanout CPU cores | Generator CPU cores | +|---|---:|---:|---:|---:|---:| +| Mixed | 429,749 | 32 | 429,504–471,506 | 6.95 | 7.02 | +| Traces | 243,696 | 64 | 225,110–267,916 | 6.03 | 6.83 | +| Logs | 342,494 | 64 | 299,902–347,721 | 6.82 | 3.46 | +| Metrics | 540,102 | 64 | 293,700–543,941 | 5.83 | 4.64 | + +## Mixed sweep + +All rates below are accepted items/s across the three repetitions. CPU +columns are median average cores per host. + +| Processes per signal | Median items/s | Min items/s | Max items/s | Fanout CPU cores | Generator CPU cores | +|---|---:|---:|---:|---:|---:| +| 1 | 41,300 | 40,269 | 41,362 | 4.92 | 0.31 | +| 2 | 81,075 | 80,661 | 81,651 | 4.44 | 0.65 | +| 4 | 148,972 | 130,086 | 154,626 | 5.09 | 1.33 | +| 8 | 244,888 | 219,064 | 273,901 | 6.06 | 2.56 | +| 16 | 330,232 | 325,618 | 364,301 | 6.39 | 4.29 | +| 32 | 429,749 | 429,504 | 471,506 | 6.95 | 7.02 | +| 64 | 422,667 | 384,338 | 441,460 | 6.79 | 7.49 | + +## Signal sweeps + +The charts use a shared vertical scale and an evenly spaced log2 process +axis. Lines and points show the median; bands show the minimum and maximum +across three repetitions. The diamond marks the sustained phase at 32 +processes per signal. The shaded region marks generator CPU of at least +7 cores. + + + +## Evidence + +The [published evidence directory](https://github.com/labstack/fanout-bench/tree/main/published/2026-10-16-ccx33x2-v2026.10.7-alpha) +contains the raw artifacts, and its +[README](https://github.com/labstack/fanout-bench/blob/main/published/2026-10-16-ccx33x2-v2026.10.7-alpha/README.md) +summarises the run. It records all gates passing: successful generator exits, +zero dropped rows, no restarts and a verified Parquet store. + +The harness was clean at commit +[`8a2a28aafa828fc7967ba82a481c7cdb5c7e921e`](https://github.com/labstack/fanout-bench/commit/8a2a28aafa828fc7967ba82a481c7cdb5c7e921e). +The [Fanout release artifact](https://github.com/labstack/fanout/releases/download/v2026.10.7-alpha/fanout_v2026.10.7-alpha_linux_amd64.tar.gz) +has SHA-256: + +```text +d1b602130463b38a03f7575c52c1c2178213839dbf276294abd57ce662c8756b ``` -The harness repository documents signal-specific saturation, sustained -three-signal load, read-under-write latency, machine identity, and publication -rules. For a publication-quality run, use the `publish` preset and retain all -three repetitions: +## Reproduce + +From the [fanout-bench](https://github.com/labstack/fanout-bench) repository, +run the Hetzner provisioner with the same release, preset and repetition count: ```sh -fanout-bench run \ - --host your-benchmark-host \ - --fanout-version v2026.8.11 \ +scripts/hetzner.sh \ + --fanout-version v2026.10.7-alpha \ --preset publish \ - --repeat 3 \ - --output results/fanout-v2026.8.11 + --repeat 3 ``` -:::caution[A result describes the machine it ran on] -Benchmark output describes the hardware and dataset you tested, not an -equivalent vCPU count at another provider. Two machines advertised with the same -core count differ in memory bandwidth, disk latency and noisy neighbours, and -Fanout is sensitive to all three — [storage](/explanation/storage-model) -explains why. -::: - -## What to watch in production - -For capacity, the useful signals are the ones an instance emits about itself: -telemetry drops, sustained query latency, readiness failures, and free disk. -[Troubleshooting](/guides/troubleshoot) lists where they are. +Both VMs default to ccx33. The +[publishing guide](https://github.com/labstack/fanout-bench/blob/main/docs/publishing.md) +documents credentials, provisioning, the private network and artifact collection. diff --git a/site/src/content/docs/index.mdx b/site/src/content/docs/index.mdx index 7049b5d8..39c848c4 100644 --- a/site/src/content/docs/index.mdx +++ b/site/src/content/docs/index.mdx @@ -104,23 +104,20 @@ it to answer. The data directory it writes is the whole of its state.
-## Nearly 300,000 OpenTelemetry items a second. One binary. +## 422,408 OpenTelemetry items a second. One binary. -In a five-minute publication-candidate run, Fanout accepted **296,196 spans, -log records and metric data points per second** on a machine with eight logical -CPUs and 15.6 GiB of memory. -Fanout reported zero dropped rows, the process did not restart, and the -resulting Parquet store passed verification. The load generators shared the -machine, so this is an observed whole-host result—not an isolated -storage-engine ceiling. +On a Hetzner Cloud ccx33 (8 dedicated vCPUs, 32 GB RAM), with telemetrygen +on a separate ccx33 in the same location over a private network, Fanout +v2026.10.7-alpha accepted **422,408 mixed OpenTelemetry items/s for five +minutes**: 51,358 spans, 184,883 log records and 186,178 metric points per +second. Every generator exited successfully, there were zero dropped rows and +no restarts, and the Parquet store passed verification. The run measured ingest only. -It is labeled a candidate because it is a single run: the published headline -waits on a clean harness repeating it three times. -[Read the methodology and every qualification](/explanation/performance), or -[run the same open-source harness](https://github.com/labstack/fanout-bench) on -your own host. +[Read the methodology](/explanation/performance), inspect the +[raw evidence](https://github.com/labstack/fanout-bench/tree/main/published/2026-10-16-ccx33x2-v2026.10.7-alpha), +or [run the harness](https://github.com/labstack/fanout-bench) on your own hardware.
diff --git a/site/src/content/docs/status/capabilities.mdx b/site/src/content/docs/status/capabilities.mdx index a9fa214c..670ebe50 100644 --- a/site/src/content/docs/status/capabilities.mdx +++ b/site/src/content/docs/status/capabilities.mdx @@ -54,7 +54,7 @@ directory. | OIDC sign-in | shipped | Provider flow, with group and domain mapping. | | Generated settings reference | shipped | `cmd/fanout-docgen` writes it; `just check` fails when it drifts from the type. | | Release checksums and provenance | shipped | `SHA256SUMS` plus GitHub build attestations on every archive. | -| Publication benchmark | preview | A qualified candidate is visible on [Performance](/explanation/performance); repeatable public artifacts are still required. | +| Published ingest benchmark | shipped | [Performance](/explanation/performance) reports v2026.10.7-alpha with three sweep repetitions and [raw evidence](https://github.com/labstack/fanout-bench/tree/main/published/2026-10-16-ccx33x2-v2026.10.7-alpha). | | Signatures and SBOM | planned | Deliberately deferred until something consumes them. | | Guides for every operational task | preview | Dashboard authoring and inspection are documented; operational coverage is still incomplete. | | Namespace scoping on alert rules | planned | The field is stored but evaluation ignores it; scope with `service`. | diff --git a/site/src/data/benchmark.ts b/site/src/data/benchmark.ts new file mode 100644 index 00000000..5d74aa9a --- /dev/null +++ b/site/src/data/benchmark.ts @@ -0,0 +1,289 @@ +// Published v2026.10.7-alpha report values. Keep rates at report precision. +// Derived from published-v2026.10.7.json; raw evidence is linked below. +export const benchmark = { + release: "v2026.10.7-alpha", + evidence: + "https://github.com/labstack/fanout-bench/tree/main/published/2026-10-16-ccx33x2-v2026.10.7-alpha", + artifact: + "https://github.com/labstack/fanout/releases/download/v2026.10.7-alpha/fanout_v2026.10.7-alpha_linux_amd64.tar.gz#sha256=d1b602130463b38a03f7575c52c1c2178213839dbf276294abd57ce662c8756b", + harness_commit: "8a2a28aafa828fc7967ba82a481c7cdb5c7e921e", + telemetrygen: "v0.157.0", + repeat: 3, + batch_size: 1000, + accepted_total: { + spans: 131484819, + log_records: 217735381, + metric_points: 234835485, + }, + sustained: { + processes_per_signal: 32, + seconds: 302.9, + accepted_per_second: 422408, + spans_per_second: 51358, + log_records_per_second: 184883, + metric_points_per_second: 186178, + fanout_cpu: 7.33, + peak_rss_gib: 13.5, + generator_cpu: 7.01, + classification: "saturated-or-generator-limited", + }, + sweeps: { + traces: [ + { + processes_per_signal: 1, + median: 14591, + min: 14376, + max: 14631, + fanout_cpu_median: 4.91, + generator_cpu_median: 0.13, + }, + { + processes_per_signal: 2, + median: 29230, + min: 28622, + max: 29265, + fanout_cpu_median: 4.08, + generator_cpu_median: 0.28, + }, + { + processes_per_signal: 4, + median: 58232, + min: 54232, + max: 58522, + fanout_cpu_median: 3.68, + generator_cpu_median: 0.57, + }, + { + processes_per_signal: 8, + median: 104036, + min: 103638, + max: 110067, + fanout_cpu_median: 4.61, + generator_cpu_median: 1.19, + }, + { + processes_per_signal: 16, + median: 182701, + min: 150682, + max: 195737, + fanout_cpu_median: 5.37, + generator_cpu_median: 2.43, + }, + { + processes_per_signal: 32, + median: 193558, + min: 183113, + max: 284067, + fanout_cpu_median: 6.27, + generator_cpu_median: 4.21, + }, + { + processes_per_signal: 64, + median: 243696, + min: 225110, + max: 267916, + fanout_cpu_median: 6.03, + generator_cpu_median: 6.83, + }, + ], + logs: [ + { + processes_per_signal: 1, + median: 13468, + min: 13138, + max: 13471, + fanout_cpu_median: 2.46, + generator_cpu_median: 0.09, + }, + { + processes_per_signal: 2, + median: 26532, + min: 26436, + max: 26878, + fanout_cpu_median: 3.15, + generator_cpu_median: 0.18, + }, + { + processes_per_signal: 4, + median: 50600, + min: 49616, + max: 52532, + fanout_cpu_median: 6.9, + generator_cpu_median: 0.35, + }, + { + processes_per_signal: 8, + median: 100808, + min: 86979, + max: 104131, + fanout_cpu_median: 2.97, + generator_cpu_median: 0.74, + }, + { + processes_per_signal: 16, + median: 180022, + min: 170624, + max: 185542, + fanout_cpu_median: 4.97, + generator_cpu_median: 1.45, + }, + { + processes_per_signal: 32, + median: 299290, + min: 247014, + max: 319885, + fanout_cpu_median: 5.7, + generator_cpu_median: 2.75, + }, + { + processes_per_signal: 64, + median: 342494, + min: 299902, + max: 347721, + fanout_cpu_median: 6.82, + generator_cpu_median: 3.46, + }, + ], + metrics: [ + { + processes_per_signal: 1, + median: 13192, + min: 12430, + max: 13395, + fanout_cpu_median: 5.14, + generator_cpu_median: 0.08, + }, + { + processes_per_signal: 2, + median: 26846, + min: 26708, + max: 27036, + fanout_cpu_median: 4.61, + generator_cpu_median: 0.16, + }, + { + processes_per_signal: 4, + median: 52641, + min: 32335, + max: 53373, + fanout_cpu_median: 3.37, + generator_cpu_median: 0.32, + }, + { + processes_per_signal: 8, + median: 99628, + min: 95654, + max: 106147, + fanout_cpu_median: 3.84, + generator_cpu_median: 0.63, + }, + { + processes_per_signal: 16, + median: 184239, + min: 179830, + max: 205136, + fanout_cpu_median: 4.97, + generator_cpu_median: 1.26, + }, + { + processes_per_signal: 32, + median: 338541, + min: 263804, + max: 341351, + fanout_cpu_median: 4.56, + generator_cpu_median: 2.53, + }, + { + processes_per_signal: 64, + median: 540102, + min: 293700, + max: 543941, + fanout_cpu_median: 5.83, + generator_cpu_median: 4.64, + }, + ], + mixed: [ + { + processes_per_signal: 1, + median: 41300, + min: 40269, + max: 41362, + fanout_cpu_median: 4.92, + generator_cpu_median: 0.31, + }, + { + processes_per_signal: 2, + median: 81075, + min: 80661, + max: 81651, + fanout_cpu_median: 4.44, + generator_cpu_median: 0.65, + }, + { + processes_per_signal: 4, + median: 148972, + min: 130086, + max: 154626, + fanout_cpu_median: 5.09, + generator_cpu_median: 1.33, + }, + { + processes_per_signal: 8, + median: 244888, + min: 219064, + max: 273901, + fanout_cpu_median: 6.06, + generator_cpu_median: 2.56, + }, + { + processes_per_signal: 16, + median: 330232, + min: 325618, + max: 364301, + fanout_cpu_median: 6.39, + generator_cpu_median: 4.29, + }, + { + processes_per_signal: 32, + median: 429749, + min: 429504, + max: 471506, + fanout_cpu_median: 6.95, + generator_cpu_median: 7.02, + }, + { + processes_per_signal: 64, + median: 422667, + min: 384338, + max: 441460, + fanout_cpu_median: 6.79, + generator_cpu_median: 7.49, + }, + ], + }, +} as const; + +export type Signal = keyof typeof benchmark.sweeps; +export const signalNames: Record = { + traces: "Traces", + logs: "Logs", + metrics: "Metrics", + mixed: "Mixed", +}; +export const formatRate = (value: number) => value.toLocaleString("en-US"); +export const peak = (signal: Signal) => + benchmark.sweeps[signal].reduce((best, point) => + point.median > best.median ? point : best, + ); +export const acceptedTotal = Object.values(benchmark.accepted_total).reduce( + (sum, value) => sum + value, + 0, +); +export const composition = [ + { label: "Spans", rate: benchmark.sustained.spans_per_second }, + { label: "Log records", rate: benchmark.sustained.log_records_per_second }, + { + label: "Metric points", + rate: benchmark.sustained.metric_points_per_second, + }, +];