Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Don't box every single value type dictionary key.#46460

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
layomia merged 1 commit intodotnet:mainfromlezzi:json-dict-key-boxing
Mar 3, 2021

Conversation

@lezzi
Copy link
Contributor

@lezzilezzi commentedDec 30, 2020
edited
Loading

Deserialization of dictionaries fromStream always causes keys boxing for value types becauseReadStackFrame.DictionaryKey is an object. Saving key in the state (boxing) is only needed when value can't be fully read (Read call returnsfalse).

In the best-case scenario when an entire dictionary fits in a buffer - it should completely remove unnecessary heap allocations for keys.

ahsonkhan and samsosa reacted with hooray emoji
@lezzilezziforce-pushed thejson-dict-key-boxing branch 2 times, most recently fromda5acaa to43ef1d7CompareDecember 30, 2020 14:11
@lezzilezzi marked this pull request as ready for reviewDecember 30, 2020 16:00
@ahsonkhan
Copy link
Contributor

This is great. How did you detect it?

In the best-case scenario when an entire dictionary fits in a buffer - it should completely remove unnecessary heap allocations for keys.

Can we run some benchmarks to get a sense of how much heap allocations we save? It might help modifying and running this benchmark on a dictionary input that you expect to get performance wins on (with value type keys). Please share the benchmarkdotnet results when you have them:
https://github.com/dotnet/performance/blob/0b094042e7dc114c8cd038b1ae90dad0e5696fa2/src/benchmarks/micro/libraries/System.Text.Json/Serializer/ReadJson.cs#L57-L64

@lezzi
Copy link
ContributorAuthor

This is great. How did you detect it?

In the best-case scenario when an entire dictionary fits in a buffer - it should completely remove unnecessary heap allocations for keys.

Can we run some benchmarks to get a sense of how much heap allocations we save? It might help modifying and running this benchmark on a dictionary input that you expect to get performance wins on (with value type keys). Please share the benchmarkdotnet results when you have them:
https://github.com/dotnet/performance/blob/0b094042e7dc114c8cd038b1ae90dad0e5696fa2/src/benchmarks/micro/libraries/System.Text.Json/Serializer/ReadJson.cs#L57-L64

I am currently working on the high-performance dynamodb library which involves some low-level optimized JSON deserialization. I was able to detect several inefficiencies during some internal benchmark comparisons.

Here is the benchmark result forDictionary<int, string> with100 items. I think the most important column for this case isAllocated, where we can see that the2KB difference disappears after the PR. It also becomes slightly faster.

BenchmarkDotNet=v0.12.1.1466-nightly,OS=Windows 10.0.19041.572 (2004/May2020Update/20H1)Intel Core i7-7820X CPU 3.60GHz (Kaby Lake), 1 CPU, 6 logical and 3 physical cores.NETSDK=6.0.100-alpha.1.20630.6  [Host]     : .NET 6.0.0 (6.0.20.62903), X64 RyuJIT  Job-NDNXAQ : .NET 6.0.0 (42.42.42.42424), X64 RyuJIT  Job-EVXCXL : .NET 6.0.0 (42.42.42.42424), X64 RyuJITPowerPlanMode=00000000-0000-0000-0000-000000000000Arguments=/p:DebugType=portableIterationTime=250.0000 msMaxIterationCount=20MinIterationCount=15WarmupCount=1
MethodJobToolchainMeanErrorStdDevMedianMinMaxRatioRatioSDGen 0Gen 1Gen 2Allocated
DeserializeFromStringJob-NDNXAQmaster19.96 μs0.156 μs0.138 μs19.93 μs19.77 μs20.20 μs1.000.003.28610.2347-19 KB
DeserializeFromStringJob-EVXCXLPR20.05 μs0.304 μs0.312 μs19.94 μs19.77 μs20.84 μs1.010.023.27270.1596-19 KB
DeserializeFromUtf8BytesJob-NDNXAQmaster19.56 μs0.232 μs0.194 μs19.54 μs19.30 μs19.97 μs1.000.003.23960.1580-19 KB
DeserializeFromUtf8BytesJob-EVXCXLPR19.52 μs0.138 μs0.122 μs19.52 μs19.34 μs19.78 μs1.000.013.22330.1572-19 KB
DeserializeFromStreamJob-NDNXAQmaster21.66 μs0.187 μs0.175 μs21.58 μs21.49 μs22.17 μs1.000.003.65090.2608-21 KB
DeserializeFromStreamJob-EVXCXLPR21.25 μs0.201 μs0.178 μs21.27 μs20.90 μs21.57 μs0.980.013.26690.1675-19 KB

It is also worth noting another potential optimization that I am considering to create a PR for. On the benchmark, you can see that deserialization fromStream is visibly slower than from bytes array even when entire JSON fits in a single buffer. I suspect it happens because we don't useUseFastPath for a single buffer case. But it is unrelated and probably not worth discussing in this thread.

ahsonkhan reacted with thumbs up emojiahsonkhan reacted with heart emoji

During slow path deserialization fallback to storing dictionary keyas object only when Read returns false.
@stephentoubstephentoub added this to the6.0.0 milestoneJan 15, 2021
@stevehartersteveharter added the tenet-performancePerformance related issue labelJan 15, 2021
Copy link
Contributor

@stevehartersteveharter left a comment

Choose a reason for hiding this comment

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

Thanks!

@ericstj
Copy link
Member

Looks like we have a couple approvals: Is this ready to merge? Might want to get fresh test results (current are from Jan 5)

Base automatically changed frommaster tomainMarch 1, 2021 09:07
Copy link
Contributor

@layomialayomia left a comment

Choose a reason for hiding this comment

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

Thanks for the PR; this good to merge. The perf results shouldn't be stale given the changes.

It is also worth noting another potential optimization that I am considering to create a PR for. On the benchmark, you can see that deserialization from Stream is visibly slower than from bytes array even when entire JSON fits in a single buffer. I suspect it happens because we don't use UseFastPath for a single buffer case. But it is unrelated and probably not worth discussing in this thread.

We'd be happy to take a PR exploring this if we can detect a single buffer case.

@layomialayomia merged commit6919fc2 intodotnet:mainMar 3, 2021
@ghostghost locked asresolvedand limited conversation to collaboratorsApr 2, 2021
Sign up for freeto subscribe to this conversation on GitHub. Already have an account?Sign in.

Reviewers

@stephentoubstephentoubstephentoub approved these changes

@eiriktsarpaliseiriktsarpalisAwaiting requested review from eiriktsarpalis

@jozkeejozkeeAwaiting requested review from jozkee

+3 more reviewers

@ahsonkhanahsonkhanahsonkhan left review comments

@steveharterstevehartersteveharter approved these changes

@layomialayomialayomia approved these changes

Reviewers whose approvals may not affect merge requirements

Assignees

@layomialayomia

Labels

Projects

None yet

Milestone

6.0.0

Development

Successfully merging this pull request may close these issues.

7 participants

@lezzi@ahsonkhan@ericstj@stephentoub@steveharter@layomia@Dotnet-GitSync-Bot

[8]ページ先頭

©2009-2025 Movatter.jp