Closed
Bug 410890
Opened 17 years ago
Closed 16 years ago
nsJSON speedups
Categories
(Core :: DOM: Core & HTML, defect)
Core
DOM: Core & HTML
Tracking
()
RESOLVED
FIXED
mozilla1.9beta4
People
(Reporter: sayrer, Assigned: sayrer)
References
Details
(Keywords: perf)
Attachments
(3 files, 5 obsolete files)
3.59 KB,
text/plain
|
Details | |
217.68 KB,
text/plain
|
Details | |
29.62 KB,
patch
|
sayrer
:
review+
sayrer
:
superreview+
mtschrep
:
approval1.9+
|
Details | Diff | Splinter Review |
Shark says a good amount of decoding time is spent in string manipulation (appending one char at a time in the loop) and creating about:blank for the channel, so we'll route around that.
Comment 1•17 years ago
|
||
This simple JS script can test the native JSON imp against the JSM version and the json.org (json2.js) version. I tested like this from xpcshell: js> version(170); js> load("path/to/json-benchmark.js"); js> load("path/to/json2.js"); js> startEncode(); js> startDecode(); json2.js is in the tree or can be downloaded from json.org
Assignee | ||
Comment 2•17 years ago
|
||
Encode test case at 1000 iterations: Shark Bottom-Up summary. 6.8% szone_free 5.3% nsAString_internal::Replace(unsigned, unsigned, unsigned short const*, unsigned) 4.2% pthread_mutex_lock 3.5% nsAString_internal::ReplacePrep(unsigned, unsigned, unsigned) 3.2% pthread_mutex_unlock 2.5% js_Enumerate 2.2% JS_dtostr 2.2% szone_malloc 2.1% nsJSONWriter::WriteString(unsigned short const*, unsigned) 2.0% nsJSON::EncodeObject(JSContext*, long*, nsJSONWriter*, JSObject*, unsigned) 2.0% tiny_malloc_from_free_list 1.8% js_LookupPropertyWithFlags 1.8% szone_size 1.6% js_NewGCThing Three main issues here. 1.) String manipulation from nsJSONWriter::Write is expensive 2.) js_AtomizeString calls to PR_Lock are expensive 3.) JS_Enumerate allocations are expensive
Updated•17 years ago
|
Version: unspecified → Trunk
Assignee | ||
Comment 3•17 years ago
|
||
This patch pretty much removes string manipulation from the profile. We do spend some extra time in nsJSON::Write, but it's a win overall. Before iterations nsJSON json.jsm json2.js 20 5 22 38 50 9 52 95 100 17 103 196 200 34 198 379 500 88 496 955 750 130 994 1371 1000 166 958 2141 After iterations nsJSON json.jsm json2.js 20 3 20 39 50 7 51 97 100 15 101 192 200 30 206 386 500 77 500 964 750 117 1047 1394 1000 145 972 2156 Shark After: 6.7% szone_free 3.8% pthread_mutex_lock 3.7% pthread_mutex_unlock 3.6% nsJSONWriter::Write() 2.8% js_Enumerate 2.6% nsJSONWriter::WriteString() 2.5% JS_dtostr 2.3% szone_malloc 2.1% nsJSON::EncodeObject() 2.1% js_NewGCThing 2.0% szone_size 2.0% js_LookupPropertyWithFlags 1.8% tiny_malloc_from_free_list 1.7% js_CallIteratorNext 1.6% js_SearchScope 1.4% XUL SearchTable
Assignee | ||
Comment 4•17 years ago
|
||
Bottom-up view shows lots of allocator thrashing from string mutation. Decode top-down view: 96.2% start 96.2% _start 96.2% main 88.1% Process() 88.1% ProcessFile() 88.0% JS_ExecuteScript 88.0% js_Execute 88.0% js_Interpret 87.9% js_Invoke 79.1% Load() 78.9% JS_ExecuteScript 78.9% js_Execute 78.9% js_Interpret 78.7% js_Invoke 78.3% XPC_WN_CallMethod() 78.1% XPCWrappedNative::CallMethod() 77.8% NS_InvokeByIndex_P 77.3% nsJSON::Decode() 77.2% nsJSON::DecodeInternal() 72.0% nsJSONListener::OnDataAvailable() 71.8% nsJSONListener::ProcessBytes() 71.4% nsJSONListener::Consume() 33.8% nsAString_internal::Replace() 19.8% nsJSONListener::HandleString() 8.6% nsJSONListener::PushValue() 4.0% nsAString_internal::Assign() 3.3% nsAString_internal::SetLength() 2.8% js_NewStringCopyN 0.4% nsStringBuffer::AddRef()
Comment 5•17 years ago
|
||
This is another xpcshell benchmark script. It uses a 1600 item array to create a variable length chunk of JSON data. It will use 25, 50, 100, 200, 400, 800 & 1600 item chunks to benchmark how the parsers handle different data sizes (rather than iterating over a fixed size chunk like the other benchmark script). load xpcshell and init the same as before: js> version(170); js> load("path/to/json2.js"); js> load("path/to/json-array.js"); js> startEncode(); ... js> startDecode();
Assignee | ||
Comment 6•17 years ago
|
||
encode attachment 295803 [details] rounds nsJSON-patch nsJSON JSON.jsm json2.js 20 3 3 21 43 50 7 9 52 95 100 15 16 108 189 200 29 34 214 380 500 76 87 504 943 750 113 128 1077 1353 1000 143 161 977 2134 decode attachment 295803 [details] rounds nsJSON-patch nsJSON JSON.jsm json2.js 20 3 6 13 10 50 6 14 31 25 100 12 26 67 53 200 25 52 121 103 500 63 128 303 260 750 94 192 460 390 1000 124 255 843 514 encode attachment 296405 [details] rounds nsJSON-patch nsJSON JSON.jsm json2.js 24 0 1 2 6 49 0 1 5 11 99 1 2 12 25 199 3 3 23 48 399 5 6 48 89 799 10 11 94 177 1599 20 23 191 356 decode attachment 296405 [details] rounds nsJSON-patch nsJSON JSON.jsm json2.js 24 0 1 2 2 49 1 2 2 3 99 1 3 4 5 199 3 5 8 10 399 4 9 17 20 799 8 18 36 39 1599 18 41 65 79
Attachment #295872 -
Attachment is obsolete: true
Assignee | ||
Comment 7•17 years ago
|
||
Attachment #296770 -
Attachment is obsolete: true
Assignee | ||
Comment 8•17 years ago
|
||
Attachment #298586 -
Attachment is obsolete: true
Attachment #298589 -
Flags: review?(brendan)
Assignee | ||
Comment 9•17 years ago
|
||
Comment on attachment 298589 [details] [diff] [review] nit fix switching review to crowder, brendan has bigger bacon to fry
Attachment #298589 -
Flags: superreview?(jst)
Attachment #298589 -
Flags: review?(crowder)
Attachment #298589 -
Flags: review?(brendan)
Comment 10•17 years ago
|
||
Comment on attachment 298589 [details] [diff] [review] nit fix + mBufferCount = 0; + } + + memcpy(&mBuffer[mBufferCount], aBuffer, aLength * sizeof(PRUnichar)); + mBufferCount += aLength; What's the purpose of initially setting mBufferCount to 0 here? +#define PUSHCHAR(_c) \ Ever undefine this when you're done with it? Is that a spidermonkey-only style thing? Otherwise looks good to me, pending jst's happiness.
Attachment #298589 -
Flags: review?(crowder) → review+
Comment 11•17 years ago
|
||
Comment on attachment 298589 [details] [diff] [review] nit fix +static const nsString kJSONNumChars = NS_LITERAL_STRING("-+0123456789eE."); Last I heard, which was a long time ago now so this could've changed, we're not supposed to have statics of types that have constructors and/or destructors. Either way, that could be a nsDependentString to save on a malloc, but I also wonder if what this is used for couldn't be written faster with a little helper here that checks if c < '9' && c > '0' and a switch statement for the rest? sr=jst either way.
Attachment #298589 -
Flags: superreview?(jst) → superreview+
Assignee | ||
Comment 12•16 years ago
|
||
Attachment #298589 -
Attachment is obsolete: true
Attachment #301572 -
Flags: superreview+
Attachment #301572 -
Flags: review+
Attachment #301572 -
Flags: approval1.9?
Assignee | ||
Updated•16 years ago
|
Attachment #301572 -
Attachment is patch: true
Attachment #301572 -
Attachment mime type: application/octet-stream → text/plain
Assignee | ||
Comment 13•16 years ago
|
||
missed -u8pN
Attachment #301572 -
Attachment is obsolete: true
Attachment #301573 -
Flags: superreview+
Attachment #301573 -
Flags: review+
Attachment #301573 -
Flags: approval1.9?
Attachment #301572 -
Flags: approval1.9?
Assignee | ||
Comment 14•16 years ago
|
||
(In reply to comment #10) > (From update of attachment 298589 [details] [diff] [review]) > + mBufferCount = 0; > + } > + > + memcpy(&mBuffer[mBufferCount], aBuffer, aLength * sizeof(PRUnichar)); > + mBufferCount += aLength; > > What's the purpose of initially setting mBufferCount to 0 here? If we hit that case, the result of adding aBuffer to mBuffer would be bigger than we can handle, so we put the contents of mBuffer in a string. We can then reuse the buffer for more content, and we start over from zero.
Updated•16 years ago
|
Attachment #301573 -
Flags: approval1.9? → approval1.9+
Assignee | ||
Updated•16 years ago
|
Status: NEW → RESOLVED
Closed: 16 years ago
Resolution: --- → FIXED
Updated•16 years ago
|
OS: Mac OS X → All
Hardware: PC → All
Target Milestone: --- → mozilla1.9beta4
Updated•5 years ago
|
Component: DOM → DOM: Core & HTML
You need to log in
before you can comment on or make changes to this bug.
Description
•