Uh oh!
There was an error while loading. Please reload this page.
assert: improve deepEqual perf for large input - #12849
Conversation
addaleax
commented
May 5, 2017
Also, I found some weird behaviour while doing this: a={};assert.deepStrictEqual([a,a],[a,{}]);This does not throw, but I think it should; do you agree? Would you consider changing it semver-major? If not, I could do it in this PR, otherwise I’ll just wait until after this to avoid conflicts. |
There was a problem hiding this comment.
How about instead doing if (!memos) { memos = ... }?
776351a to
788ac8bCompareaddaleax
commented
May 5, 2017
7664b48 to
a60f489CompareThere was a problem hiding this comment.
@joyeecheung That thought occurred to me and I couldn’t really find a difference … would there be one? Is that going to be more performant?
There was a problem hiding this comment.
@addaleax I think the GC pressure would be smaller after we leave the function because the references don't have be traversed?
@addaleax I keep being surprised by your energy and dedication 🥇 |
addaleax
commented
May 5, 2017
@refack That seems like a completely different issue, though? :D |
refack
commented
May 5, 2017
It fit under the title "assert: improve deepEqual perf for large input". No need to sort keys of arrays. It is an O(n*log(n)) operation. |
addaleax
commented
May 5, 2017
@refack Arrays can have extra non-indexed properties, too ;) This might not be as easy as you think. If you think you can improve the situation, feel free to experiment and see if you can get a PR together, and I’ll be happy to review. |
refack
commented
May 5, 2017
Challenge accepted 🖖 |
Fishrock123
commented
May 5, 2017
Imo, no. |
Fishrock123
left a comment
There was a problem hiding this comment.
CI again, since the last one only ran linux(?): https://ci.nodejs.org/job/node-test-pull-request/7899/
addaleax
commented
May 5, 2017
@joyeecheung Looks like doing this with |
addaleax
commented
May 5, 2017
Sorry, huh – what do memory addresses have to do with this? It’s not about the left and the right side of To have a more explicit example: a={};b={};assert.deepStrictEqual({key1:a,key2:a},{key1:a,key2:b});should throw imo, because |
There was a problem hiding this comment.
Changing from Array.prototype.indexOf (which uses Strict Equality Comparison) to Map.prototype.get (which uses SameValueZero) can have subtle nuances that might result in incompatibilities, especially around NaN. Not sure if we need to care about it though.
There was a problem hiding this comment.
I don’t think that actually affects the logic here – if it matters at all, it should only affect cases where non-primitives compare deep-equal to primitives, but that doesn’t seem to happen anyway (e.g. assert.deepEqual([0], 0) throws even though [0] == 0).
Trott
commented
May 5, 2017
One more reason to consider the implementation of IMO, that should not throw (so the current behavior is correct). The So, confusingly, the "strict" part doesn't apply to objects (or arrays or--ideally at least--Maps or Sets). It does mean "don't cast a string to a number" though. Whee! But I do agree it's confusing and unfortunate. Even if you disagree, I definitely wouldn't fix it in this PR because I predict a CITGM run will not be kind to the additional change. |
refack
commented
May 6, 2017
CI (linux only): https://ci.nodejs.org/job/node-test-commit-linux/9688/ |
@addaleax hmm wait, do we even need to put primitives into the memos? The memos are for cycles and is it even possible to make a cycle with primitives? (Or do we even care if they do since they are not compared recursively?) Also FWIW I think the example above should not throw because objects are not primitives and as the docs and the comments stare, for non-primitives we don't compare them by using operators. Objects with the same properties(or no properties), prototypes and tags should be considered equal. |
addaleax
commented
May 7, 2017
I don’t think so, for both questions – but I’m not sure it’s trivial to undo that without changing the logic here for really weird edge cases. |
Use a Map instead of an array for checking previously found cyclic references. This reduces complexity for an array-of-objects case from O(n²) to O(n·log n). Fixes: nodejs#12842 PR-URL: nodejs#12849 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com> Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com>
32c658d to
bc62437Compareaddaleax
commented
May 7, 2017
Landed in 7e5f500 |
Use a Map instead of an array for checking previously found cyclic references. This reduces complexity for an array-of-objects case from O(n²) to O(n·log n). Fixes: #12842 PR-URL: #12849 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com> Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com>
Use a Map instead of an array for checking previously found cyclic references. This reduces complexity for an array-of-objects case from O(n²) to O(n·log n). Fixes: nodejs#12842 PR-URL: nodejs#12849 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com> Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com>
Use a Map instead of an array for checking previously found
cyclic references.
This reduces complexity for an array-of-objects case from
O(n²) to O(n·log n).
Case from the issue, new output:
Fixes: #12842
Checklist
make -j4 test(UNIX), orvcbuild test(Windows) passesAffected core subsystem(s)