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

timers: improve setImmediate() performance #8655

Merged
merged 1 commit into from
Oct 5, 2016

Conversation

mscdex
Copy link
Contributor

@mscdex mscdex commented Sep 19, 2016

Checklist
  • make -j4 test (UNIX), or vcbuild test nosign (Windows) passes
  • commit message follows commit guidelines
Affected core subsystem(s)
  • timers
Description of change

This commit avoids re-creating a new immediate queue object every time the immediate queue is processed. Additionally, a few functions are tweaked to make them inlineable.

These changes result in ~6-7% improvement in the existing setImmediate() benchmarks and should help reduce GC work.

@nodejs-github-bot nodejs-github-bot added the timers Issues and PRs related to the timers subsystem / setImmediate, setInterval, setTimeout. label Sep 19, 2016


function processImmediate() {
const queue = immediateQueue;
var domain, immediate;
var p = immediateQueue.head;
Copy link
Contributor

@Fishrock123 Fishrock123 Sep 19, 2016

Choose a reason for hiding this comment

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

p is poorly named

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed to ptr. Is that sufficient?

Copy link
Contributor

Choose a reason for hiding this comment

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

why not just keep it as immediate?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

@mscdex mscdex force-pushed the timers-improve-immediate-perf branch from 5f4c590 to a284f41 Compare September 19, 2016 17:59
@mscdex
Copy link
Contributor Author

mscdex commented Sep 19, 2016

@mscdex mscdex force-pushed the timers-improve-immediate-perf branch from a284f41 to dcc9fe0 Compare September 19, 2016 23:04
@mscdex
Copy link
Contributor Author

mscdex commented Sep 19, 2016

I've now tweaked a few of the functions used by setImmediate() and others to be inlineable, which gives another ~3% boost in performance, upping the improvement to ~6-7%.

@mscdex
Copy link
Contributor Author

mscdex commented Sep 19, 2016

@@ -45,6 +45,21 @@ function setupPromises(scheduleMicrotasks) {
}
}

function emitWarning() {
const warning = new Error('Unhandled promise rejection ' +
`(rejection id: ${uid}): ${reason}`);
Copy link
Member

@richardlau richardlau Sep 20, 2016

Choose a reason for hiding this comment

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

uid and reason not defined here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

@mscdex mscdex force-pushed the timers-improve-immediate-perf branch from dcc9fe0 to e66340a Compare September 20, 2016 06:25
@mscdex
Copy link
Contributor Author

mscdex commented Sep 20, 2016

'Node.js process with a non-zero exit code.',
'DeprecationWarning');
}
emitWarning(uid, reason);
Copy link
Contributor

Choose a reason for hiding this comment

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

@mscdex err, why is this included?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

To allow for more inlining. emitPendingUnhandledRejections() is used by setImmediate().

Copy link
Member

@jasnell jasnell left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Member

@imyller imyller left a comment

Choose a reason for hiding this comment

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

LGTM

@jasnell
Copy link
Member

jasnell commented Sep 27, 2016

ping @Fishrock123 ... does this LGTY?

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.

Functionality LGTM, I'd like some commenting around the new linkedlist stuff personally, I find them notoriously hard to read / understand and I doubt I am alone.

OK otherwise if CI passes.


immediateQueue = L.create();
immediateQueue.head = immediateQueue.tail = null;
Copy link
Contributor

Choose a reason for hiding this comment

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

a comment would be helpful

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What did you have in mind? To me it's self-explanatory, it's effectively clearing the linked list.

Copy link
Contributor

Choose a reason for hiding this comment

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

I know what it does, I think it just may look strange to someone else encountering it.

immediateQueue.head = next;
} else {
immediateQueue.head = next;
immediateQueue.tail = oldTail;
Copy link
Contributor

Choose a reason for hiding this comment

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

Can this be a helper fn?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What do you mean?

this.head = item;
}
this.tail = item;
};
Copy link
Contributor

Choose a reason for hiding this comment

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

I probably should specify: comments on how these two modify their respective properties

@mscdex mscdex force-pushed the timers-improve-immediate-perf branch from e66340a to 67f1a2a Compare September 29, 2016 08:15
@mscdex
Copy link
Contributor Author

mscdex commented Sep 29, 2016

@Fishrock123 Comments added, let me know if they are sufficient.

