-
Notifications
You must be signed in to change notification settings - Fork 29.6k
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: replace _linklist with ES6 Sets #2973
Conversation
a0027b6
to
9fe8754
Compare
cc @Fishrock123 |
Aren't sets a better replacement for Freelist or something? There are some specific performance and memory related reasons for which we use linked lists. Timers is one of those, since the number of timers can be very large. Also, linked list operations are very speedy. Cc @bnoordhuis |
I spotted three instances of for/of that prevent crankshaft optimization, although in two instances it doesn't really matter because of the try/catch statements in the same function. As to using Sets vs. a linked list, I can see it going either way. Linked list insertion/deletion is theoretically a constant O(1) but because Sets in V8 are basically hashmaps, with O(1) amortized performance. Amortized is worse than constant but because Set methods don't do property lookups, they don't turn megamorphic. |
Awesome, thanks @bnoordhuis and @Fishrock123. I'll keep experimenting and see if anything good comes of it. |
@Trott Atm, usage of It looks to me that removing it is safe. Well, as long as it gives us an improvent. |
@bnoordhuis wouldn't it be faster to have separate copies of all functions per each type then? |
@vkurchatkin Yes, but that basically means open-coding the functions everywhere you use them. You could eval() code (or rather, |
Well, we can require _linklist and then erase it from cache. It seems like less of a hack |
Oh, like that. Yes, that would amount to the same thing. It wouldn't help much for objects that users can modify, though. E.g. |
5c0816e
to
5ca4154
Compare
@bnoordhuis Do I need to worry about Disclaimer: I don't actually know what I'm talking about. I just read http://blog.chromium.org/2015/07/revving-up-javascript-performance-with.html |
Eventually, yes, but TF is not the default yet and I don't know when it will be. |
07d6847
to
4ee7370
Compare
Wouldn't it be easier to immediately resolve the time to its epoch offset (e.g. Anyway. Benchmarks have shown me that Maps and Sets are amazing for random access, but as soon as they need to be transversed you're in trouble. This implementation is clean, but also will suffer a performance hit because of needing to transverse the data. |
4ee7370
to
d8dbbeb
Compare
a2d892e
to
4510314
Compare
Updated list is here! Expression: ape-algorithm-0.0.8.tgz/linklist.js:2://var L = require('_linklist');
biojs-vis-blast-0.1.5.tgz/node/lib/timers.js:23:var L = require('_linklist');
biojs-vis-blast-0.1.5.tgz/node/test/simple/test-timers-linked-list.js:24:var L = require('_linklist');
candle-0.4.0.tgz/timers.js:23:var L = require('_linklist');
chromify-0.0.2.tgz/builtins/timers.js:23:var L = require('_linklist');
commonjs-everywhere-0.9.7.tgz/node/lib/timers.js:23:var L = require('_linklist');
flush-all-0.1.1.tgz/node-v0.13/lib/timers.js:25:var L = require('_linklist');
flush-all-0.1.1.tgz/node-v0.13/test/simple/test-timers-linked-list.js:24:var L = require('_linklist');
jsg-0.0.3.tgz/testdata/node_core_modules/timers.js:23:var L = require('_linklist');
micropromise-0.4.10.tgz/promise-bench/benchmark/lib/timers-ctx.js:23:var L = require('_linklist');
node-cjs-deps-0.2.2.tgz/nodeCjsDeps/Global.js:19: _linklist = require('_linklist'),
node-core-lib-0.11.11.tgz/timers.js:23:var L = require('_linklist');
node-core-test-simple-0.11.11.tgz/test-timers-linked-list.js:24:var L = require('_linklist');
node-natives-0.10.25.tgz/timers.js:23:var L = require('_linklist');
perf-time-0.1.0.tgz/bench/settimeout/timers2.js:23:var L = require('_linklist');
perf-time-0.1.0.tgz/bench/settimeout/timers3.js:23:var L = require('_linklist');
perf-time-0.1.0.tgz/bench/settimeout/timers.js:23:var L = require('_linklist');
perf-timers-0.1.0.tgz/bench/settimeout/timers2.js:23:var L = require('_linklist');
perf-timers-0.1.0.tgz/bench/settimeout/timers3.js:23:var L = require('_linklist');
perf-timers-0.1.0.tgz/bench/settimeout/timers.js:23:var L = require('_linklist');
pezhu-0.0.0.tgz/Downloads/node-v0.9.11/lib/timers.js:23:var L = require('_linklist');
pezhu-0.0.0.tgz/Downloads/node-v0.9.11/test/simple/test-timers-linked-list.js:24:var L = require('_linklist');
portable-js-0.0.3.tgz/misc/io/timers.js:4:const L = require('_linklist');
portable-js-0.0.3.tgz/misc/node/timers.js:25:var L = require('_linklist');
promise-bench-0.0.2.tgz/benchmark/lib/timers-ctx.js:23:var L = require('_linklist');
wtfnode-0.2.1.tgz/index.js:28: var L = require('_linklist'); That's actually 17 packages, but we could even file issues to each of them in advance. |
@trevnorris Sure enough, a single ordered array is more efficient than a bunch of sets. The benchmarks in
And with this array-based implementation:
I suspect this is not worth doing if the only result is identical performance. Still tinkering, though... |
Additional changes seem to have made the benchmarks difference more substantial. Node 4.1.1:
Current master branch:
This implementation:
Small sample size here, of course. Maybe I'll try to do 100 or 1000 runs and get a median or something... |
Annnnnd....if I push the number of timers from 500,000 to 5,000,000, then current node starts out-performing this version. Which makes a lot of sense. Was just kind of thinking some magical use-native-constructs optimizations would trump it somehow. Anyway, I'm going to close this for now and will re-open if something amazing and unexpected happens. |
Linking this with #3078 — |
Hoping to get some early feedback on this.
Things remaining to be done:
It's semver-major because
_linklist
is exposed and could be used in userland. In reality, this is unlikely but weirder things have happened. (Perhaps @ChALkeR can do one of their trademark greps through npm source to see if any examples come up.)