Skip to content

editor: Skip multi-cursor selection broadcast when unshared - #59731

Closed
Rani367 wants to merge 3 commits into
zed-industries:mainfrom
Rani367:multicursor-perf-track-a
Closed

editor: Skip multi-cursor selection broadcast when unshared#59731
Rani367 wants to merge 3 commits into
zed-industries:mainfrom
Rani367:multicursor-perf-track-a

Conversation

@Rani367

@Rani367 Rani367 commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Follow-up to #58510. Profiling multi-cursor typing on current main showed the per-keystroke set_active_selections broadcast does an O(selections) multi-buffer anchor remap and runs even with zero collaborators (about 0.9ms/call at 1k cursors, 8.4ms at 10k, fired ~3x per edited iteration).

This skips the broadcast when the buffer has no audience, and re-publishes on share so there is no regression:

  • Add CollaborationHub::should_broadcast_selections, defaulting to true. Entity<Project> overrides it to Project::is_shared(), which is true for a host that shared the project and for a collab guest, and stays correct before peer-join notifications have propagated locally (unlike a live collaborator count). A purely local project has no audience.
  • Gate set_active_selections in selections_did_change on it. Follow-mode is unaffected since it uses the separate UpdateFollowers/UpdateView channel, and the focused user's own cursors render from editor.selections, not remote_selections.
  • When the project becomes (re)shared (RemoteIdChanged(Some), Reshared, HostReshared), the focused editor re-publishes its current selections, so a peer joining after a share still sees the host's cursor without waiting for the next selection change.
  • Reuse the post-edit display snapshot in the hard_wrap branch instead of taking a redundant fresh buffer snapshot.

Multi-cursor type+delete benchmark: about 5% faster at both 1k and 10k cursors (615 to 583 ms at 10k, significant). All 773 editor tests pass locally. Collab and channel-buffer integration tests need the test DB, so they run on CI.

Discussion and profiling: #32051

Release Notes:

  • Improved multi cursor editing performance

@cla-bot cla-bot Bot added the cla-signed The user has signed the Contributor License Agreement label Jun 22, 2026
@Rani367
Rani367 marked this pull request as ready for review June 24, 2026 17:52
@yara-blue yara-blue added the area:editor Feedback for code editing, formatting, editor iterations, etc label Jun 25, 2026
Rani367 added 2 commits June 30, 2026 22:32
The per-keystroke `set_active_selections` broadcast does an O(selections)
multi-buffer anchor remap and runs even with zero collaborators. Profiling
multi-cursor typing showed it costs ~0.9ms/call at 1k cursors and ~8.4ms at
10k, fired ~3x per edited iteration — pure overhead when nobody is observing.

- Add `CollaborationHub::should_broadcast_selections`, defaulting to `true`.
  `Entity<Project>` overrides it to `Project::is_shared()`, which is true for a
  host that shared the project and for a collab guest, and stays correct before
  peer-join notifications have propagated locally (unlike a live collaborator
  count). A purely local project has no audience.
- Gate the `set_active_selections` call in `selections_did_change` on it.
  Follow-mode is unaffected (it uses the separate UpdateFollowers/UpdateView
  channel); the focused user's own cursors render from `editor.selections`, not
  `remote_selections`.
- input: reuse the post-edit display snapshot in the `hard_wrap` branch instead
  of taking a redundant fresh buffer snapshot.

~5% faster multi-cursor type+delete at both 1k and 10k cursors (615->583ms at
10k, significant). All 773 editor tests pass.
The previous commit skips the per-keystroke selection broadcast while a
project is unshared. On its own that means a peer joining right after the
host shares the project would not see the host's cursor until the host next
moved it.

Re-publish the focused editor's current selections when the project emits
RemoteIdChanged(Some), Reshared, or HostReshared, reusing the same focus and
leader gating as the per-change broadcast. Addresses review feedback on
zed-industries#32051.
@Rani367
Rani367 force-pushed the multicursor-perf-track-a branch from 0460cb2 to fbc1ce9 Compare June 30, 2026 19:40
Comment thread crates/editor/src/editor.rs Outdated
Comment on lines +11110 to +11111
fn should_broadcast_selections(&self, cx: &App) -> bool {
let _ = cx;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
fn should_broadcast_selections(&self, cx: &App) -> bool {
let _ = cx;
fn should_broadcast_selections(&self, _: &App) -> bool {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 54519f1, thanks.

@Rani367 Rani367 closed this Jul 3, 2026
@Rani367
Rani367 deleted the multicursor-perf-track-a branch July 3, 2026 14:20
@Rani367

Rani367 commented Jul 8, 2026

Copy link
Copy Markdown
Contributor Author

Replaced by #60605. This one got auto-closed when I accidentally deleted its branch, not because anything was wrong with it. The new one is rebased on latest main with @osiewicz's review feedback already applied.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:editor Feedback for code editing, formatting, editor iterations, etc cla-signed The user has signed the Contributor License Agreement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants