Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JSON serialization performance improvement #1527

Merged
merged 4 commits into from Apr 4, 2023

Conversation

tomatosalat0
Copy link
Contributor

Summary

Now with .NET Core added as a build target, a small performance improvement can be made for JSON serialization.

This change reduces the time needed for serialization. Depending on the content to serialize, the change leads to a 10-20% time reduction. For some JSON files, it reduced the time to serialize even more, for a few of them, the improvement is almost negatable or even a little bit slower (see citm_catalog which takes 4% longer). The improvement works best for all ASCII-only strings (which are probably 99% of all keys for JSON objects) and for long string values (see doj-blog.json result for that).

Changes

I've changed the signature of the internal method NumberPrototype.NumberToString. It doesn't return a string anymore and instead will always fill the provided StringBuilder. That change allowed me to remove the NumberBuffer string builder during serialization which means that the JsonSerializer will now only allocate one StringBuilder per execution.

This didn't improve the performance a lot, but reduced the allocations quite significantly if a lot of floating point numbers needed to get serialized - which happens in the canada.json example.

Stuff tried but not included

I've also tried to remove all the checks for "indentation is active -> yes/no" during serialization. Basically I've doubled the implementation - one for the indentation active case and one without any indentation and did only one check at the very start. That one improves the performance, but not significantly enough (~5%) to accept the downside of having to maintain basically two almost identical implementations in my opinion.

JSON files

The same I've used previously:

Results

To reduce the torture of the previous huge tables, I tried to make it more readable by reducing the amount of columns and group the results - first all old serialize results and then all new serializer results.

As before, the important columns are Ratio and Alloc Ratio.

Method FileName Mean StdDev Ratio RatioSD Allocated Alloc Ratio
Old algol(...)ation [31] 297,032.16 us 2,585.905 us 1.00 0.00 202776.95 KB 1.00
Old australia-abc 147.93 us 1.102 us 1.00 0.00 100.62 KB 1.00
Old bestbuy_dataset 119,934.28 us 2,390.633 us 1.00 0.00 92342.08 KB 1.00
Old bitcoin 78.35 us 0.311 us 1.00 0.00 56.64 KB 1.00
Old canada 32,022.94 us 405.695 us 1.00 0.00 15735.25 KB 1.00
Old citm_catalog 6,356.62 us 106.456 us 1.00 0.00 3031.61 KB 1.00
Old doj-blog 423.06 us 11.418 us 1.00 0.00 306.49 KB 1.00
Old eu-lobby-country 48.27 us 0.639 us 1.00 0.00 42.34 KB 1.00
Old eu-lobby-financial 305.91 us 4.102 us 1.00 0.00 196.78 KB 1.00
Old eu-lobby-repr 695.80 us 21.872 us 1.00 0.00 435.74 KB 1.00
Old github-events 470.79 us 19.117 us 1.00 0.00 293.95 KB 1.00
Old github-gists 273.47 us 3.533 us 1.00 0.00 184.19 KB 1.00
Old inspe(...)yload [22] 72,972.65 us 955.740 us 1.00 0.00 48622.71 KB 1.00
Old json-generator 50.25 us 0.293 us 1.00 0.00 34.98 KB 1.00
Old meteorites 2,242.53 us 34.279 us 1.00 0.00 1225.83 KB 1.00
Old movies 34,296.78 us 631.736 us 1.00 0.00 21048.1 KB 1.00
Old reddit-scala 486.05 us 2.104 us 1.00 0.00 305.85 KB 1.00
Old rick-morty 94.73 us 0.539 us 1.00 0.00 75.87 KB 1.00
Old temp-anomaly 71.18 us 0.634 us 1.00 0.00 19.84 KB 1.00
Old thai-cinemas 51.92 us 0.456 us 1.00 0.00 43.85 KB 1.00
Old turkish 2,949.88 us 27.902 us 1.00 0.00 2025.41 KB 1.00
Old twitter 2,656.04 us 21.603 us 1.00 0.00 1434.4 KB 1.00
Old twitt(...)ponse [28] 50.13 us 0.976 us 1.00 0.00 34.89 KB 1.00
Old twitter_api_response 59.64 us 0.715 us 1.00 0.00 39.06 KB 1.00
New algol(...)ation [31] 257,276.46 us 3,874.708 us 0.87 0.01 195039.42 KB 0.96
New australia-abc 106.71 us 1.308 us 0.72 0.01 95.76 KB 0.95
New bestbuy_dataset 104,258.14 us 2,215.129 us 0.87 0.03 91635.72 KB 0.99
New bitcoin 69.05 us 0.314 us 0.88 0.01 56.64 KB 1.00
New canada 29,138.67 us 184.635 us 0.91 0.01 9390.84 KB 0.60
New citm_catalog 6,506.70 us 268.591 us 1.04 0.05 3031.84 KB 1.00
New doj-blog 197.10 us 4.667 us 0.47 0.02 306.43 KB 1.00
New eu-lobby-country 33.17 us 0.606 us 0.69 0.01 42.34 KB 1.00
New eu-lobby-financial 237.94 us 2.449 us 0.78 0.01 196.78 KB 1.00
New eu-lobby-repr 435.58 us 7.794 us 0.63 0.02 433.48 KB 0.99
New github-events 318.51 us 5.484 us 0.68 0.03 293.95 KB 1.00
New github-gists 181.78 us 3.831 us 0.67 0.02 184.19 KB 1.00
New inspe(...)yload [22] 69,506.84 us 763.500 us 0.95 0.02 47265.95 KB 0.97
New json-generator 39.96 us 0.337 us 0.80 0.01 34.98 KB 1.00
New meteorites 2,184.65 us 24.285 us 0.97 0.02 1156.53 KB 0.94
New movies 33,338.31 us 387.716 us 0.97 0.02 21034.4 KB 1.00
New reddit-scala 381.65 us 7.489 us 0.78 0.01 305.85 KB 1.00
New rick-morty 75.83 us 0.907 us 0.80 0.01 75.84 KB 1.00
New temp-anomaly 68.26 us 1.231 us 0.96 0.02 15.56 KB 0.78
New thai-cinemas 48.10 us 0.522 us 0.93 0.01 43.85 KB 1.00
New turkish 2,784.32 us 39.356 us 0.94 0.01 2025.28 KB 1.00
New twitter 2,402.95 us 30.261 us 0.90 0.01 1434.06 KB 1.00
New twitt(...)ponse [28] 38.99 us 0.511 us 0.78 0.02 34.89 KB 1.00
New twitter_api_response 45.00 us 0.496 us 0.75 0.01 39.06 KB 1.00