@mscdex
Copy link
Contributor Author

mscdex commented Oct 5, 2016

ping @Fishrock123

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.

lgtm

@mscdex
Copy link
Contributor Author

mscdex commented Oct 5, 2016

CI before landing: https://ci.nodejs.org/job/node-test-pull-request/4389/

EDIT: checking again after rebasing just to be sure flakiness is unrelated: https://ci.nodejs.org/job/node-test-commit/5451/

@mscdex mscdex force-pushed the timers-improve-immediate-perf branch from 67f1a2a to 1bb9048 Compare October 5, 2016 06:43
This commit avoids re-creating a new immediate queue object every
time the immediate queue is processed. Additionally, a few functions
are tweaked to make them inlineable.

These changes give ~6-7% boost in setImmediate() performance in the
existing setImmediate() benchmarks.

PR-URL: nodejs#8655
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Ilkka Myller <ilkka.myller@nodefield.com>
Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
@mscdex mscdex force-pushed the timers-improve-immediate-perf branch from 1bb9048 to 0ed8839 Compare October 5, 2016 07:11
@mscdex mscdex merged commit 0ed8839 into nodejs:master Oct 5, 2016
@mscdex mscdex deleted the timers-improve-immediate-perf branch October 5, 2016 07:13
jasnell pushed a commit that referenced this pull request Oct 6, 2016
This commit avoids re-creating a new immediate queue object every
time the immediate queue is processed. Additionally, a few functions
are tweaked to make them inlineable.

These changes give ~6-7% boost in setImmediate() performance in the
existing setImmediate() benchmarks.

PR-URL: #8655
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Ilkka Myller <ilkka.myller@nodefield.com>
Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
@MylesBorins
Copy link
Contributor

adding to lts watch but unsure if this should land. Will definitely need time to sit in a release for a while

/cc @mscdex

Fishrock123 pushed a commit that referenced this pull request Oct 11, 2016
This commit avoids re-creating a new immediate queue object every
time the immediate queue is processed. Additionally, a few functions
are tweaked to make them inlineable.

These changes give ~6-7% boost in setImmediate() performance in the
existing setImmediate() benchmarks.

PR-URL: #8655
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Ilkka Myller <ilkka.myller@nodefield.com>
Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>

 Conflicts:
	lib/internal/process/promises.js
@ErisDS
Copy link

ErisDS commented Oct 13, 2016

Hey there!

We started having test failures due to this change. There's more information on the issue & PR linked just above this comment. To pull some of that here:

The last job never get's executed, because setImmediate does not get triggered!

We have a temporary fix in place in the PR, that reduces the timeout and this appears to work (the tests pass). Would love a little bit of input into how this change has impacted the functionality and whether we've found a bug or are doing something wrong :)

@MylesBorins
Copy link
Contributor

/cc @nodejs/ctc

@Trott
Copy link
Member

Trott commented Oct 13, 2016

@ErisDS I don't suppose you have a minimal test that could be used to demonstrate the immediate running in v6.7.0 and not running in v6.8.0, do you? I'm guessing not because you probably would have mentioned it, but I'm having trouble replicating the problem, probably because I am Doing Something Wrong.

@kirrg001
Copy link

@Trott i will provide an example file asap

@kirrg001
Copy link

kirrg001 commented Oct 13, 2016

var jobs = [Date.now() + 1000, Date.now() + 2000, Date.now() + 3000];

jobs.forEach(function(timestamp) {
    var timeout = setTimeout(function() {
        clearTimeout(timeout);

        (function retry() {
            var immediate = setImmediate(function() {
                clearImmediate(immediate);

                if (Date.now() < timestamp) {
                    return retry();
                }

                console.log("FINISHED JOB");
            });
        }());
    }, timestamp - 200);
});

v6.8.0 - does not work, you will see 1 x FINISHED JOB
v4.4.7 && v6.7.0 - works as expected, you will see 3 x FINISHED JOB

@Fishrock123
Copy link
Contributor

Fishrock123 commented Oct 13, 2016

Moving to a new issue so we can help you better: #9084

please put all comments in that thread rather than here

@nodejs nodejs locked and limited conversation to collaborators Oct 13, 2016
@nodejs nodejs unlocked this conversation Oct 13, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
timers Issues and PRs related to the timers subsystem / setImmediate, setInterval, setTimeout.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants