New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"Not optimized" JavaScript profiler bailout reasons #53

Open
paulirish opened this Issue Jan 17, 2014 · 41 comments

Comments

Projects
None yet
@paulirish
Member

paulirish commented Jan 17, 2014

Edit (sept 2015): This issue is the living documentation for the deopt & bailout reasons provided by Chrome DevTools and the V8 sampling profiler.

image

Should I care?

A deopt warning is important to consider if:

  • You've profiled a slow interaction
  • When viewing a Costly Functions / bottom-up / Heavy report of all operations, sorted by self-time, the function is towards the top
  • The function has significant self-time. Fixing the deopt will reduce the self-time of this particular function.

What is a deopt?

The optimizing compiler makes for very fast execution, but functions are not always optimized, and it depends on a number of indicators. First, there's four types of function optimization state:

  1. Optimized: V8 has identified this function is hot (runs a lot) and has run it through the optimizing compiler so execution is faster.
  2. Unoptimized: The function was not identified by V8 to be worth optimizing.
  3. Deoptimized (bailout): V8 wanted to optimize this function, but before executing it, the optimizing compiler refused to optimize because it uses some unsupported Javascript feature (e.g. try/catch, for of, or with()) or hits certain limitations.
  4. Deoptimized (deopt): V8 wanted to optimize this function, and did successfully send it through the optimizing compiler. However, this already optimized code runs into a situation it did not foresee and cannot handle. (for example: using a negative array key, or a unexpected variable type). V8 then throws away the optimized code, falls back to unoptimized code and tries again later with more information.

These warnings in DevTools will be shown for both 3 and 4.

These deopt affect only that function, and not its children. For example, try/catch is one of the most common warnings. You can address the concern by using a separate function for the body of the try{} block:

These deopt rules change frequency, so always profile before following these rules arbitrarily across your codebase. In try/catch's case, V8's upcoming Turbofan compiler will optimize code that includes a try/catch block. Turbofan is expected to land in Chrome 48.

Related items:

What do each of the reasons mean?

Read the comments below.

@kangax

This comment has been minimized.

kangax commented Jan 19, 2014

Want this as well; chiming in for updates.

@kangax

This comment has been minimized.

kangax commented Jan 20, 2014

"Not optimized: Inlining bailed out"

Example

var obj = { prop1: ..., prop2: ... };

function f(obj) {
  obj.someOtherProp = ...;
}
f(obj);

or:

function someMethodThatAssignsSomeOtherProp(obj) {
  obj.someOtherProp = ...;
}
function f(obj) {
  someMethodThatAssignsSomeOtherProp(obj);
}
f(obj);

Possible fix

var obj = { prop1: ..., prop2: ..., someOtherProp: ... };
f(obj);

More on hidden classes.

@kangax

This comment has been minimized.

kangax commented Jan 20, 2014

What: "Not optimized: ForInStatement is not fast case"

Example

for (var prop in obj) {
  /* lots of code */
}

Possible fix

function f() {
  /* lots of code */
}
for (var prop in obj) {
  f();
}
@kangax

This comment has been minimized.

kangax commented Jan 20, 2014

"Not optimized: Bad value context for arguments value"

Example: ?

Possible fix: ?

@kangax

This comment has been minimized.

kangax commented Jan 20, 2014

(just pasting some notes; perhaps will come in useful)

@paulirish

This comment has been minimized.

Member

paulirish commented Jan 20, 2014

very useful. thank you sir.

@kangax

This comment has been minimized.

kangax commented Jan 20, 2014

"Not optimized: Optimized too many times"

Example: ?

Possible fix: ?

kOptimizedTooManyTimes

@paulirish

This comment has been minimized.

Member

paulirish commented Mar 11, 2014

"Not optimized: Reference to a variable which requires dynamic lookup"

We bailout during optimization when there are variables for which lookup at compile time fails, and we need to resort to dynamic lookup at runtime.

Example

function f() {
  with ({x:1}) {
    return x;
  }
}

possible fix: refactor to remove the dependency on runtime-information to resolve the lookup.

mailing list thread with more discussion: https://groups.google.com/forum/#!msg/google-chrome-developer-tools/Y0J2XQ9iiqU/H60qqZNlQa8J

