New issue
Advanced search Search tips

Issue 771227 link

Starred by 1 user

Issue metadata

Status: Started
Owner:
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Mac
Pri: 3
Type: Bug

Blocking:
issue 808503



Sign in to add a comment

V8's JSON parser is slow

Project Member Reported by lfg@chromium.org, Oct 3 2017

Issue description

I've attached a microbenchmark that's based on speedometer's VanillaJS usage. You can run them by placing it inside src/third_party/WebKit/PerformanceTests/

Here are some numbers:

Chrome canary 63.0.3231.0:

Time:
values 11.15903295820384, 11.174308030975174, 11.220951761128378, 11.140385568744525, 11.073154797167497, 11.168192986374809, 11.117040199217344, 11.214219630491435, 11.17355889024214, 10.922038489263636, 11.050029006326136, 10.90173719182152, 11.007699886070307, 10.934219734079782, 11.041427435738889, 10.107033484601954, 11.049723756906054, 10.977249650100141, 10.994145617458694, 10.995838075288487 runs/s
avg 11.021099357510037 runs/s
median 11.049876381616095 runs/s
stdev 0.2365787306034051 runs/s
min 10.107033484601954 runs/s
max 11.220951761128378 runs/s

Safari 11.0 (12604.1.38.1.7):
Time:
values 12.461059190031152, 12.812299807815506, 12.561236025624924, 12.545477355413368, 12.690355329949238, 12.60716086737267, 12.6135216952573, 12.787723785166241, 12.465719272001998, 12.462612163509478, 12.631047113805751, 12.489072061945786, 12.763241863433311, 12.130033964095105, 12.56755058439109, 12.592872434202265, 12.799180852425456, 12.67587780453797, 12.820512820512791, 12.727504136438892 runs/s
avg 12.610202956396513 runs/s
median 12.610341281314984 runs/s
stdev 0.16535712651697212 runs/s
min 12.130033964095105 runs/s
max 12.820512820512791 runs/s

Firefox nightly 58.0a1 (2017-10-03) (64-bit):
Time:
values 15.03386377816031, 15.17997760953303, 16.308757395002182, 14.688008342788732, 15.52126218904121, 15.120872474341757, 15.768766803592126, 15.927751718206215, 14.667756969934766, 15.176752250902064, 15.731742329792374, 15.709993519627664, 15.188681394624721, 14.99222278443056, 16.065353859500483, 14.91107408194385, 15.614265192680021, 15.032790273784702, 15.330428217186164, 16.29400910020404 runs/s
avg 15.41321651426385 runs/s
median 15.259554805905442 runs/s
stdev 0.4967561754516186 runs/s
min 14.667756969934766 runs/s
max 16.308757395002182 runs/s

Firefox beat us by ~40% on this microbenchmark, and Safari also consistently beat us by a smaller margin, but still significant ~15% margin.

We should investigate whether we can improve these numbers.

 
test.html
5.9 KB View Download

Comment 1 by adamk@chromium.org, Oct 3 2017

Components: -Blink>JavaScript>Parser Blink>JavaScript>Runtime
Status: Available (was: Untriaged)
Project Member

Comment 2 by bugdroid1@chromium.org, Oct 4 2017

The following revision refers to this bug:
  https://chromium.googlesource.com/v8/v8.git/+/a7ecf7d4ee542f5c6e1819d94e1aa3ab04081ff1

commit a7ecf7d4ee542f5c6e1819d94e1aa3ab04081ff1
Author: Toon Verwaest <verwaest@chromium.org>
Date: Wed Oct 04 15:01:29 2017

Inline relevant parts of MigrateToMap into AllocateStorageForMap

This speeds up the json parser by 10-20%

Bug: chromium:771227
Change-Id: Ib2392471bdd9ff9041237708cb272229b5ece410
Reviewed-on: https://chromium-review.googlesource.com/700494
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Reviewed-by: Camillo Bruni <cbruni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48287}
[modify] https://crrev.com/a7ecf7d4ee542f5c6e1819d94e1aa3ab04081ff1/src/objects.cc

