thlorenz / deoptigate

⏱️ Investigates v8/Node.js function deoptimizations.
https://nodesource.github.io/deoptigate-examples/xml2js/01_start/?selectedFileIdx=31&selectedLocation=157&includeAllSeverities=false&highlightCode=true&selectedTabIdx=1&selectedSummaryTabIdx=1
MIT License
1.16k stars 22 forks source link

Insufficient type feedback for call deoptimization #2

Open schermannj opened 6 years ago

schermannj commented 6 years ago

Hello,

I was playing with your tool and found that you mark soft deopts with Severity 1 and eager - Severity 3. And as I understand you consider Severity 1 as something acceptable.

I have this piece of code:

const pair = (x, y) => ({ x, y });

const add = (p1, p2) => pair(p1.x + p2.x, p1.y + p2.y);

const ITER = 1E3;

for (let i = 0; i < ITER; i++) {
  for (let j = 0; j < ITER; j++) {
    add(pair(i, j), pair(1, 1));
  }
}

add({ y: 10, x: 412 }, pair(1, 1));

It produces next deopts:

code-deopt,90721,2432,0x30a9606af80,-1,305,soft,<F:\projects\ic\ic-check.js:13:1>,Insufficient type feedback for call
code-deopt,90766,1056,0x30a9606ab60,-1,78,eager,<F:\projects\ic\ic-check.js:1:79>,wrong map

Even if I replace the last line in my code with

add(pair(2, 2), pair(1, 1));

I'm still getting the 1st soft deoptimization.

I understand why I have the second deopt. But maybe you could explain something about the first one?

thlorenz commented 6 years ago

Hey, thanks for playing around with this new tool :)

deoptigate only visualizes the data, but V8 is making the decisions about (de)optimizations and so on. soft deopts happen all the time and are not a problem and is nothing to worry about. They just happen if V8 optimizes too soon and didn't collect enough feedback to generate code for all the use cases (hence the Insufficient type feedback message).

If you have more questions about that I recommend asking in a V8 group or similar. Hope this helps and if you got no more questions please close the issue :)

LeszekSwirski commented 6 years ago

Call ICs are collected at the call site, and soft deopts happen when we never managed to collect any feedback at all for a particular code path. Because the loops have so many iterations, optimization is triggered during the loop execution ("on-stack replacement", a.k.a. OSR), which means that feedback-collecting interpreter execution never reaches line 13 before optimization happens, and so no call feedback is collected for that add (or pair) call. As a result, there is a soft deopt once that call is reached (for the first time).

You might be wondering "why not reuse the call IC for the add function we had before" -- it's because a) call ICs also store invocation count at that call-site so that we know where the function is hot enough to inline, and b) for all we know someone could change the "add" variable at some point between the loop call and the line 13 call.

thlorenz commented 6 years ago

Thanks for the details @LeszekSwirski. Gonna keep this open so others can find that info.

Wondering if we should start a FAQ, i.e. in a Wiki to have that info in one place. Could make that accessible via a link from the app.

I also remember that IRHydra had some of these explanations built in, i.e. via hover, so maybe we could add this to deoptigate as well :)

Thoughts?

schermannj commented 6 years ago

Thank you @thlorenz and @LeszekSwirski, that's good to know.

@thlorenz yeah, it would be great to see this/similar info somewhere in popups on the deoptigate page. FAQ page is a good idea too if you have something extra to add. With only one question/answer it won't look cool ;)