General bailout reason explanation.

V8 will not try to optimize functions with some constructs, try/catch block is one example, the full list may change over time as the engine evolves. It can also give up if it tries to optimize and then has to deoptimize some hot function too many times (e.g. because of the type feedback being different each time the function executes). Also you should pass --trace-opt flag in addition to --trace-deopt to see bailout reason when V8 fails to optimize a function.

see link for more

@octatone

This comment has been minimized.

octatone commented Mar 17, 2014

"Not optimized: assignment to parameter in arguments object"

This is likely either of:

(function() {
  arguments[0] = ...;
})();

// or

(function(foo, bar) {
  foo = ...
})();
@Lukenickerson

This comment has been minimized.

@Trott Trott referenced this issue May 11, 2014

Closed

optimize #44

@twokul

This comment has been minimized.

twokul commented Aug 12, 2014

"Not optimized: Bad value context for arguments value"

Example:

function f1() {
  return arguments;
}

function f2() {
  var args = [].slice.call(arguments);
}

function f3() {
    arguments = 3;
    return arguments;
}

Possible fix:

function f3(fn) {
  var args = new Array(arguments.length);
  for (var i = 0, l = arguments.length; i < l; i++) {
    args[i] = arguments[i];
  }
  return fn.apply(this, args);
}

Updated per @WebReflection's comment.

@WebReflection

This comment has been minimized.

WebReflection commented Aug 12, 2014

@twokul the first parameter for .apply is the context, not the arguments neither an array … I think you are passing arguments as context instead.

@twokul

This comment has been minimized.

twokul commented Aug 12, 2014

Also, I think "Not optimized: Inlining bailed out" might be caused by a completely different bailout. Fox example, the function won't be inlined if the function that is called inside bails out. Cascading bailout?

@twokul

This comment has been minimized.

twokul commented Aug 12, 2014

@WebReflection good catch!

@WebReflection

This comment has been minimized.

WebReflection commented Aug 12, 2014

then in f3 case you should have full speed without needing to recreate the args to apply as described in this thread: https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#what-is-safe-arguments-usage

the STRICTLY .apply part in special

@cedricpinson

This comment has been minimized.

cedricpinson commented Jan 6, 2015

I have also the problem about the
'Not optimized: Optimized too many times'
that would be great to have reason or some hints when the compiler reject those optimization

@paulirish paulirish changed the title from JavaScript profiler bailout reasons to "Not optimized" JavaScript profiler bailout reasons Jan 27, 2015

@paulirish

This comment has been minimized.

Member

paulirish commented Mar 25, 2015

We've landed a bunch of patches recently to expose deopt reasons:
https://code.google.com/p/chromium/issues/detail?id=452067#c19
It's not done yet, but I'll ping this thread when there's something to try out.

@acthp

This comment has been minimized.

acthp commented Jun 1, 2015

I can't make sense of the "Not optimized: Inlining bailed out" examples. A function f is defined that adds a property to an obj, and is then called with no args? So it throws on "cannot set property of undefined"? Fix is to.. what? Not define the function and then call it, so it throws on "undefined is not a function"? The example is extremely unclear.

@kangax

This comment has been minimized.

kangax commented Jun 1, 2015

@acthp you're right, I made a mistake in my example (mind you, this is simply my assumption about the error — I haven't worked on a profiler, I don't know the actual meaning behind these messages). Updated/fixed example. The point is not to modify object at runtime. So instead of assigning property dynamically, a property would be created initially as part of an object literal. Of course this might not always be possibly but... that's besides the point.

@acthp

This comment has been minimized.

acthp commented Jun 2, 2015

Hm... if that's the case, I wonder if initializing the property to undefined would help.

@govo

This comment has been minimized.

govo commented Aug 7, 2015

"Not optimized:Yield"

The yield keyword is used in the function body.

@kdzwinel

This comment has been minimized.

Member

kdzwinel commented Sep 12, 2015

IMO "optimized too many times" means that function was optimized multiple times with wrong assumptions (both args are int! first is string the other is int? both are string?! I give up...). Check if types and order of params you pass to that function is always the same.

@WebReflection

