Skip to content

Avoid forced layout when measuring the Chat view title - #331846

Merged
Dmitriy Vasyura (dmitrivMS) merged 5 commits into
mainfrom
dev/dmitriv/observe-chat-title-height
Aug 20, 2026
Merged

Avoid forced layout when measuring the Chat view title#331846
Dmitriy Vasyura (dmitrivMS) merged 5 commits into
mainfrom
dev/dmitriv/observe-chat-title-height

Conversation

@dmitrivMS

Copy link
Copy Markdown
Collaborator

Background

This change comes from a Windows startup performance investigation across published Insiders builds and subsequent packaged CPU profiling.

A warmed renderer profile showed repeated synchronous calls to ChatViewTitleControl.getHeight() consuming about 20-30 ms during startup. getHeight() read titleContainer.offsetHeight, which could force Blink style/layout after the title or its toolbars changed.

Observed startup caller paths included:

ChatViewTitleControl.getHeight
<- ChatViewTitleControl.updateTitle
<- ChatViewTitleControl.doUpdate
<- ChatViewTitleControl.update
<- ChatViewPane.showModel

and:

ChatViewTitleControl.getHeight
<- ChatViewPane.layoutChatAndSessions
<- ChatViewPane.doLayoutBody
<- ViewPane layout

The title height is dynamic, but the browser already exposes that state asynchronously and before paint through ResizeObserver.

Change

  • Observe the Chat title container's border-box height.
  • Cache the most recently reported height.
  • Fire the existing onDidChangeHeight event only when the observed height changes.
  • Return the cached value from getHeight() instead of reading offsetHeight.
  • Keep the existing ChatViewPane relayout path, which applies the final observed size before paint.
  • Make the observer factory injectable so unit tests use a real-interface fake instead of replacing the global ResizeObserver.

There is no intended visual or accessibility change.

Startup improvement

Focused warmed CPU traces:

Metric Before After
ChatViewTitleControl.getHeight self-time 29.5 ms 0 ms

End-to-end validation used fully bundled current-source Windows desktop applications with identical Electron, resources, extensions, minification, and NLS processing. The applications differed only by this change.

Two independent campaigns ran 30 interleaved measured pairs each, alternating A/B and B/A order after three warmups.

Campaign Median startup change Bootstrap 95% interval
First 30 pairs -9.5 ms -27.5 ms to +4.0 ms
Repeat 30 pairs -11.5 ms -19.5 ms to -1.0 ms
Combined 60 pairs -11.5 ms -19.0 ms to -1.0 ms

The conservative end-to-end startup gain is 11.5 ms on this Windows host.

Repeated phase improvements across both campaigns:

Startup phase Combined paired change Bootstrap 95% interval
Restore primary viewlet -13.0 ms -14.0 ms to -11.0 ms
Restore auxiliary bar -13.0 ms -14.0 ms to -11.0 ms
Workbench create/restore -5.0 ms -8.0 ms to -3.0 ms
Restore editors -4.0 ms -8.0 ms to -1.0 ms
Renderer start to workbench ready -7.0 ms -11.0 ms to 0.0 ms

The phase measurements overlap and should not be summed.

Improvements to other scenarios

The removed forced layout was not startup-specific. The same code runs when:

  • A Chat model is shown or switched.
  • A session title/custom title changes.
  • A request updates a title.
  • Chat view actions or navigation controls change size.
  • Chat is restored in the primary sidebar.
  • Chat is restored in the auxiliary bar.
  • The containing pane is resized or moved between view locations.

These paths now consume the cached browser-reported height instead of synchronously flushing style/layout. ResizeObserver continues to trigger the existing relayout event whenever the real border-box height changes.

The measured 13 ms improvements in both primary viewlet and auxiliary-bar restoration demonstrate that the gain applies across multiple Chat view locations.

Compatibility and behavior

  • The title remains dynamically sized.
  • Visibility changes are reflected by the observer, including a height of zero.
  • Duplicate height notifications do not trigger redundant relayouts.
  • Final layout is applied before paint through the existing onDidChangeHeight listener.
  • The observer is disconnected with the control's disposables.
  • The observed element belongs to the same window as the Chat view, so auxiliary-window behavior is unchanged.
  • Keyboard navigation, ARIA state, labels, and focus behavior are unchanged.

The focused test verifies:

  1. An observed height updates getHeight().
  2. The existing height-change event fires.
  3. Repeating the same height does not fire another event.
  4. Observing zero updates the cache and fires the second real change.

Validation

npm run typecheck-client
npm run transpile-client
scripts\test.bat --run src\vs\workbench\contrib\chat\test\browser\widgetHosts\viewPane\chatViewTitleControl.test.ts --run src\vs\workbench\contrib\chat\test\browser\widget\chatWidget.test.ts
  • Client typecheck passed.
  • Client transpilation passed.
  • 16 focused Chat tests passed.
  • Production desktop baseline/fix bundles succeeded.
  • Packaged startup succeeded.
  • Two independent correctness/diff reviews found no significant issue.

Rejected alternatives

  • Coalescing title-bar overflow checks did not reduce the targeted CPU or forced-layout cost.
  • Replacing toolbar getBoundingClientRect() reads with cached observer width removed that leaf but did not improve packaged startup over 30 interleaved pairs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings August 20, 2026 17:35
@dmitrivMS Dmitriy Vasyura (dmitrivMS) added perf perf-startup layout General VS Code workbench layout issues workbench-views Workbench view issues labels Aug 20, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Replaces synchronous Chat title height reads with an asynchronously updated cache to reduce forced layout during startup and relayout.

Changes:

  • Adds ResizeObserver-based title height tracking.
  • Relayouts Chat when the cached height changes.
  • Adds focused height-change tests.
Show a summary per file
File Description
chatViewTitleControl.ts Adds observer-backed height caching.
chatViewPane.ts Uses the updated title control constructor.
chatViewTitleControl.test.ts Tests cached height and deduplication.

Review details

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

  • Files reviewed: 3/3 changed files
  • Comments generated: 2
  • Review effort level: Balanced

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@dmitrivMS
Dmitriy Vasyura (dmitrivMS) requested a balanced review from Copilot August 20, 2026 20:23

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 3/3 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@dmitrivMS
Dmitriy Vasyura (dmitrivMS) marked this pull request as ready for review August 20, 2026 20:35
@dmitrivMS
Dmitriy Vasyura (dmitrivMS) merged commit fea32a8 into main Aug 20, 2026
27 checks passed
@dmitrivMS
Dmitriy Vasyura (dmitrivMS) deleted the dev/dmitriv/observe-chat-title-height branch August 20, 2026 21:53
@vs-code-engineering vs-code-engineering Bot added this to the 1.135.0 milestone Aug 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

layout General VS Code workbench layout issues perf perf-startup workbench-views Workbench view issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants