Skip to content

perf(render): fix lazy-render and fold performance for large sessions#393

Open
jensenojs wants to merge 1 commit into
sudo-tee:mainfrom
jensenojs:fix/render-perf
Open

perf(render): fix lazy-render and fold performance for large sessions#393
jensenojs wants to merge 1 commit into
sudo-tee:mainfrom
jensenojs:fix/render-perf

Conversation

@jensenojs
Copy link
Copy Markdown
Contributor

Problem

2786-message sessions take ~36 seconds to render. Two root causes:

  1. set_folds() uses cursor() + normal! zc/zo per fold, each triggering a full-screen redraw (~90ms/fold × 392 folds)
  2. _render_full_session_data() renders all messages on initial load

Closes #392

Changes

Fold performance (36s → 3s)

  • Replace vim.fn.cursor() + normal! zc/zo with :{from},{to}fold and :{from},{to}foldopen! — Ex commands don't move the cursor, zero screen redraws
  • Switch to foldmethod=manual before creating folds and stay there — prevents foldexpr recalculation for every buffer line (~4.6s on 87K lines)
  • Add line count validation to prevent E16: Invalid range errors

Lazy render (3s → ~10ms)

  • Only render enough messages to fill the output window on initial load (~1.5× viewport height)
  • Load more on scroll-to-top via WinScrolled autocmd
  • opts.lazy = true explicit opt-in — tests and headless environments render all messages
  • Fix lazy_render_count being cleared by M.reset(): read before reset, persist back to ctx after determining limit
  • Debounce WinScrolled load_more callback (150ms) to prevent rapid re-renders during fast scrolling
  • Remove debug vim.notify logging from render paths

Performance

Phase Before After
Fold creation ~35,266ms ~0.8ms
Total render ~36,000ms ~10ms
E2E (incl. async fetch) ~36,000ms ~1,875ms

Measured on a 2786-msg / 87K-line session

Testing

7 new test cases in tests/unit/renderer_lazy_spec.lua:

  • Renders all messages when lazy=false
  • Renders limited messages when ctx.lazy_render_count is set
  • Preserves lazy_render_count increment across render reset (exposes the core bug)
  • load_more_messages increments rendered message count
  • load_more_messages returns false when all/no messages loaded
  • No INFO-level debug notifications during rendering

All 110 existing tests pass.

- Replace cursor+zc fold creation with :{from},{to}fold Ex commands
  — avoids cursor-triggered screen redraws (~90ms/fold in large buffers)
- Switch to foldmethod=manual and stay there — prevents foldexpr
  recalculation on every buffer line (~4.6s on 87K lines)
- Lazy-render only viewport-sized message count on initial load
- Load more messages on scroll-to-top via WinScrolled autocmd
- Fix lazy_render_count being cleared by M.reset() — read before reset,
  persist back to ctx after determining limit
- Debounce WinScrolled load_more callback (150ms) to prevent rapid
  re-renders during fast scrolling
- Remove debug vim.notify logging from render paths

Performance: ~36s → ~10ms render time on a 2786-msg/87K-line session.

Closes sudo-tee#392
@sudo-tee
Copy link
Copy Markdown
Owner

Thanks for the PR.

I will have a look at soon, I will be out for the weekend. So I will look at it at the start of the next week

@jensenojs
Copy link
Copy Markdown
Contributor Author

I want to go out and have fun too. Have a nice weekend!

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.

Rendering large sessions is extremely slow (>30s for ~2800 messages)

2 participants