Skip to content

Commit 0c02e11

Browse files
authored
Merge pull request #125 from seqeralabs/edmundmiller/split-up-table-generation-and-report-generation
refactor: split benchmark report into JSONL stages
2 parents 1576360 + b01dd29 commit 0c02e11

40 files changed

Lines changed: 1854 additions & 2836 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@ modules/local/benchmark_report_v2/tests/data/
1919
.beads/
2020
.lineage/
2121
.claude/
22+
.hermes/

AGENTS.md

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ Nextflow pipeline to aggregate metrics across Seqera Platform pipeline runs.
88
input CSV (id, workspace, group, logs, fusion)
99
→ branch: api (SeqeraApi.fetchRunData) | external (EXTRACT_TARBALL)
1010
→ collect JSON files
11-
→ BENCHMARK_REPORT process (benchmark_report.py build-db + report)
12-
→ benchmark.duckdb + benchmark_report.html
11+
→ NORMALIZE_BENCHMARK_JSONL (raw JSON -> jsonl_bundle/)
12+
→ AGGREGATE_BENCHMARK_REPORT_DATA (jsonl_bundle -> report_data.json)
13+
→ RENDER_BENCHMARK_REPORT (report_data.json -> benchmark_report.html)
1314
```
1415

1516
## Key Params
@@ -32,26 +33,32 @@ input CSV (id, workspace, group, logs, fusion)
3233
## Rebuild Command (local testing)
3334

3435
```bash
35-
# Build DuckDB from JSON data:
36-
uv run --with duckdb --with typer --with pyyaml --with pyarrow \
37-
python bin/benchmark_report.py build-db \
38-
--data-dir /path/to/json_data --output /tmp/benchmark.duckdb
36+
# Normalize raw run JSON (+ optional CUR parquet) to JSONL bundle:
37+
uv run --with typer --with pyyaml --with pyarrow \
38+
python bin/benchmark_report.py normalize-jsonl \
39+
--data-dir /path/to/json_data --output-dir /tmp/jsonl_bundle
3940

40-
# Render HTML report from DuckDB:
41-
uv run --with duckdb --with jinja2 --with typer --with pyyaml \
42-
python bin/benchmark_report.py report \
43-
--db /tmp/benchmark.duckdb --brand assets/brand.yml --output /tmp/report.html
41+
# Aggregate JSONL bundle to report data:
42+
uv run --with typer --with pyyaml \
43+
python bin/benchmark_report.py aggregate-report-data \
44+
--jsonl-dir /tmp/jsonl_bundle --output /tmp/report_data.json
45+
46+
# Render HTML report from report_data.json:
47+
uv run --with jinja2 --with typer --with pyyaml \
48+
python bin/benchmark_report.py render-html \
49+
--data /tmp/report_data.json --brand assets/brand.yml --output /tmp/report.html
4450

4551
# Fetch run data from Seqera Platform API (standalone):
46-
uv run --with duckdb --with typer --with pyyaml --with httpx \
52+
uv run --with typer --with pyyaml \
4753
python bin/benchmark_report.py fetch \
4854
--run-ids <id> --workspace org/name --output-dir /tmp/json_data
4955
```
5056

5157
## Gotchas
5258

5359
- Wave freeze strategy: `['conda', 'container', 'dockerfile']` — no `spack` (breaks builds)
54-
- DuckDB `read_json_auto` needs file paths, not JSON strings — use temp files
60+
- JSONL is the primary handoff (`jsonl_bundle/`) for Fusion-friendly streaming
61+
- `report_data.json` is the explicit boundary between aggregation and rendering
5562
- `commit.gpgsign` must be true (SSH signing via 1Password)
5663
- RTK `buildOutputFiltering` / `testOutputAggregation` can swallow nf-test output — disable to debug
5764

@@ -62,14 +69,22 @@ uv run --with duckdb --with typer --with pyyaml --with httpx \
6269
| Service | Purpose | Run command |
6370
|---------|---------|-------------|
6471
| Nextflow pipeline | Core product — aggregates metrics from Seqera Platform runs | `nextflow run . --input <csv> --outdir results -profile docker` |
65-
| Python benchmark_report.py | Builds DuckDB + renders HTML report | See "Rebuild Command" section above |
72+
| Python benchmark_report.py | Normalizes JSON -> JSONL, aggregates report data, then renders HTML | See "Rebuild Command" section above |
6673

6774
### Running tests
6875

69-
- **pytest (Python unit tests):** `uv run --with duckdb --with typer --with pyyaml --with jinja2 --with pyarrow --with pytest --with httpx pytest bin/test_benchmark_report.py -v`
76+
- **pytest (Python unit tests):** `uv run --with typer --with pyyaml --with jinja2 --with pyarrow --with pytest --with httpx pytest -v modules/local/aggregate_benchmark_report_data/tests/test_aggregate.py modules/local/normalize_benchmark_jsonl/tests/test_normalize.py modules/local/render_benchmark_report/tests/test_render.py bin/test_benchmark_report_fetch.py`
7077
- **nf-test (pipeline integration tests):** `nf-test test --profile=+docker --verbose`
7178
- **Lint:** `pre-commit run --all-files`
7279

80+
### Agent quick verify (offline)
81+
82+
Run this exact sequence when validating split benchmark-report changes in Cursor Cloud:
83+
84+
1. `uv run --with typer --with pyyaml --with jinja2 --with pyarrow --with pytest --with httpx pytest -v modules/local/aggregate_benchmark_report_data/tests/test_aggregate.py modules/local/normalize_benchmark_jsonl/tests/test_normalize.py modules/local/render_benchmark_report/tests/test_render.py bin/test_benchmark_report_fetch.py`
85+
2. `nf-test test --profile=+docker --verbose`
86+
3. `nextflow run . --input workflows/nf_aggregate/assets/test_benchmark.csv --generate_benchmark_report --outdir /tmp/nf-aggregate-e2e-results -profile docker`
87+
7388
### Docker in Cloud VM (cgroupv2 workaround)
7489

7590
The Cloud VM runs inside a Firecracker VM where the root cgroupv2 hierarchy cannot delegate `memory`/`io` controllers. Docker containers that request resource limits (`--memory`, `--cpu-shares` — used by Nextflow's `process { memory; cpus }`) will fail with `"cannot enter cgroupv2 ... with domain controllers"`.

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,9 @@ The results from the pipeline will be published in the path specified by the `--
9191
```
9292
./results
9393
├── benchmark_report/
94-
│ ├── benchmark.duckdb
95-
│ └── benchmark_report.html ## Benchmark report
94+
│ ├── benchmark_report.html ## Benchmark report
95+
│ ├── report_data.json ## Aggregated report data boundary
96+
│ └── jsonl_bundle/ ## Streaming stage handoff (runs/tasks/metrics[/costs].jsonl)
9697
└── pipeline_info/
9798
```
9899