Comment 3 by lfg@chromium.org, Oct 5 2017

Thanks! I just tested today's canary which contains your improvement, here are some numbers:

Time:
values 11.981141682990975, 11.848341232227492, 11.803031018365512, 11.970456912340339, 11.977697527204342, 11.810558639423647, 11.372165487752175, 11.787170843254188, 12.060616659329785, 11.500730296373817, 11.982649124068363, 11.901503159849096, 11.973323435385979, 12.018075185078333, 11.947574045090121, 12.012372743926239, 11.859512218262465, 11.862959096517022, 12.0500801330329, 12.048120192047021 runs/s
avg 11.888403981625988 runs/s
median 11.95901547871523 runs/s
stdev 0.17771026565578585 runs/s
min 11.372165487752175 runs/s
max 12.060616659329785 runs/s

Comment 4 by lfg@chromium.org, Oct 5 2017

Also, the perf dashboard for speedometer's VanillaJS shows an improvement for Linux and Mac (Windows didn't change much, and I can confirm on my windows box that there wasn't an improvement -- hopefully this will change with clang on windows).

https://chromeperf.appspot.com/report?sid=7e09cfe84f43452952e6a3220140c2b9658d0643de47d2ff2ac3e89d4c3df93b

For what it's worth, the change in #2 is also a 20% speedup in the structured deserializer (postMessage etc.), which is similar to the JSON parser. Awesome work!
Owner: jbroman@chromium.org
Status: Started (was: Available)
I've got a few ideas for relatively-micro stuff that might squeeze another bit out of here.
Cc: marja@chromium.org
What exactly? I've put optimizing the JSON parser on marja's plate. She'll look into replacing the recursive descent parser with a tight loop using a single zone stack (instead of multiple zonelists).
Ah, I wasn't aware Marja was going to look at this.

I have a CL to avoid reallocating the properties ZoneVector by using a single ZoneVector stack for the entire time:
https://chromium-review.googlesource.com/c/v8/v8/+/789511

(And a similar trick for elements seems useful, even though it doesn't matter for the Speedometer case.)

I was also going to look at shuffling around when the JSObject is actually created, since doing the allocation and then later the AllocateStorageForMap seems to be slower than just doing the allocation with the final map (at least for the transitioning fast path). I've done a little poking at that, but haven't polished a CL yet.

I'm sure a deeper look at improving the parser loop would yield results; I don't mean to interfere with such work.
Project Member

Comment 10 by bugdroid1@chromium.org, Nov 28 2017

The following revision refers to this bug:
  https://chromium.googlesource.com/v8/v8.git/+/d3104923b24180d32747287ba51b41e4af8b0da7

commit d3104923b24180d32747287ba51b41e4af8b0da7
Author: Jeremy Roman <jbroman@chromium.org>
Date: Tue Nov 28 22:53:50 2017

Implement and use VectorSegment to avoid repeated allocation of ZoneVector properties.

The parser holds a single vector whose backing storage is reused in calls
to ParseJsonObject, so that once we reach the peak number of unstored
properties no more allocations are required.

This improves performance of parsing inputs like those in Speedometer VanillaJS
by about 2% in my local measurement, and would presumably do better on more
pathological inputs.

This should also have the side effect of reducing peak memory usage at this time
slightly, since we do fewer zone allocations which cannot be freed until the
parse finishes.

Bug: chromium:771227
Change-Id: I8aa1514b37a74f82539f95f94292c8fa1582d66a
Reviewed-on: https://chromium-review.googlesource.com/789511
Reviewed-by: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: Marja Hölttä <marja@chromium.org>
Commit-Queue: Jeremy Roman <jbroman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49693}
[modify] https://crrev.com/d3104923b24180d32747287ba51b41e4af8b0da7/src/json-parser.cc
[modify] https://crrev.com/d3104923b24180d32747287ba51b41e4af8b0da7/src/json-parser.h

Project Member

Comment 11 by bugdroid1@chromium.org, Nov 29 2017

