Skip to content

perf: load wiring maps once per process instead of per session - #69

Draft
tabedzki wants to merge 6 commits into
m-beau:mainfrom
tabedzki:tabedzki/perf/shared-wiring-maps
Draft

tabedzki wants to merge 6 commits into
m-beau:mainfrom
tabedzki:tabedzki/perf/shared-wiring-maps

Conversation

@tabedzki

@tabedzki tabedzki commented Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

🤖 AI text below 🤖

Split out of #52 (the performance half).

What

  • make_wiring_maps(wiring_maps_dir) resolves its argument and passes it to _load_wiring_maps, a loader wrapped in functools.cache. Each process holds one copy of the wiring conflict maps per directory, and every caller gets that same object whether it passes a Path or a str.
  • The shared map is read-only: MappingProxyType views with frozenset values. A stray in-place mutation now raises an error instead of quietly changing electrode availability for every session. The pickle on disk is still plain dicts and sets.
  • Smaller cleanups: dropped a duplicate directory check, trimmed the docstrings, and the Electrodes.wiring_map annotation now accepts any read-only mapping.

Why

ChannelmapGUI.__init__ calls make_wiring_maps once per Panel session, and each call unpickled its own ~24 MB copy. Every copy is identical, and the GUI only reads it: Electrodes copies .keys(), looks up wiring_map[e] and does & intersections, all of which build new sets. That makes sharing one copy safe. Freezing it doesn't measurably change load time (0.24s vs 0.23s) or peak RSS (+70 MB either way).

Commits

Each commit does one thing:

  1. Share the map via the cache.
  2. Switch to functools.cache.
  3. Drop the duplicate check.
  4. Isolate the cache between tests.
  5. Make the map read-only.
  6. Trim the docstrings.

Each commit passes the tests on its own.

Tests

TestWiringMapsSharing covers:

  • the same object for Path vs str and across calls
  • cache_clear() reloads
  • a missing directory still raises
  • mutating the map raises
  • Electrodes select/deselect/undo/redo on the shared map leaves it unchanged and doesn't affect another session
  • a rebuild still writes a pickle that loads back (1.0 probe only, to keep it fast)

uv run pytest -q: 572 passed, 1 xfailed.

Assisted-by: ClaudeCode:claude-opus-5-5

Every ChannelmapGUI session called backend.make_wiring_maps(), which
unpickled its own ~24 MB copy of the electrode wiring conflict maps.
The result is identical across sessions and only ever read, so
make_wiring_maps now resolves its argument and delegates to an
lru_cache-backed loader. Every caller for a given directory, whether it
passes a Path or a str, gets the same object.

Split out of m-beau#52.

Assisted-by: ClaudeCode:claude-opus-5-5
@codecov-commenter

codecov-commenter commented Oct 16, 2026 •

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (main@4dfcfc7). Learn more about missing BASE report.
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@           Coverage Diff           @@
##             main      #69   +/-   ##
=======================================
  Coverage        ?   70.17%           
=======================================
  Files           ?       20           
  Lines           ?     3128           
  Branches        ?        0           
=======================================
  Hits            ?     2195           
  Misses          ?      933           
  Partials        ?        0           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

lru_cache(maxsize=None) is what functools.cache already spells.

Assisted-by: ClaudeCode:claude-opus-5-5
make_wiring_maps already asserts that the resolved directory exists
before calling _load_wiring_maps, so the loader's own check never fires.

Assisted-by: ClaudeCode:claude-opus-5-5
The sharing tests assert object identity, so a map cached by an earlier
test (or left behind by one) could make them pass or fail depending on
test order.

Assisted-by: ClaudeCode:claude-opus-5-5
make_wiring_maps now returns one object shared by every session, so an
in-place mutation (e.g. |= or .add() on a conflict set) would silently
change electrode availability for everyone. Return MappingProxyType
views with frozenset values instead, so mutating raises an error. The
pickle on disk stays plain dicts and sets. Load time and peak RSS are
unchanged. The Electrodes annotation now accepts any read-only mapping.

Assisted-by: ClaudeCode:claude-opus-5-5
Keep the contract (cached per directory, shared, read-only) and leave the
measurements and history to the commit log and PR. The read-only rule no
longer needs spelling out now that the mapping enforces it.

Assisted-by: ClaudeCode:claude-opus-5-5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants