Skip to content
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

lib: improve error creation performance #24747

Closed
wants to merge 2 commits into from

Conversation

BridgeAR
Copy link
Member

In case of an error where we only care about a cleaned up stack
trace it is cheaper to reset the stack trace limit for the error
that is created. That way the stack frames do not have to be
computed twice.
In a local mini benchmark it reduced the Error creation time by around
30 %.

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • documentation is changed or added
  • commit message follows commit guidelines

In case of an error where we only care about a cleaned up stack
trace it is cheaper to reset the stack trace limit for the error
that is created. That way the stack frames do not have to be
computed twice.
@nodejs-github-bot nodejs-github-bot added errors Issues and PRs related to JavaScript errors originated in Node.js core. fs Issues and PRs related to the fs subsystem / file system. http Issues or PRs related to the http subsystem. process Issues and PRs related to the process subsystem. labels Nov 30, 2018
Copy link
Member

@addaleax addaleax left a comment

Choose a reason for hiding this comment

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

Would it make sense to abstract this into a helper function?

lib/_http_outgoing.js Outdated Show resolved Hide resolved
@targos
Copy link
Member

targos commented Nov 30, 2018

Do you think V8 could help with this?

Co-Authored-By: BridgeAR <[email protected]>
@BridgeAR
Copy link
Member Author

@addaleax

Would it make sense to abstract this into a helper function?

I thought about that and the reason why I did not yet do that is that we have very different signatures and we can prevent resetting the numbers in some cases. If we use this pattern more commonly, we could write something like this:

function assertSize(size) {
  errors.removeFramesFrom(assertSize);

  if (typeof size !== 'number') {
    throw new ERR_INVALID_ARG_TYPE('size', 'number', size);
  }
  if (size < 0 || size > kMaxLength) {
    throw new ERR_INVALID_OPT_VALUE.RangeError('size', size);
  }
  errors.resetFrames();
}

That way the internal errors could take care of it.

@targos

Do you think V8 could help with this?

I spoke with @hashseed about this but so far there was no real conclusion (but two issues). I personally would love to get a completely new API that would allow to reduce the code overhead and potentially allow further optimizations in V8.

Example API
function assertSize(size) {
  let err = null;

  if (typeof size !== 'number') {
    err = new ERR_INVALID_ARG_TYPE('size', 'number', size);
  } else if (size < 0 || size > kMaxLength) {
    err = new ERR_INVALID_OPT_VALUE.RangeError('size', size);
  }

  if (err !== null) {
    Error.captureStackTrace(err, assertSize);
    throw err;
  }
}

// If this would instead be written similar to: 

function assertSize(size) {
  Error.dontSetLowerStackFrames();

  if (typeof size !== 'number') {
    throw new ERR_INVALID_ARG_TYPE('size', 'number', size);
  } else if (size < 0 || size > kMaxLength) {
    throw new ERR_INVALID_OPT_VALUE.RangeError('size', size);
  }
}

// Pass the message to the constructor instead of setting it on the object
// to make sure it is the same as the one created in C++
// eslint-disable-next-line no-restricted-syntax
const err = new Error(message);
Error.stackTraceLimit = tmpLimit;
Copy link
Member

@jdalton jdalton Nov 30, 2018

Choose a reason for hiding this comment

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

This seems like something V8 folks should be made aware of since, in this case, the lazily populated .stack isn't even being accessed yet. The fact that setting the Error.stackTraceLimit to 0 appears to improves basic error creation performance when the .stack isn't accessed is counterintuitive at least.

I'd rather this be tracked as a V8 issue and fixed there than throwing Error.stackTraceLimit = 0 all over the Node codebase.

Copy link
Member Author

Choose a reason for hiding this comment

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

As mentioned above, I already did that :)

Copy link
Member

Choose a reason for hiding this comment

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

Yes, but the V8 issues mentioned above

  • 8451 – loading Error.stackTraceLimit could be done faster:

    We load Error.stackTraceLimit every time we collect a stack trace. Maybe this is something we want to improve? See https://docs.google.com/document/d/1wwigvXVQ-mdLmSfNnLie2xVQGCt-6AKhP1OuyE38Vw8/edit

  • 8452 – Faster stack traces:

    Stack traces are not used a lot in benchmarks, but often on real web sites for telemetry purposes. Some Node.js frameworks also use it to implement async stack traces. We could use better performance for stack trace collection in general