This comment has been minimized.

WebReflection commented Sep 12, 2015

@kdzwinel so you are saying a script language shouldn't have overloads like most common strict languages? wouldn't that be somehow hilarious :-) I'd rather like to know the eventual maximum amount of overloads can be optimized before "giving up", there are already so many native methods and functions in JS that accepts different amount of parameters with different kind of types, I don't think developers should avoid creating nice APIs because of this. just my 2 cents

@skybrian

This comment has been minimized.

skybrian commented Sep 12, 2015

Knowing which variables aren't type-stable is useful for optimizing heavily-used inner loops. When performance doesn't really matter, you're probably not even looking at that function in the profiler in the first place.

@kdzwinel

This comment has been minimized.

Member

kdzwinel commented Sep 14, 2015

@WebReflection you sure can have polymorphic functions, they won't be as optimized an monomorphic ones. Which, in most cases, is OK.

After reading this article my guess is that "optimized too many times" warning is emitted not when V8 figures out that function is polymorphic, but when it figures out that it's megamorphic (see this summary).

If you need a definite answer, I suggest asking @mraleph.

@mraleph

This comment has been minimized.

mraleph commented Sep 14, 2015

When talking about optimizations it's more polymorphism of each individual operation inside the function is more relevant than polymorphism of the function (that's why my blog post always talks about operations, call sites - not functions).

optimized too many times means only one thing - precisely what it says: V8 (re)optimized this function many times and eventually gave up.

In reality this very often actually means a bug in V8 - there is some optimization which is too optimistic so the generated code deopts all the time.

Just use IRHydra and look at the deoptimization reasons - the picture should become clear immediately.

Megamorphism of some operation is not the reason to not optimize the function - you can just emit an IC call there instead of specializing the operation.

@kdzwinel

This comment has been minimized.

Member

kdzwinel commented Sep 14, 2015

@mraleph thanks for an explanation! Now it makes much more sense, hopefully we will get that documented.

Since "optimized too many times" suggests a V8 bug, should we consider reporting it when we run into this warning? If so, should it be reported to https://code.google.com/p/v8/ or crbug.com ?

@mraleph

This comment has been minimized.

mraleph commented Sep 14, 2015

@kdzwinel "Often" does not mean "always". I recommend actually investigating what happens, confirming that it looks like a bug and then filing a bug (with a repro) at V8's bugtracker.

@spite

This comment has been minimized.

spite commented Oct 17, 2016

"Not optimized: Unsupported phi use of const or let variable"?

@vhf

This comment has been minimized.

vhf commented Oct 17, 2016

@spite I don't have an explanation yet but I added a rather minimal reproduction. (And here is a test on various recent node versions.)

@kdzwinel

This comment has been minimized.

Member

kdzwinel commented Oct 17, 2016

@spite here is the code responsible for throwing this warning

bool HGraph::CheckConstPhiUses() {
  int block_count = blocks_.length();
  for (int i = 0; i < block_count; ++i) {
    for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
      HPhi* phi = blocks_[i]->phis()->at(j);
      // Check for the hole value (from an uninitialized const).
      for (int k = 0; k < phi->OperandCount(); k++) {
        if (phi->OperandAt(k) == GetConstantHole()) return false;
      }
    }
  }
  return true;
}

@mraleph should be able to help explaining it (as always!)

@billhance

This comment has been minimized.

billhance commented Dec 9, 2016

I came across the same "Not optimized: Unsupported phi use of const or let variable" bug as @spite and unsure of why exactly. Opened a pr here vhf/v8-bailout-reasons#10 with details.

@vsemozhetbyt

This comment has been minimized.

vsemozhetbyt commented Jan 29, 2017

@paolocaminiti
I've tried to reduce your case. It seems we have found out something interesting.
See vhf/v8-bailout-reasons#13

t-mw added a commit to t-mw/lua.vm.js that referenced this issue Feb 13, 2017

lencioni added a commit to lencioni/aphrodite that referenced this issue Mar 5, 2017

Avoid deoptimization in generateCSS()
I was profiling the css() function and Chrome raised a flag on this
function:

> Not optimized: Bad value context for arguments value

More info on this warning:
GoogleChrome/devtools-docs#53 (comment)

Looking at the warning and the compiled version of this code, it seems
to do some things with `arguments` when using the default values
here, which is causing this deoptimization.

```js
var selectorHandlers = arguments.length <= 2 || arguments[2] === undefined ? [] : arguments[2];
var stringHandlers = arguments.length <= 3 || arguments[3] === undefined ? {} : arguments[3];
var useImportant = arguments.length <= 4 || arguments[4] === undefined ? true : arguments[4];
```

By removing the default values for the arguments, the deoptimization
disappears. I thought about adding logic that would provide values for
these arguments if they aren't defined, but since the only thing that
relies on that is tests I decided to just update the tests to always
pass all of the arguments.

In my benchmark, this does not seem to make much of a difference but it
still seems like a good idea to avoid things that the browser tells us
is deoptimized.

xymostech added a commit to Khan/aphrodite that referenced this issue Mar 6, 2017

Avoid deoptimization in generateCSS() (#204)
I was profiling the css() function and Chrome raised a flag on this
function:

> Not optimized: Bad value context for arguments value

More info on this warning:
GoogleChrome/devtools-docs#53 (comment)

Looking at the warning and the compiled version of this code, it seems
to do some things with `arguments` when using the default values
here, which is causing this deoptimization.

```js
var selectorHandlers = arguments.length <= 2 || arguments[2] === undefined ? [] : arguments[2];
var stringHandlers = arguments.length <= 3 || arguments[3] === undefined ? {} : arguments[3];
var useImportant = arguments.length <= 4 || arguments[4] === undefined ? true : arguments[4];
```

By removing the default values for the arguments, the deoptimization
disappears. I thought about adding logic that would provide values for
these arguments if they aren't defined, but since the only thing that
relies on that is tests I decided to just update the tests to always
pass all of the arguments.

In my benchmark, this does not seem to make much of a difference but it
still seems like a good idea to avoid things that the browser tells us
is deoptimized.
@jimbojw

This comment has been minimized.

jimbojw commented May 10, 2017

Unsupported let compound assignment

For anyone trying to decode this bailout reason, here's an example:

function example() {
  let x = 0;
  x += 1; // Causes the deopt.
}

Notably, the increment operator ++ does not cause deopt, nor does the following:

function example() {
  let x = 0;
  x = x + 1; // Does NOT cause deopt.
}

Previously, I had interpreted the term compound assignment to mean multiple assignment statements, comma separated, after the same leading let. E.g.

function example() {
  let x = 0, y = 0; // Does NOT cause deopt.
  let a = 0, b = a + x + y; // Does NOT cause deopt.
}

I have not been able to construe a way to trigger the related bailout reason "Unsupported const compound assignment". Given that const variables can't be reassigned, and that "Unsupported let compound assignment" is triggered by post-declaration assignment operators like +=, I'm skeptical that it's possible to trigger this bailout reason at all.

http://stackoverflow.com/questions/34595356/what-does-compound-let-const-assignment-mean

EDIT

"Unsupported const compound assignment" has been removed from V8 as far as I can tell.

@wtfrank

This comment has been minimized.

wtfrank commented Jul 31, 2017

Not optimized: TryCatchStatement

Its worth pointing out that in older versions of v8 (e.g. 5.1.281.83) TryCatchStatement seems to be also triggered by functions with no try/catch but a "for...of" construction

filipesilva added a commit to filipesilva/webpack that referenced this issue Aug 29, 2017

fix: replace for..of to prevent v8 deoptimization
According to GoogleChrome/devtools-docs#53 (comment), use of `for...of` statements will cause a deopt in some versions of v8.

In a my particular case these two changes reduced 1.6 seconds in a big rebuild.

filipesilva added a commit to filipesilva/webpack that referenced this issue Aug 29, 2017

fix: replace for..of to prevent v8 deoptimization
According to GoogleChrome/devtools-docs#53 (comment), use of `for...of` statements will cause a deopt in some versions of v8.

In a my particular case these two changes reduced 1.6 seconds in a big rebuild.

@earlymeme earlymeme referenced this issue Nov 20, 2018

Closed

书签 #13

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment