Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,34 @@ and the project (informally) follows [Semantic Versioning](https://semver.org/).

## [Unreleased]

### Performance — Analyze & Suggest on the 2-vCPU Space (30 s → 75 s regression)

- **Step-2 result payload no longer ships full-grid per-branch arrays.** Each
combined-action pair carried `p_or_combined` / `p_ex_combined` — one float per
line of the grid (~6–8k) × ~100 pairs ≈ **29 MB** on the European grid — that
the frontend never reads (`CombinedAction` uses only betas / max_rho /
rho_before / rho_after; session-reload rebuilds them as `[]`). New
`services/analysis/combined_pairs.slim_combined_actions_for_payload()` empties
them at the step-2 API boundary. On the reported case (`eu-pyrenees`): payload
**29 269 KiB → 267 KiB**, `sanitize_for_json` **2.57 s → 0.01 s**, and the
"Other (network / streaming)" bucket **3.80 s → 0.51 s** — plus a proportional
cut to the real browser transfer. Covered by
`tests/test_combined_actions_payload_slim.py`.
- **Reassessment forced serial on the Space** via
`EXPERT_OP4GRID_REASSESSMENT_PARALLEL=0` in the `Dockerfile`. The library's
new container-aware detection already picks serial on 2 vCPUs; the env pin
makes it explicit. (The 47 s assessment was ~10 worker threads over-subscribing
2 vCPUs, each cloning a full network — see the `expert_op4grid_recommender`
changelog.)
- **New benchmark** `benchmarks/bench_analyze_suggest.py` drives the exact
`/api/config → step1 → step2` path via `TestClient` and prints the UI
execution-time breakdown with "Other" decomposed (discovery-overhead /
sanitize / transport); `--serial`, `--compare`, `--tier`, `--study`. Full
write-up in `docs/performance/history/analyze-suggest-2vcpu.md`.
- The step-2 `result` event now also carries `reassessment_parallelism`
(`{parallel, workers, cores_available, n_actions}`) so a client can confirm
serial vs parallel and on how many effective cores.

### Compatibility with the `expert_op4grid_recommender` typed-pipeline refactor

- **`run_analysis_step1` now tolerates the library's new single-value return.**
Expand Down
44 changes: 44 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,50 @@ NAD/SLD payloads:

---

## Contributing & Pull Requests

- **Upstream is `ainetus`; `marota` is the working fork.** Development branches
are pushed to `marota/Co-Study4Grid`, but **pull requests are opened directly
against the upstream `ainetus/Co-Study4Grid`** (base = its default branch,
head = `marota:<branch>`) — *not* against `marota`. The sibling library
`Expert_op4grid_recommender` follows the same rule against
`ainetus/Expert_op4grid_recommender`.
- **Load `ainetus` as an initial source.** A cross-fork PR into `ainetus` can
only be created from a session/tool context that has the `ainetus` repo in
scope, so a new working session should be started with
**`ainetus/Co-Study4Grid` and `ainetus/Expert_op4grid_recommender` as the
initial sources** (they should always be auto-loaded). A session rooted only
at `marota` cannot target `ainetus` (cross-tier adds are blocked) and the PR
step fails with an access-denied error.
- **Sync `marota` with `ainetus` before starting new work.** PRs merge into
`ainetus/main`, but development happens on `marota`, so `marota/main` drifts
behind `ainetus/main` after every merged PR (this applies to **both** repos —
Co-Study4Grid and Expert_op4grid_recommender). **At the start of a dev session,
bring `marota/main` up to date with `ainetus/main`** — GitHub "Sync fork", or
locally `git fetch ainetus main && git merge --ff-only ainetus/main` then push
`marota/main` — and branch from there. Skipping this makes a new branch collide
with the already-merged revisions when it is PR'd into `ainetus`. If the sync
was missed and the PR already shows conflicts, merge `ainetus/main` into the
branch (or rebase onto it) and resolve, then force-with-lease push.
- **DCO sign-off is required on every commit.** The `ainetus` repos enforce the
[Developer Certificate of Origin](https://developercertificate.org/): every
commit must carry a `Signed-off-by: <Name> <amarot91@gmail.com>` trailer, and
because the DCO check matches the sign-off against the commit **author**, the
commit must also be *authored* under that same identity (author email =
`amarot91@gmail.com`):

```bash
git config user.name "<Name>"
git config user.email "amarot91@gmail.com"
git commit -s -m "..." # -s appends the Signed-off-by trailer
```

To sign off commits already made under a different identity, re-author and add
the trailer (`git rebase --exec 'git commit --amend --no-edit --reset-author \
-s' <base>`), then force-with-lease push.

---

## Standalone Interface Parity Audit

The detailed audit — feature inventory, mirror-status table, Layer
Expand Down
8 changes: 8 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,15 @@ COPY --chown=user --from=frontend /build/dist ./frontend/dist
COPY --chown=user frontend/src/utils/svg/pinGlyph.js ./frontend/src/utils/svg/pinGlyph.js

# The backend serves this directory at "/" (same origin as the API).
#
# EXPERT_OP4GRID_REASSESSMENT_PARALLEL=0 forces the per-action reassessment to
# run SERIALLY. The Space runs on 2 vCPUs; the recommender's container-aware
# detection already picks serial there, but pinning it makes the guarantee
# explicit and independent of the host's cgroup exposure — parallel worker
# threads each clone a full pypowsybl network, so on 2 vCPUs they over-subscribe
# the CPU and are far SLOWER than serial (the 47 s → ~15 s assessment win).
ENV COSTUDY4GRID_FRONTEND_DIST=/home/user/app/frontend/dist \
EXPERT_OP4GRID_REASSESSMENT_PARALLEL=0 \
PORT=7860

EXPOSE 7860
Expand Down
27 changes: 27 additions & 0 deletions benchmarks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,35 @@ export BENCH_CONTINGENCY=DISCO_NAME # only for bench_n1_diagram
| `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/config` → `step1` → `step2` (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` |
| `run_all.py` | Drives every benchmark above sequentially. | — |

### `bench_analyze_suggest.py`

```bash
# 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
Expand Down
Loading
Loading