don't clearly state this specific case though.

Copy link
Member Author

Choose a reason for hiding this comment

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

I opened another issue to properly address this: https://bugs.chromium.org/p/v8/issues/detail?id=8555

Copy link
Member

@jdalton jdalton left a comment

Choose a reason for hiding this comment

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

I'd like to hold off on this PR. If, once the issue has been properly raised with the V8 team, there is no movement then this PR can progress as a kind of last resort.

Copy link
Contributor

@Fishrock123 Fishrock123 left a comment

Choose a reason for hiding this comment

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

This seems reasonable to me.

I think V8 was supposed to make stacktrace gathering faster but, who knows when.

We could add some // on V8 version comments I guess

@BridgeAR
Copy link
Member Author

BridgeAR commented Dec 2, 2018

I also doubt that stack traces will be fast soon. As soon as that's done, removing these should not be an issue.

I do not have a strong opinion about this PR as it's only about error cases but I don't think that adding this hurts in any way.

What I could try is to implement my suggestion (#24747 (comment)) instead as it's cleaner code, if requested.

@jdalton
Copy link
Member

jdalton commented Dec 2, 2018

Just in case it got lost in the replies, my comment #24747 (comment) has not been addressed.

@hashseed
Copy link
Member

hashseed commented Dec 2, 2018

I also doubt that stack traces will be fast soon.

Can confirm. We have plans, but won't be able to do any time soon.

@BridgeAR
Copy link
Member Author

BridgeAR commented Dec 6, 2018

Ping @jdalton

@BridgeAR
Copy link
Member Author

BridgeAR commented Dec 8, 2018

@BridgeAR BridgeAR added the author ready PRs that have at least one approval, no pending requests for changes, and a CI started. label Dec 8, 2018
@Trott
Copy link
Member

Trott commented Dec 8, 2018

Given the failures of test-cli-syntax on multiple hosts, I'm going to do a Rebuild rather than a Resume CI so it rebases and gets a recent commit that hopefully makes that failure less frequent:

https://ci.nodejs.org/job/node-test-pull-request/19333/

@Trott
Copy link
Member

Trott commented Dec 9, 2018

Resume Build CI: https://ci.nodejs.org/job/node-test-pull-request/19340/ ✔️

@Trott
Copy link
Member

Trott commented Dec 9, 2018

Landed in a1a5c04

@Trott Trott closed this Dec 9, 2018
Trott pushed a commit to Trott/io.js that referenced this pull request Dec 9, 2018
In case of an error where we only care about a cleaned up stack
trace it is cheaper to reset the stack trace limit for the error
that is created. That way the stack frames do not have to be
computed twice.

PR-URL: nodejs#24747
Reviewed-By: Anna Henningsen <[email protected]>
Reviewed-By: Jeremiah Senkpiel <[email protected]>
BethGriggs pushed a commit that referenced this pull request Dec 17, 2018
In case of an error where we only care about a cleaned up stack
trace it is cheaper to reset the stack trace limit for the error
that is created. That way the stack frames do not have to be
computed twice.

PR-URL: #24747
Reviewed-By: Anna Henningsen <[email protected]>
Reviewed-By: Jeremiah Senkpiel <[email protected]>
@BethGriggs BethGriggs mentioned this pull request Dec 18, 2018
@BridgeAR BridgeAR added the performance Issues and PRs related to the performance of Node.js. label Dec 23, 2018
refack pushed a commit to refack/node that referenced this pull request Jan 14, 2019
In case of an error where we only care about a cleaned up stack
trace it is cheaper to reset the stack trace limit for the error
that is created. That way the stack frames do not have to be
computed twice.

PR-URL: nodejs#24747
Reviewed-By: Anna Henningsen <[email protected]>
Reviewed-By: Jeremiah Senkpiel <[email protected]>
@BridgeAR BridgeAR deleted the faster-errors branch January 20, 2020 11:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
author ready PRs that have at least one approval, no pending requests for changes, and a CI started. errors Issues and PRs related to JavaScript errors originated in Node.js core. fs Issues and PRs related to the fs subsystem / file system. http Issues or PRs related to the http subsystem. performance Issues and PRs related to the performance of Node.js. process Issues and PRs related to the process subsystem.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants