Skip to content

Improve desktop mode performance#275

Open
grahamfindlay wants to merge 11 commits into
SpikeInterface:mainfrom
grahamfindlay:perf/desktop-traceview
Open

Improve desktop mode performance#275
grahamfindlay wants to merge 11 commits into
SpikeInterface:mainfrom
grahamfindlay:perf/desktop-traceview

Conversation

@grahamfindlay

@grahamfindlay grahamfindlay commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Several parts:

(1) Align the spike vector dtype for fast np.searchsorted on trace view refresh

For 83.5M spikes, reduces each np.searchsorted call (triggered by every trace view refresh) from ~730 ms to ~4 us (essentially free).

(2) Avoid scanning the whole segment in get_selected_spikes_data

It built np.isin(arange(n_spikes_in_segment), selected) on every refresh.
For 83.5M spikes, was ~1.3s even with nothing selected, now essentially free.

(3) Avoid refreshing views hidden behind a tab (and do refresh them when brought forward)

(4) Avoid materializing a whole zarr time vector in get_times_chunk, and just get visible times.

(5) Remove eager refreshing of all views on startup -- this is now possible thanks to (3).

(6) Fast splitting of clusters from selected spikes (e.g. in spike amplitude view)

This cuts the time it takes to split clusters on long recordings from minutes (or even hours) to <1s.

(7) Fix some preexisting failing tests (from the pre-SortingAnalyzer era).

Not to actually have test coverage (yes, I read the README 😆):

Contrary to the spikeinterface package, for the development of this viewer all good practices of coding are deliberately put aside: no test, no CI, no auto formatting, no doc, ... Feel free to contribute, it is an open wild zone. Code anarchists are very welcome. So in this mess, persona non grata: pre-commit, black, pytest fixture, ...

Just to silence the warnings!

…lder

argparse was stores --recording-base-folder as args.recording_base_folder, but
run_mainwindow_cli() was trying to access the non-existent args.recording_base_path.

That error was caught by the except and only printed a misleading
'check the path or the file format', so --recording silently failed.
For 83.5M spikes, reduces each call from ~730 ms to ~4 us aligned.
This is important, because it is triggered by every trace view refresh.
It built `np.isin(arange(n_spikes_in_segment), selected)` on every
refresh: ~1.3 s at 83.5M spikes, even with nothing selected.
`selected_indices` are absolute, so filter them to the segment and index
directly.
…sh (align spike dtype; direct-index selected spikes)
`recording.get_times()`` without frame bounds risks loading a whole zarr
time vector into memory. We only need to read the visible window.
`visibilityChanged(True)` is already triggered for each front tab on the
initial `win.show()`, is triggered for views behind tabs when they are
brought to the front (fixed in previous commit), so the eager refresh-all
loop was either redundant (for front tabs) or unnecessary (for hidden tabs).
When using e.g. the spikeamplitude view to split select spikes and then
split a cluster, `Controller.make_manual_split_if_possible` was doing
a slow O(N_selected x N_unit_spikes) loop to get the spike positions
within the unit's train and to validate that the selected spikes belong
to the unit.

`np.searchsorted(spike_inds, indices)` can do both in one pass.

On long recordings, this cuts the time it takes to split a cluster from
minutes (or even hours) to <1 second.
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.

1 participant