Closed
Bug 847682
Opened 12 years ago
Closed 12 years ago
AppendSubstrings has bad allocating behaviour
Categories
(Core :: JavaScript Engine, defect)
Core
JavaScript Engine
Tracking
()
RESOLVED
FIXED
mozilla22
People
(Reporter: h4writer, Assigned: h4writer)
References
(Blocks 1 open bug)
Details
Attachments
(1 file, 1 obsolete file)
(deleted),
patch
|
sstangl
:
review+
|
Details | Diff | Splinter Review |
Added in bug 820124, AppendSubstrings actually has bad behaviour by using RopeBuilder.
Every append will create a new string and the contents needs to get copied. But we can really easy calculate the length of the new string and pre-allocate and fill it linearly.
Assignee | ||
Comment 1•12 years ago
|
||
Assignee: general → hv1989
Assignee | ||
Comment 2•12 years ago
|
||
When appending using RopeBuilder and length of both strings combined is lower than JSShortString::MAX_SHORT_LENGTH, the strings get copied. This is particular bad for small matches.
This patch improves the following benchmark from 240s to 180s. That is on par with v8.
var re11 = /\./g;
var str = "3.5.0.0";
for (var i = 0; i < 1000000; i++) {
str.replace(re11, '');
}
Attachment #720960 -
Attachment is obsolete: true
Attachment #721163 -
Flags: review?(sstangl)
Comment 3•12 years ago
|
||
Comment on attachment 721163 [details] [diff] [review]
AppendSubstrings should fill linearly before using RopeBuilder
Review of attachment 721163 [details] [diff] [review]:
-----------------------------------------------------------------
Nice! Locally this is a 5-7% speedup on v8-regexp. r+ with comments addressed.
The patch might be cleaner if it were restructured so that AppendSubstrings asks FlattenSubstrings whether a flattening can occur, but it's not a big deal.
::: js/src/jsstr.cpp
@@ +2362,5 @@
> };
>
> +static inline JSShortString *
> +FlattenSubstrings(JSContext *cx, Handle<JSStableString*> stableStr,
> + const StringRange *ranges, size_t rangesLen, size_t len)
"len" isn't a descriptive name. Perhaps "outputLen"?
@@ +2380,5 @@
> + for (size_t i = 0; i < rangesLen; i++) {
> + PodCopy(buf + pos, chars + ranges[i].start, ranges[i].length);
> + pos += ranges[i].length;
> +
> + JS_ASSERT(pos <= len);
This assert might look nicer as |JS_ASSERT(pos == outputLen)| after the loop.
@@ +2397,5 @@
> /* For single substrings, construct a dependent string. */
> if (rangesLen == 1)
> return js_NewDependentString(cx, stableStr, ranges[0].start, ranges[0].length);
>
> + /* Concat Strings by filling JSShortStrings */
This comment should still read "/* Collect substrings into a rope. */", since it's still doing the same action, just with an additional optimization.
@@ +2404,2 @@
> RopeBuilder rope(cx);
> + while (end < rangesLen) {
|start| and |end| are always equal at the top of the loop. With that in mind, I would rename |start| to |i|, change the condition to |i < rangesLen|, and move the definition of |end| into the loop body.
It would also be OK to write |for (size_t i = 0; i < rangesLen; )|.
@@ +2404,5 @@
> RopeBuilder rope(cx);
> + while (end < rangesLen) {
> +
> + /* Find maximum range that fits in JSShortString */
> + size_t len = 0;
Perhaps "substrLen"?
@@ +2411,5 @@
> + break;
> + len += ranges[end].length;
> + }
> +
> + RootedString part(cx, NULL);
The Rooted should be moved outside of the loop -- there's a small cost to creating a Rooted object, but reassignation is free. This bug was preexisting. It should probably go above the "/* Concat Strings..." comment, with its own comment.
@@ +2414,5 @@
> +
> + RootedString part(cx, NULL);
> +
> + if (start == end) {
> + /* If even one range doesn't fit JSShortString, use DependentString */
The wording in this comment is ambiguous -- better as "If not even one range fits JSShortString...".
@@ +2419,5 @@
> + const StringRange &sr = ranges[start];
> + part = js_NewDependentString(cx, stableStr, sr.start, sr.length);
> + end++;
> + } else {
> + /* Create string by linearly copying stableStr into */
Comment appears cut off.
@@ +2429,5 @@
>
> /* Appending to the rope permanently roots the substring. */
> + rope.append(part);
> +
> + start = end;
With the change to |i < rangesLen|, this chunk moves into the else{} block.
Attachment #721163 -
Flags: review?(sstangl) → review+
Assignee | ||
Comment 4•12 years ago
|
||
https://hg.mozilla.org/integration/mozilla-inbound/rev/e057918ed405
(In reply to Sean Stangl [:sstangl] from comment #3)
> Comment on attachment 721163 [details] [diff] [review]
> Nice! Locally this is a 5-7% speedup on v8-regexp. r+ with comments
> addressed.
That is a bit optimistic. I measured 2%-3% locally and awfy seems to agree.
Comment 5•12 years ago
|
||
Status: NEW → RESOLVED
Closed: 12 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla22
Comment 6•12 years ago
|
||
(In reply to Hannes Verschore [:h4writer] from comment #4)
> That is a bit optimistic. I measured 2%-3% locally and awfy seems to agree.
It wasn't optimistic -- I actually measured it :)
You need to log in
before you can comment on or make changes to this bug.
Description
•