vscode icon indicating copy to clipboard operation
vscode copied to clipboard

Window hang when rendering deeply nested trees

Open roblourens opened this issue 1 year ago • 6 comments

  • Install the Red Hat YAML extension
  • Have the Outline view visible on the screen
  • Open this file and copy the contents ghpr2.log
  • Open new untitled editor in vscode
  • Paste
  • File language is auto-detected as YAML, or change it to YAML if it picked a different one
  • Renderer process hang

When I disable the YAML extension, this doesn't repro

roblourens avatar May 29 '24 17:05 roblourens

Stack that might be infinitely recursive

F (indexTreeModel.ts:705)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
F (indexTreeModel.ts:711)
getNode (indexTreeModel.ts:755)
getParentNodeLocation (objectTreeModel.ts:305)
w (abstractTree.ts:503)
v (abstractTree.ts:487)
renderElement (abstractTree.ts:417)
renderElement (listWidget.ts:1249)
Z (listView.ts:940)
(anonymous) (listView.ts:876)
transact (rowCache.ts:80)
Y (listView.ts:867)
ib (listView.ts:1107)
y (event.ts:1196)
z (event.ts:1207)
fire (event.ts:1231)
(anonymous) (scrollableElement.ts:216)
y (event.ts:1196)
fire (event.ts:1227)
n (scrollable.ts:393)
setScrollPositionNow (scrollable.ts:303)
setScrollPosition (scrollableElement.ts:619)
setScrollTop (listView.ts:1030)
reveal (listWidget.ts:1909)
reveal (abstractTree.ts:2989)
H (outlinePane.ts:332)
y (event.ts:1196)
z (event.ts:1207)
fire (event.ts:1231)
p (documentSymbolsOutline.ts:404)
n (documentSymbolsOutline.ts:370)
await in n (async)
(anonymous) (documentSymbolsOutline.ts:189)
y (event.ts:1196)
z (event.ts:1207)
fire (event.ts:1218)
(anonymous) (codeEditorWidget.ts:275)
y (event.ts:1196)
fire (event.ts:1227)
D (editorConfiguration.ts:110)
updateOptions (editorConfiguration.ts:167)
updateOptions (codeEditorWidget.ts:414)
Mb (textCodeEditor.ts:49)
Qb (textEditor.ts:323)
(anonymous) (textEditor.ts:188)
y (event.ts:1196)
z (event.ts:1207)
fire (event.ts:1231)
(anonymous) (codeEditorWidget.ts:1730)
y (event.ts:1196)
fire (event.ts:1227)
s (viewModelEventDispatcher.ts:64)
emitOutgoingEvent (viewModelEventDispatcher.ts:39)
(anonymous) (viewModelImpl.ts:442)
y (event.ts:1196)
z (event.ts:1207)
fire (event.ts:1231)
setLanguageId (tokenizationTextModelPart.ts:331)
Fb (textModel.ts:1956)
setLanguage (textModel.ts:1951)
z (textEditorModel.ts:98)
F (textEditorModel.ts:134)
await in F (async)
(anonymous) (textEditorModel.ts:119)
queue (async.ts:231)
(anonymous) (async.ts:423)
(anonymous) (async.ts:364)
Promise.then (async)
trigger (async.ts:358)
trigger (async.ts:423)
D (textEditorModel.ts:119)
mb (untitledTextEditorModel.ts:406)
(anonymous) (untitledTextEditorModel.ts:376)
(anonymous) (textModel.ts:231)
y (event.ts:1196)
z (event.ts:1207)
fire (event.ts:1231)
endDeferredEmit (textModel.ts:2508)
pushEditOperations (textModel.ts:1273)
c (cursor.ts:795)
executeCommands (cursor.ts:753)
G (cursor.ts:359)
(anonymous) (cursor.ts:595)
L (cursor.ts:519)
paste (cursor.ts:594)
(anonymous) (viewModelImpl.ts:1061)
S (viewModelImpl.ts:1107)
R (viewModelImpl.ts:1043)
paste (viewModelImpl.ts:1061)
Wb (codeEditorWidget.ts:1149)
trigger (codeEditorWidget.ts:1075)
I (copyPasteController.ts:535)
await in I (async)
(anonymous) (copyPasteController.ts:320)
await in (anonymous) (async)
b (async.ts:27)
z (copyPasteController.ts:302)
w (copyPasteController.ts:293)
(anonymous) (copyPasteController.ts:105)
(anonymous) (clipboard.ts:229)
runCommand (editorExtensions.ts:229)
handler (editorExtensions.ts:155)
invokeFunction (instantiationService.ts:109)
n (commandService.ts:95)
executeCommand (commandService.ts:60)
M (abstractKeybindingService.ts:370)
J (abstractKeybindingService.ts:225)
(anonymous) (keybindingService.ts:281)

roblourens avatar May 29 '24 17:05 roblourens

I see that we end up with every row producing a symbol that is a child of the preceeding row and I think we get really inefficient at rendering extremely deeply nested trees.

I can't repro the hang in Stable, but I do see that the outline view doesn't render properly and things are slow

roblourens avatar May 29 '24 18:05 roblourens

I'm a little confused because it's easily reproable and seems worse in Insiders, Logan and Devin confirmed this too, but I don't see any interesting changes in any relevant outline view or tree files for months or years, so any ideas @jrieken or @joaomoreno?

roblourens avatar May 29 '24 18:05 roblourens

Not a recent regression, since it repros in Stable, so moving it to June.

After a few profiling runs, I could find two culprits here: sticky scrolling and tree indent guides. The issue no longer reproduces if you disable both of those features in the user settings. Also, even after disabling both those features, a profile of scrolling all the way down and then all the way up, while somewhat smooth, still reveals some fat frames (70ms on my M2 machine) which could definitely be optimized. The deep stacks are not infinite but just super deep and are the result of these two recursive functions: https://github.com/microsoft/vscode/blob/f10898df1d33b0cb8486e2cade6713f952ac6fe7/src/vs/base/browser/ui/tree/indexTreeModel.ts#L684-L713 (funny how they claim they are cheap 😆). We should refactor these to be iterative instead of recursive and see if that helps with the runtime of getNode.

Finally, I think we should also follow up with the Red Hat so they figure out a better strategy of reporting outline information on such a file which clearly isn't valid YAML straight from the first character.

joaomoreno avatar May 29 '24 19:05 joaomoreno

To be clear, were you able to repro on stable? I was never able to repro a full hang on stable, with all the same settings and extensions. But I can believe that it should be the same in theory.

And our language detection always seems to love detecting 'yaml' on files that are not yaml.

roblourens avatar May 29 '24 20:05 roblourens

Yeah I did repro and profile on stable only. 👌

And our language detection always seems to love detecting 'yaml' on files that are not yaml.

Yeah maybe another good follow up!

joaomoreno avatar May 29 '24 20:05 joaomoreno

@roblourens AFAIK it has always been like this with Sticky Scroll further emphasizing it

rendering upwards of 50 nested levels causes very noticeable shuttering with upwards of 1000 nested levels, hanging VSCode for multiple minutes

  • https://github.com/microsoft/vscode/issues/235890
  • https://github.com/microsoft/vscode/issues/233056
  • https://github.com/microsoft/vscode/issues/232263
  • https://github.com/microsoft/vscode/issues/230361
  • https://github.com/microsoft/vscode/issues/61524
  • https://github.com/microsoft/vscode/issues/235014

dup:

  • https://github.com/microsoft/vscode/issues/205840

RedCMD avatar Mar 28 '25 04:03 RedCMD