Closed
Bug 1383648
Opened 6 years ago
Closed 6 years ago
Measure if it's useful to keep the Array.prototype.sort entry point in self-hosted code
Categories
(Core :: JavaScript: Standard Library, defect)
Core
JavaScript: Standard Library
Tracking
()
RESOLVED
FIXED
mozilla57
Tracking | Status | |
---|---|---|
firefox57 | --- | fixed |
People
(Reporter: anba, Assigned: anba)
References
(Blocks 1 open bug)
Details
Attachments
(1 file, 1 obsolete file)
12.27 KB,
patch
|
anba
:
review+
|
Details | Diff | Splinter Review |
Right now the entry point for Array.prototype.sort is in C++, but we call back to self-hosted code when a comparator function is present. So basically from user-JS to C++ and back to self-hosted JS. In Speedometer (all frameworks run once from InteractiveRunner.html), we see approx. the same number of calls to the self-hosted ArraySort function and to the C++ sort implementation. Name self-hosted c++ Vanilla 0 0 Vanilla2015 0 0 Vanilla-babel 0 0 React 401 0 React-Redux 300 0 Ember 2 61 Backbone 101 804 AngularJS 124 0 Angular2 0 0 Vue 3 0 jQuery 1 8 Preact 0 0 Inferno 0 0 Elm 0 0 Flight 1 31 But at least for Speedometer, it seems like the bytecode matching comparator matching isn't used [1]: Backbone: 8 breakpoint keep y 0x00007fffe88130dc in js::array_sort(JSContext*, unsigned int, JS::Value*) at /home/andre/hg/mozilla-inbound/js/src/jsarray.cpp:2116 breakpoint already hit 838 times 9 breakpoint keep y 0x00007fffe88130dc in js::array_sort(JSContext*, unsigned int, JS::Value*) at /home/andre/hg/mozilla-inbound/js/src/jsarray.cpp:2116 stop only if fval.ptr->data.debugView.tag == JSVAL_TAG_NULL breakpoint already hit 837 times 10 breakpoint keep y 0x00007fffe88130dc in js::array_sort(JSContext*, unsigned int, JS::Value*) at /home/andre/hg/mozilla-inbound/js/src/jsarray.cpp:2116 stop only if fval.ptr->data.debugView.tag != JSVAL_TAG_NULL Ember: 8 breakpoint keep y 0x00007fffe88130dc in js::array_sort(JSContext*, unsigned int, JS::Value*) at /home/andre/hg/mozilla-inbound/js/src/jsarray.cpp:2116 breakpoint already hit 61 times 9 breakpoint keep y 0x00007fffe88130dc in js::array_sort(JSContext*, unsigned int, JS::Value*) at /home/andre/hg/mozilla-inbound/js/src/jsarray.cpp:2116 stop only if fval.ptr->data.debugView.tag == JSVAL_TAG_NULL breakpoint already hit 61 times 10 breakpoint keep y 0x00007fffe88130dc in js::array_sort(JSContext*, unsigned int, JS::Value*) at /home/andre/hg/mozilla-inbound/js/src/jsarray.cpp:2116 stop only if fval.ptr->data.debugView.tag != JSVAL_TAG_NULL so we could simply decide on whether or not to call into C++ even from self-hosted code (i.e. if the comparator is present, stay in self-hosted JS; otherwise call into C++). This may improve the overall performance of Array.prototype.sort, because the slowish C++ to self-hosted JS call is no longer present. array_sort doesn't have a great ticks/call ratio per bug 1365361, so we could see if this change helps to improve the performance. [1] http://searchfox.org/mozilla-central/rev/3a3af33f513071ea829debdfbc628caebcdf6996/js/src/jsarray.cpp#2065
Assignee | ||
Comment 1•6 years ago
|
||
Except for BackboneJS, all other three frameworks with more than >100 calls are calling Array.prototype.sort on an array with less than 24 elements, where 24 is the insertion-sort cut-off [2]. All <24 >= 24 React: 401 401 0 React-Redux: 300 300 0 AngularJS: 124 124 0 Backbone: 905 827 78 Measured by placing breakpoints here [1]: br jsarray.cpp:2069 br jsarray.cpp:2069 if ((*(obj.ptr)).group_.value->clasp_ == &js::ArrayObject::class_)&(((ObjectElements*)((uintptr_t)(((ArrayObject*)obj.ptr)->elements_)-16))->length<24) br jsarray.cpp:2069 if ((*(obj.ptr)).group_.value->clasp_ == &js::ArrayObject::class_)&(((ObjectElements*)((uintptr_t)(((ArrayObject*)obj.ptr)->elements_)-16))->length>=24) [1] http://searchfox.org/mozilla-central/rev/3a3af33f513071ea829debdfbc628caebcdf6996/js/src/jsarray.cpp#2069 [2] http://searchfox.org/mozilla-central/rev/3a3af33f513071ea829debdfbc628caebcdf6996/js/src/builtin/Sorting.js#261
Assignee | ||
Comment 2•6 years ago
|
||
There is a slight performance regression when the optimized comparator path can be taken, because we now have to perform one additional call (from user code -> self-hosted code -> native code instead of just user code -> native code), but the performance improvement when the optimized comparator path can't be taken outweighs clearly (at least in this µ-benchmark): // Optimized comparator, int32 elements. // 4 elements: 465ms -> 485ms // 8 elements: 540ms -> 560ms // 16 elements: 740ms -> 760ms // 32 elements: 1080ms -> 1100ms // Note: Runtime difference for all variations was between 10-20ms, rounded up to 20ms. function cmp(a, b) { return a - b; } // Non-optimized comparator, int32 elements. // 4 elements: 520ms -> 220ms // 8 elements: 780ms -> 410ms // 16 elements: 1200ms -> 800ms // 32 elements: 3600ms -> 3100ms function cmp(a, b) { var x = a - b; return x; } var a = Array(16).fill(0).map((v, k) => k); var dt = 0; for (var i = 0; i < 1000000; ++i) { a.reverse(); var t = dateNow(); a.sort(cmp); dt += dateNow() - t; } print(dt);
Assignee: nobody → andrebargull
Status: NEW → ASSIGNED
Attachment #8895353 -
Flags: review?(jdemooij)
Comment 3•6 years ago
|
||
Comment on attachment 8895353 [details] [diff] [review] bug1383648.patch Review of attachment 8895353 [details] [diff] [review]: ----------------------------------------------------------------- Thanks. This is definitely the better design since C++ -> JS calls are slow. ::: js/src/jsarray.cpp @@ +2113,5 @@ > ComparatorMatchResult comp = MatchNumericComparator(cx, fval); > if (comp == Match_Failure) > return false; > > + if (!fval.isUndefined() && comp == Match_None) { Do you know how common comparators are? Pre-existing but I think it would be easier to understand and a little bit faster to wrap the MatchNumericComparator call and this if-statement in an |if (fval.isObject())| block and then replace the isObject check in MatchNumericComparator with an assert or something.
Attachment #8895353 -
Flags: review?(jdemooij) → review+
Comment 4•6 years ago
|
||
Also maybe rename array_sort to ArrayNativeSort or ArraySortIntrinsic? To make it a little clearer it's not the entry point.
Assignee | ||
Comment 5•6 years ago
|
||
Updated the patch to include the review comments/suggestions from comment #3 and comment #4. Also changed the error message back to JSMSG_BAD_SORT_ARG (I didn't see we don't use the standard JSMSG_NOT_FUNCTION for Array.prototype.sort). Carrying r+ from :jandem.
Attachment #8895353 -
Attachment is obsolete: true
Attachment #8897838 -
Flags: review+
Assignee | ||
Comment 6•6 years ago
|
||
Try: https://treeherder.mozilla.org/#/jobs?repo=try&revision=4e66807e000e3de296029b7e4c356ef92703f762
Keywords: checkin-needed
Pushed by ryanvm@gmail.com: https://hg.mozilla.org/integration/mozilla-inbound/rev/5f199b9a3f47 Move the Array.prototype.sort entry point to self-hosted code. r=jandem
Keywords: checkin-needed
Comment 8•6 years ago
|
||
bugherder |
https://hg.mozilla.org/mozilla-central/rev/5f199b9a3f47
Status: ASSIGNED → RESOLVED
Closed: 6 years ago
status-firefox57:
--- → fixed
Resolution: --- → FIXED
Target Milestone: --- → mozilla57
You need to log in
before you can comment on or make changes to this bug.
Description
•