avoid deoptimizations in v8
See original GitHub issueThere are several code parts that trigger alot of deoptimizations in v8. Run
chrome --js-flags="--trace-opt --trace-deopt --trace"
to get the trace info. For my typical benchmark with ls -lR /usr/lib
the demo shows the following:
[deoptimizing (DEOPT eager): begin 0x27f83bd2d3b9 <JSFunction TextRenderLayer._forEachCell (sfi = 0x27f83bd1bf49)> (opt #2) @3, FP to SP delta: 96, caller sp: 0x7ffc6b031a28]
;;; deoptimize at <http://localhost:3000/dist/bundle.js:7140:36>, wrong map
[deoptimizing (DEOPT soft): begin 0x27f83bd2bea9 <JSFunction StaticCharAtlas.draw (sfi = 0x27f83bd2b189)> (opt #1) @19, FP to SP delta: 56, caller sp: 0x7ffc6b031748]
;;; deoptimize at <http://localhost:3000/dist/bundle.js:7740:36>, Insufficient type feedback for generic named access
[deoptimizing (DEOPT soft): begin 0x27f83bd19341 <JSFunction InputHandler.print (sfi = 0x27f83bd04fd1)> (opt #16) @53, FP to SP delta: 144, caller sp: 0x7ffc6b031dd0]
;;; deoptimize at <http://localhost:3000/dist/bundle.js:1999:30>, Insufficient type feedback for generic named access
[deoptimizing (DEOPT eager): begin 0x27f83bd19341 <JSFunction InputHandler.print (sfi = 0x27f83bd04fd1)> (opt #19) @21, FP to SP delta: 144, caller sp: 0x7ffc6b031e90]
;;; deoptimize at <http://localhost:3000/dist/bundle.js:2027:35>, wrong map
[deoptimizing (DEOPT lazy): begin 0x27f83bd4b819 <JSFunction Terminal.blankLine (sfi = 0x31d068a7c271)> (opt #28) @18, FP to SP delta: 72, caller sp: 0x7ffc6b031d00]
[deoptimizing (DEOPT eager): begin 0x27f83bd2d3b9 <JSFunction TextRenderLayer._forEachCell (sfi = 0x27f83bd1bf49)> (opt #7) @27, FP to SP delta: 96, caller sp: 0x7ffc6b031a28]
;;; deoptimize at <http://localhost:3000/dist/bundle.js:7143:36>, wrong map
[deoptimizing (DEOPT eager): begin 0x27f83bd17d11 <JSFunction EscapeSequenceParser.parse (sfi = 0x27f83bd11d89)> (opt #20) @21, FP to SP delta: 152, caller sp: 0x7ffc6b031fa8]
;;; deoptimize at <http://localhost:3000/dist/bundle.js:1561:25>, wrong call target
[deoptimizing (DEOPT soft): begin 0x27f83bd2c9a1 <JSFunction BaseRenderLayer.drawChar (sfi = 0x27f83bd1e431)> (opt #6) @39, FP to SP delta: 128, caller sp: 0x7ffc6b0318b0]
;;; deoptimize at <http://localhost:3000/dist/bundle.js:6278:18>, Insufficient type feedback for generic named access
[deoptimizing (DEOPT soft): begin 0x27f83bd19c81 <JSFunction InputHandler.charAttributes (sfi = 0x27f83bd066f1)> (opt #45) @9, FP to SP delta: 72, caller sp: 0x7ffc6b031eb8]
;;; deoptimize at <http://localhost:3000/dist/bundle.js:2619:34>, Insufficient type feedback for generic named access
[deoptimizing (DEOPT eager): begin 0x27f83bd2d3b9 <JSFunction TextRenderLayer._forEachCell (sfi = 0x27f83bd1bf49)> (opt #2) @3, FP to SP delta: 96, caller sp: 0x7ffc6b031a28]
;;; deoptimize at <http://localhost:3000/dist/bundle.js:7140:36>, wrong map
Not all of those are fixable, since the optimizer might end up with a wrong assumption. Still some of them can be fixed by avoiding some anti pattern:
- TextRenderLayer._forEachCell at bundle.js:7140:36: https://github.com/xtermjs/xterm.js/blob/5620da49d8590efd79ca06e995c89866c239e53e/src/renderer/TextRenderLayer.ts#L67 for some reason the buffer changed the underlying map type. This can happen with arrays, if different primtives are added or if there are holes in the array. Might be fixable by ensuring the buffer always contains the same inner types without any holes.
- StaticCharAtlas.draw at bundle.js:7740:36: https://github.com/xtermjs/xterm.js/blob/5620da49d8590efd79ca06e995c89866c239e53e/src/renderer/atlas/StaticCharAtlas.ts#L62
glyph.fg
access is not optimized, not sure how the glyph object is constructed, maybe an own object prototype/class can solve this. This deopt happens several times for one run. - InputHandler.print at bundle.js:1999:30: https://github.com/xtermjs/xterm.js/blob/5620da49d8590efd79ca06e995c89866c239e53e/src/InputHandler.ts#L400 seems this assigment of 0 is not easy lol, are we sure
buffer.x
always holds a number and is not undefined at some state? - InputHandler.print at bundle.js:2027:35: https://github.com/xtermjs/xterm.js/blob/5620da49d8590efd79ca06e995c89866c239e53e/src/InputHandler.ts#L443 seems the buffer row changes the type on the fly, maybe this is related to the
.isWrapped
attribute? Not all row have this flag (undefined for most), note that for v8 an additional attribute will change the internal type. Might be solvable by applying the flag asfalse
to all rows before using them. - Terminal.blankLine this was a deopt reason several times, v8 does not like the way the new line array is constructed there. Might be solvable by using
push
instead of index assigment to an empty array. This method is also performance critical in the stats. - TextRenderLayer._forEachCell at bundle.js:7143:36: https://github.com/xtermjs/xterm.js/blob/5620da49d8590efd79ca06e995c89866c239e53e/src/renderer/TextRenderLayer.ts#L70 the cell internal type changed for some reason, weird. Are there
CharData
objects with additional attributes? - EscapeSequenceParser.parse at bundle.js:1561:25: https://github.com/xtermjs/xterm.js/blob/5620da49d8590efd79ca06e995c89866c239e53e/src/EscapeSequenceParser.ts#L464 this is a weird deopt, I was able to track it down to several
charAttribute
calls (CSI m) and a followingeraseLine
(CSI K) which triggers the deopt. Not sure yet if this a wrong assumption of v8 that always CSI m will be called. In older chrome v58 it even shows an (unresolved function), no clue yet what causes it. - BaseRenderLayer.drawChar at bundle.js:6278:18: https://github.com/xtermjs/xterm.js/blob/5620da49d8590efd79ca06e995c89866c239e53e/src/renderer/BaseRenderLayer.ts#L251 seems
this._drawUncachedChar
cannot be resolved easily. No clue why. - InputHandler.charAttributes at bundle.js:2619:34: Here v8 cannot get
DEFAULT_ATTR
from the context object (made by the bundler). Not fixable imho.
There was another deopt in EscapeSequenceParser.parse https://github.com/xtermjs/xterm.js/blob/5620da49d8590efd79ca06e995c89866c239e53e/src/EscapeSequenceParser.ts#L378 which I lost the trace data for, this is an out of bound error (right overflow for charCodeAt
), which happens only now and then (I guess it depends on the input data provided). When it happens parse
kinda doubles the runtime from ~120 ms to ~250 ms. Should be easy to fix.
Details
- Browser and browser version: chrome v65 & electron v58
- OS version: linux
- xterm.js version: master
Steps to reproduce
- Run
chrome --js-flags="--trace-opt --trace-deopt --trace"
with the demo - dig through the trace output
Issue Analytics
- State:
- Created 5 years ago
- Reactions:1
- Comments:5 (5 by maintainers)
Top GitHub Comments
Oh well didnt know that ‘y’ feature, thought the line click is always commit aware. Gonna change the links.
I think @jerch has covered most of these and we’re always wary when new things come in. Reopen if it needs more