github-actions[bot]
Deploy 7688ef1
13d4e44
|
Raw
History Blame Contribute Delete
7.01 kB

Co-Study4Grid — Performance benchmarks

Consolidated micro-benchmarks that exercise the critical path of a Load Study on the reference PyPSA-EUR France 400 kV grid (~25 MB SVG, 6 835 VLs, 85 304 switches, 14 880 loads+generators, 55 104 operational-limit entries).

These scripts drive the same code paths as the web UI but without the HTTP stack, so they can be re-run after a patch to catch regressions before pushing.

Prerequisites

# Same venv as the backend (`expert_backend`) — needs:
#   pypowsybl, expert_op4grid_recommender, pandas, numpy
export PATH="$HOME/.asdf/shims:$PATH"
python -c "import pypowsybl, expert_op4grid_recommender"

Override the reference grid / action file via env vars:

export BENCH_NETWORK_PATH=/path/to/grid_dir          # contains grid.xiidm + grid_layout.json
export BENCH_ACTION_FILE=/path/to/reduced_actions.json
export BENCH_CONTINGENCY=DISCO_NAME                  # only for bench_n1_diagram.py

Scripts

Script What it measures Where the patch history lives
bench_load_study.py Full /api/config + 4 parallel XHRs round-trip (reset + load_network + update_config + 4 response helpers). Cumulative target of every patch on the branch. docs/performance/history/loading-parallel.md
bench_topology_cache.py Per-helper + full NetworkTopologyCache(net) init. Validates upstream vectorisation series (0.2.0.post3 → post8). docs/performance/history/vectorize-topology-cache.md, docs/performance/history/topology-cache-iter2.md
bench_voltage_level_queries.py /api/voltage-levels, /api/nominal-voltages, get_monitored_elements, _get_switches_with_topology narrow-attr wins. docs/performance/history/narrow-voltage-level-queries.md
bench_n1_diagram.py Full get_n1_diagram(contingency) cold + warm, per-sub-step breakdown. Validates the 3 N-1 fast-path patches. docs/performance/history/n1-diagram-fast-path.md
bench_nad_n_state.py get_network_diagram() cold + warm on the N-state. Captures NAD / SVG / Meta sub-timings from the [RECO] log lines. docs/performance/nad-profile-bare-env.md
bench_nad_toggles.py Matrix of NadParameters toggle combinations — quantifies per-flag impact on NAD gen + SVG size, surfaces the cost of injections_added=True. docs/performance/nad-profile-bare-env.md
bench_analyze_suggest.py Full "Analyze & Suggest" for a Game Mode study — drives /api/configstep1step2 (streaming NDJSON) through the FastAPI TestClient and prints the UI's execution-time breakdown (step1 / overflow / prediction / assessment / enrichment / Other), with "Other" decomposed into discovery-overhead / result sanitize_for_json / transport. --serial forces serial reassessment; --compare runs parallel-vs-serial. This is the case the 30 s → 75 s regression was reported on. docs/performance/history/analyze-suggest-2vcpu.md
bench_load_flow_modes.py Per-LF knob sweep — times a single run_ac on the N-1 state under each load-flow parameter variant (tap-changer control mode, shunt / reactive / phase-shifter toggles), reporting time / Newton iters / constrained-line current. Isolates the ~6x reassessment cost to transformer_voltage_control_on and shows AFTER_GENERATOR_VOLTAGE_CONTROL recovers it. --contingency / --overload / --reps. docs/performance/history/reassessment-fast-mode-tap-control.md
run_all.py Drives every benchmark above sequentially.

bench_analyze_suggest.py

# The reported "this case, first scenario": Pyrenees LANNEL61PRAGN on the
# medium/European grid (its network.xiidm ships as a Git-LFS zip — run
# `git lfs pull` first, or use --tier high for the uncompressed French grid).
python benchmarks/bench_analyze_suggest.py                 # medium tier, first study
python benchmarks/bench_analyze_suggest.py --tier high     # French grid, first study
python benchmarks/bench_analyze_suggest.py --compare       # parallel vs serial, same case

Two levers this benchmark validates:

  • Per-action reassessment goes serial on a CPU-limited host. The tail line reports reassessment: serial|parallel — N worker(s) / M effective core(s). On a 2-vCPU host the recommender's container-aware detection picks serial; even on a 4-core dev box --compare shows parallel is no faster than serial (each worker clones a full network), so over-subscribing 2 vCPUs with ~10 workers was the 47 s assessment in the regression.
  • The step-2 result payload no longer ships full-grid per-branch arrays. Each combined-action pair used to carry p_or_combined / p_ex_combined (one float per line × ~100 pairs ≈ 29 MB on the European grid); the frontend reads neither, so they are emptied at the API boundary. Watch payload=… KiB and the result sanitize_for_json sub-line drop (29 269 KiB / 2.57 s → 267 KiB / 0.01 s).

Reference measurements

On a developer box with pypowsybl 1.14.0 + Python 3.12 + the full PyPSA-EUR France 400 kV grid, current branch tip:

bench_load_study.py

Segment Measured
reset() ~0 ms
load_network ~2 200 ms
update_config ~5 900 ms
4 response XHRs ~330 ms
Total ~8.5 s

This maps to ~8.8 s end-to-end wall-clock on Chrome DevTools traces — see v18 row of docs/performance/history/loading-parallel.md (-63 % vs v6 baseline).

bench_voltage_level_queries.py

Endpoint Before After
/api/voltage-levels 7.5 ms 4.5 ms
/api/nominal-voltages 144 ms 5.7 ms (~25×)
get_monitored_elements 265 ms 175 ms
_get_switches_with_topology 174 ms 141 ms

bench_n1_diagram.py (contingency ARGIAL71CANTE)

Call Before After
COLD (first view) 18 125 ms 4 159 ms (-77 %)
WARM (repeat view) 11 906 ms 3 200 ms (-73 %)

When to run them

  • Before pushing a perf patch on the backend or on expert_op4grid_recommender: run the benchmark closest to the change and confirm no regression on the rest via run_all.py.
  • When a DevTools trace suggests slowdown: map the hot span to one of the four scripts to isolate it from web-layer variance.
  • When upstream bumps expert_op4grid_recommender: re-run bench_topology_cache.py + bench_voltage_level_queries.py to catch behavioural changes in pypowsybl / numpy / pandas upgrades.

Notes

  • These scripts import expert_backend.services.* directly, so they need to run inside the Co-Study4Grid venv.
  • Each benchmark is idempotent — running one does not alter global state in a way that would affect the next (each call to setup_service resets the recommender).
  • The scripts intentionally use real data paths rather than mocks: the goal is to measure the full pypowsybl + JNI + pandas stack. Unit tests in expert_backend/tests/ cover the mock path.