The following revision refers to this bug:
  https://chromium.googlesource.com/v8/v8.git/+/32033f4f4fdf96986a32d9fd97da5cacd814795c

commit 32033f4f4fdf96986a32d9fd97da5cacd814795c
Author: Michael Achenbach <machenbach@chromium.org>
Date: Wed Nov 29 10:57:48 2017

Revert "Implement and use VectorSegment to avoid repeated allocation of ZoneVector properties."

This reverts commit d3104923b24180d32747287ba51b41e4af8b0da7.

Reason for revert: Breaks win debug, causes lots of timeouts.
https://build.chromium.org/p/client.v8/builders/V8%20Win64%20-%20debug/builds/20387

Original change's description:
> Implement and use VectorSegment to avoid repeated allocation of ZoneVector properties.
> 
> The parser holds a single vector whose backing storage is reused in calls
> to ParseJsonObject, so that once we reach the peak number of unstored
> properties no more allocations are required.
> 
> This improves performance of parsing inputs like those in Speedometer VanillaJS
> by about 2% in my local measurement, and would presumably do better on more
> pathological inputs.
> 
> This should also have the side effect of reducing peak memory usage at this time
> slightly, since we do fewer zone allocations which cannot be freed until the
> parse finishes.
> 
> Bug: chromium:771227
> Change-Id: I8aa1514b37a74f82539f95f94292c8fa1582d66a
> Reviewed-on: https://chromium-review.googlesource.com/789511
> Reviewed-by: Camillo Bruni <cbruni@chromium.org>
> Reviewed-by: Marja Hölttä <marja@chromium.org>
> Commit-Queue: Jeremy Roman <jbroman@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#49693}

TBR=jbroman@chromium.org,marja@chromium.org,cbruni@chromium.org

Change-Id: I5b198aeffed6f1543f6110709dc74b311d4ba144
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: chromium:771227
Reviewed-on: https://chromium-review.googlesource.com/796151
Reviewed-by: Michael Achenbach <machenbach@chromium.org>
Commit-Queue: Michael Achenbach <machenbach@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49705}
[modify] https://crrev.com/32033f4f4fdf96986a32d9fd97da5cacd814795c/src/json-parser.cc
[modify] https://crrev.com/32033f4f4fdf96986a32d9fd97da5cacd814795c/src/json-parser.h

Project Member

Comment 12 by bugdroid1@chromium.org, Dec 11 2017

The following revision refers to this bug:
  https://chromium.googlesource.com/v8/v8.git/+/d01428579cdf65eba2b0a2ff1d989bbe16f44608

commit d01428579cdf65eba2b0a2ff1d989bbe16f44608
Author: Jeremy Roman <jbroman@chromium.org>
Date: Mon Dec 11 15:30:55 2017

Reland: Implement and use VectorSegment to avoid repeated allocation of ZoneVector properties.

The parser holds a single vector whose backing storage is reused in calls
to ParseJsonObject, so that once we reach the peak number of unstored
properties no more allocations are required.

This improves performance of parsing inputs like those in Speedometer VanillaJS
by about 2% in my local measurement, and would presumably do better on more
pathological inputs.

This should also have the side effect of reducing peak memory usage at this time
slightly, since we do fewer zone allocations which cannot be freed until the
parse finishes.

Reland switches to use std::vector::data instead of operator[] to avoid an index
check in debug MSVC. In such cases the out-of-bounds pointer cannot be
dereferenced, so it is legal.

Bug: chromium:771227
Change-Id: I21837196372c904bfc799cd14353a73d11dcff32
Reviewed-on: https://chromium-review.googlesource.com/804062
Reviewed-by: Marja Hölttä <marja@chromium.org>
Commit-Queue: Jeremy Roman <jbroman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49997}
[modify] https://crrev.com/d01428579cdf65eba2b0a2ff1d989bbe16f44608/src/json-parser.cc
[modify] https://crrev.com/d01428579cdf65eba2b0a2ff1d989bbe16f44608/src/json-parser.h

Blocking: 808503
Labels: Hotlist-Speedometer

Sign in to add a comment