bin/AGENTS.md

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,34 @@ Python scripts executed inside Nextflow process containers. Placed in `bin/` so
44

55
## benchmark_report.py
66

7-
Unified benchmark report CLI. Typer app with 3 subcommands:
7+
Thin Typer CLI wrapper around focused modules.
88

99
| Subcommand | Purpose |
1010
|---|---|
11-
| `build-db` | JSON files (+ optional CUR parquet) → `benchmark.duckdb` with normalized tables (runs, tasks, metrics, costs) |
12-
| `report` | Opens `.duckdb` file → runs 9 SQL queries → renders self-contained HTML with eCharts |
13-
| `fetch` | Calls Seqera Platform API → writes run JSON files (standalone use, not used by Nextflow pipeline) |
11+
| `normalize-jsonl` | Raw run JSON (+ optional CUR parquet) → `jsonl_bundle/` (`runs.jsonl`, `tasks.jsonl`, `metrics.jsonl`, optional `costs.jsonl`) |
12+
| `aggregate-report-data` | `jsonl_bundle/``report_data.json` |
13+
| `render-html` | `report_data.json` + brand/logo assets → self-contained HTML |
14+
| `report` | Convenience wrapper (`aggregate-report-data` + `render-html`) |
15+
| `fetch` | Calls Seqera Platform API → writes run JSON files (standalone use) |
1416

15-
### DuckDB Tables
17+
## Focused modules
1618

17-
- `runs`one row per workflow run (id, group, pipeline, status, duration, efficiency, etc.)
18-
- `tasks`one row per task (hash, process, cost, cpus, memory, realtime, etc.)
19-
- `metrics`per-process resource stats (cpu/mem/time mean/min/q1-q3/max)
20-
- `costs`optional, from AWS CUR parquet (run_id, process, hash, cost, used_cost, unused_cost)
19+
- `benchmark_report_normalize.py`normalization stage
20+
- `benchmark_report_aggregate.py`report aggregation stage
21+
- `benchmark_report_render.py`HTML rendering stage
22+
- `benchmark_report_fetch.py`Seqera API fetch helpers
2123

22-
### Dependencies
24+
### Test ownership
2325

24-
`duckdb`, `jinja2`, `typer`, `pyyaml`, `pyarrow`, `httpx` (fetch only)
26+
Keep tests close to the stage they exercise:
27+
28+
- module-stage tests live under `modules/local/*/tests/`
29+
- CLI- and fetch-specific tests stay in `bin/`
30+
- shared pytest fixtures live in repo-root `conftest.py`
31+
32+
### Dependencies by stage
33+
34+
- normalize: `typer`, `pyyaml`, `pyarrow` (optional CUR parquet)
35+
- aggregate: stdlib (+ Typer in wrapper)
36+
- render: `jinja2`, `pyyaml`
37+
- fetch: stdlib networking

0 commit comments

Comments
 (0)