Closed
Bug 551109
Opened 15 years ago
Closed 4 years ago
js_StringToNumber should fast-path things that are in intStringTable
Categories
(Core :: JavaScript Engine, defect)
Tracking
()
RESOLVED
DUPLICATE
of bug 654190
People
(Reporter: bzbarsky, Assigned: gwagner)
References
Details
Attachments
(2 files, 1 obsolete file)
(deleted),
patch
|
Details | Diff | Splinter Review | |
(deleted),
text/plain
|
Details |
brendan says we should do this.
Reporter | ||
Comment 1•15 years ago
|
||
In particular, strings have free bits; we should be able to ask a string whether it's in intStringTable, and maybe even where, if that helps with this bug.
Comment 2•15 years ago
|
||
We don't need bits if isIntString is fast enough.
/be
Reporter | ||
Comment 3•15 years ago
|
||
Ah, indeed. I hadn't known that existed!
Assignee | ||
Updated•15 years ago
|
Assignee: general → anygregor
Reporter | ||
Comment 4•15 years ago
|
||
Well, I tried this... and it doesn't help the testcase in bug 551039 at all, because the literal string "1" is not an isIntString, in fact.
Reporter | ||
Comment 5•15 years ago
|
||
Assignee | ||
Comment 6•15 years ago
|
||
I remember trying this before but I have to take a look again why we didn't add the fast path for this function.
Assignee | ||
Comment 7•15 years ago
|
||
We have an unitStringTable and an IntStringTable. There shouldn't be 2 representations of the same int and so we create it with:
if (u < 10) {
/* To avoid two ATOMIZED JSString copies of 0-9. */
return &JSString::unitStringTable['0' + u];
}
return &JSString::intStringTable[u];
So the "1" is not within the intStringTable.
Comment 8•15 years ago
|
||
(In reply to comment #7)
> We have an unitStringTable and an IntStringTable. There shouldn't be 2
> representations of the same int and so we create it with:
>
> if (u < 10) {
> /* To avoid two ATOMIZED JSString copies of 0-9. */
> return &JSString::unitStringTable['0' + u];
> }
> return &JSString::intStringTable[u];
>
> So the "1" is not within the intStringTable.
Ah, thanks for reminding me. This is why js_StringToInt32, the JIT-called builtin, does:
if (str->length() == 1) {
jschar c = str->chars()[0];
if ('0' <= c && c <= '9')
return c - '0';
return 0;
}
/be
Reporter | ||
Comment 9•15 years ago
|
||
Gregor, does the code for "1" go through the codepath you describe in comment 7? Or does that only get hit for runtime int-to-string conversions?
Assignee | ||
Comment 10•15 years ago
|
||
(In reply to comment #9)
> Gregor, does the code for "1" go through the codepath you describe in comment
> 7? Or does that only get hit for runtime int-to-string conversions?
If you type "1" in the shell it goes through JSString::unitString(jschar c) and not JSString::intString(jsint i). The codepath I copied in comment 7 is from intString.
I hope that was your question.
Reporter | ||
Comment 11•15 years ago
|
||
Ah, sure. That makes sense. I'd actually been testing with "11" (literal string) and still not seeing any speedup from the patch I attached here...
Comment 12•15 years ago
|
||
So "11" is an intString, but we don't optimize all paths that do string to int or string to number based on this fact. Right?
/be
Assignee | ||
Comment 13•15 years ago
|
||
Well we went the optimize SS path.
js_StringToNumber is called 6 times in SS.
js_StringToInt32 is called 24566 times but every time the string is an unitString and we optimize it.
What is the testcase that shows a performance hit?
Reporter | ||
Comment 14•15 years ago
|
||
There is no obvious testcase, actually. This bug was filed as part of the investigation of bug 551039 on Brendan's suggestion. If this code would never be hit for things that are actually intStrings, then there's no point adding a case for them.
Brendan, literal "11" doesn't seem to be an intString as far as I can tell.
Comment 15•15 years ago
|
||
(In reply to comment #14)
> Brendan, literal "11" doesn't seem to be an intString as far as I can tell.
js> "11"
Breakpoint 1, js_AtomizeString (cx=0x810000, str=0xbfffed10, flags=8) at ../jsatom.cpp:678
678 JS_ASSERT(!(flags & ~(ATOM_PINNED|ATOM_INTERNED|ATOM_TMPSTR|ATOM_NOCOPY)));
(gdb) n
679 JS_ASSERT_IF(flags & ATOM_NOCOPY, flags & ATOM_TMPSTR);
(gdb)
681 if (str->isAtomized())
(gdb)
684 size_t length = str->length();
(gdb)
685 if (length == 1) {
(gdb) p length
$1 = 2
(gdb) n
698 if (2 <= length && length <= 3) {
(gdb)
699 const jschar *chars = str->chars();
(gdb)
701 if ('1' <= chars[0] && chars[0] <= '9' &&
(gdb)
704 jsint i = (chars[0] - '0') * 10 + chars[1] - '0';
(gdb)
706 if (length == 3)
(gdb)
708 if (jsuint(i) < INT_STRING_LIMIT)
(gdb)
709 return (JSAtom *) STRING_TO_JSVAL(JSString::intString(i));
(gdb)
788 }
/be
Reporter | ||
Comment 16•15 years ago
|
||
This works fine. I have no idea why it didn't work before...
Attachment #431297 -
Attachment is obsolete: true
Reporter | ||
Comment 17•15 years ago
|
||
This of course still leaves the question of whether we want this change. This fast-path is about 10x faster than current slow-path, but only 4x faster if we get rid of LOCK_DTOA, I think.
Assignee | ||
Comment 18•15 years ago
|
||
static inline int32 intStringToInt(void* ptr) {
The naming is kind of dangerous since "0"-"9" are not intStrings. We should add a big warning.
I remember a small SS regression so I removed the optimization code last year.
Reporter | ||
Comment 19•15 years ago
|
||
> I remember a small SS regression so I removed the optimization code last year.
Which code?
Assignee | ||
Comment 20•15 years ago
|
||
When we did the patch I experimented with the fast-path code. I had the fast-path code in both StringToNumber and StringToInt32 but the version with only unitString optimization in StringToInt32 was the fastest for SS on my very old MacBook Pro. But there was no difference on a MacPro. So we decided to add other fast path on demand.
Maybe its time for it now :) I like this patch.
Assignee | ||
Comment 21•15 years ago
|
||
The remaining question is how big the overhead is if we only have to convert "double strings".
I got some numbers for attached micro-benchmark on my Mac Pro 2.66 Dual Core. Correct me if I am measuring something else here...
Tip:
Time is about 670
with this patch:
Time is about 687
I guess the slowdown is manageable and we should take the fast path. Any other opinions?
Reporter | ||
Comment 22•15 years ago
|
||
Over here on a macbook pro the numbers are:
Tip: about 1690
With this patch: about 1750
which is the same 3% difference or so that you're seeing.
I really wish we had some data on how often the fast path will be hit vs bypassed in practice....
Comment 23•15 years ago
|
||
Comment on attachment 431466 [details] [diff] [review]
Updated patch
>+ if (JSString::isIntString(str))
>+ return NumberTraits<T>::toSelfType(JSString::intStringToInt(str));
Can you Shark things to show this if test resulting in false, so the cost of the test and the branch around the early-returning then, is indeed the source of the regression?
>+ static inline int32 intStringToInt(void* ptr) {
>+ JS_ASSERT(isIntString(ptr));
>+ jsuword delta = reinterpret_cast<jsuword>(ptr) -
>+ reinterpret_cast<jsuword>(intStringTable);
>+ return delta / sizeof(JSString);
Much prefer to use the valid JSString pointer type and let the compiler do the division.
/be
Reporter | ||
Comment 24•15 years ago
|
||
I had assumed there was a reason the existing isIntString didn't take JSString*. If there isn't, so much the better.
Assignee | ||
Comment 25•15 years ago
|
||
I collected numbers for some internet pages (GMail, GDocs, CNN, Facebook....)
StringToNumberType calls: 9422
str->length == 1 : 1207 ... 13%
isIntString : 504 ... 5%
other: : 7711 ... 82%
Reporter | ||
Comment 26•15 years ago
|
||
Sounds like outside of benchmarks this isn't very useful (especially since the speedup from the fast-path will be less once LOCK_DTOA dies).
Comment 28•15 years ago
|
||
Comment on attachment 431466 [details] [diff] [review]
Updated patch
>@@ -447,16 +447,19 @@ StringToNumberType(JSContext *cx, JSStri
> {
> if (str->length() == 1) {
> jschar c = str->chars()[0];
> if ('0' <= c && c <= '9')
> return NumberTraits<T>::toSelfType(int32(c - '0'));
> return NumberTraits<T>::NaN();
> }
>
>+ if (JSString::isIntString(str))
>+ return NumberTraits<T>::toSelfType(JSString::intStringToInt(str));
>+
We should check if the str->length() == 1 should be eliminated or at least replaced with a unit string check.
>+ static inline int32 intStringToInt(void* ptr) {
The function should take JSString * pointer and use straight ptr - intStringTable to get the index.
Updated•4 years ago
|
Status: NEW → RESOLVED
Closed: 4 years ago
Resolution: --- → DUPLICATE
You need to log in
before you can comment on or make changes to this bug.
Description
•