Copy link
Collaborator

@lahma lahma left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just couple of remarks,, looks like a great improvement with just so little code changes!

@@ -303,63 +301,110 @@ private static bool CanSerializesAsArray(ObjectInstance value)
/// <summary>
/// https://tc39.es/ecma262/#sec-quotejsonstring
/// </summary>
private static void QuoteJSONString(string value, ref SerializerState target)
#if NETCOREAPP1_0_OR_GREATER
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might be easier to just use value 512 without #if here as it's (I think) a common practice, casting it to MethodImplOptions should be safe


target.Json.Append('"');
[MethodImpl(MethodImplOptions.AggressiveInlining)]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure if this will inline as it's quite big

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am pretty sure it does inline it. It is only used in two places within the method above. Once for the none-dotnetcore-part and once for the dotnet-core part. So its only used once per compile target.

I saw an increment of execution duration without that attribute during the Benchmark-Runs - that's why I added it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok cool

@@ -547,22 +590,19 @@ public static PropertyEnumeration FromObjectInstance(ObjectInstance instance)

private static void RemoveUnserializableProperties(ObjectInstance instance, List<JsValue> keys)
{
for (var i = 0; i < keys.Count; i++)
for (var i = keys.Count - 1; i >= 0; i--)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I even had to open a question about this as engines seem to differ: tc39/test262#3811

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh damn, totally forgot that you can do that in JS. Damnit! Will undo the order change. It didn't contribute anything for the perf test anyway because the tests don't include any undefined - properties or non-plain objects.

@lahma lahma merged commit 8b0da8a into sebastienros:main Apr 4, 2023
3 checks passed
@lahma
Copy link
Collaborator

lahma commented Apr 4, 2023

Thank you!

@tomatosalat0 tomatosalat0 deleted the json-serialize-optimization branch April 4, 2023 18:59
@tomatosalat0
Copy link
Contributor Author

You're welcome 😀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants