Skip to content

perf: run a long note's first word count in slices (huge idle-lag 380 → 17 ms) - #324

Merged
lidonggui merged 1 commit into
mainfrom
perf/count-in-slices
Oct 11, 2026
Merged

lidonggui merged 1 commit into
mainfrom
perf/count-in-slices

Conversation

@lidonggui

Copy link
Copy Markdown
Collaborator

What

The longest stall after typing stops on a long note was the first word count. Block counts are cached, but the first count has nothing cached. It is scheduled 400 ms after mount, typing keeps deferring it, and so it ran as one ~380 ms task (all 43,970 blocks of the 8 MB doc) right after the first pause. Once it has run, a pause stalls nothing over 30 ms.

  • DocumentCounter (word-count.ts): a resumable count. It counts uncached blocks until told time is up (always at least one block per call), resumes on the same doc, starts over on a changed doc (the cache keeps what was already counted), and returns the same result as countDocumentWords.
  • NotoEditor.reportCount runs it in 8 ms slices with setTimeout(0) between them. The existing count timer covers the continuation, so a new edit or destroy cancels it.

Measurement fix

run-noto.mjs's idle-lag probe uses a buffered Long Tasks observer. The buffer held the open's own 450–650 ms mount task, so most idle-lag numbers reported until now were the open, not idle work. The probe now counts only long tasks that reach into the observed window.

Numbers (packaged, Linux x64, Xvfb, BENCH_RUNS=5, interleaved ×2, corrected probe)

before after
huge idle-lag 383 / 375 ms 16 / 18 ms
large idle-lag 105 / 110 ms 17 / 16 ms

Huge word count: identical (1,401,569 words). It now appears ~0.1 s later. Open, typing and save are unchanged within noise.

Tests: new DocumentCounter cases (every slice size gives the whole-document count; a changed doc restarts without re-measuring kept blocks). Typecheck and full unit suite are green.

The first count of a note has no cached block counts and ran as one task
right after the first pause in typing: about 380 ms on the 8 MB document.
DocumentCounter does the same counting in 8 ms slices, keeps its place,
and reports once every block has a count.

The bench's idle-lag probe also counted the open's own long tasks from its
buffered observer; it now counts only tasks reaching into the window.
@lidonggui
lidonggui merged commit a8e9112 into main Oct 11, 2026
7 checks passed
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