- Notifications
You must be signed in to change notification settings - Fork5.2k
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
Uh oh!
There was an error while loading.Please reload this page.
Conversation
da5acaa to43ef1d7Compareahsonkhan commentedDec 30, 2020
This is great. How did you detect it?
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: |
....Json/src/System/Text/Json/Serialization/Converters/Collection/DictionaryDefaultConverter.cs OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
....Json/src/System/Text/Json/Serialization/Converters/Collection/DictionaryDefaultConverter.cs OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
lezzi commentedDec 31, 2020
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 for 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
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 |
During slow path deserialization fallback to storing dictionary keyas object only when Read returns false.
steveharter left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Thanks!
ericstj commentedFeb 17, 2021
Looks like we have a couple approvals: Is this ready to merge? Might want to get fresh test results (current are from Jan 5) |
layomia left a comment
There was a problem hiding this 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.
Uh oh!
There was an error while loading.Please reload this page.
Deserialization of dictionaries from
Streamalways causes keys boxing for value types becauseReadStackFrame.DictionaryKeyis an object. Saving key in the state (boxing) is only needed when value can't be fully read (Readcall returnsfalse).In the best-case scenario when an entire dictionary fits in a buffer - it should completely remove unnecessary heap allocations for keys.