Uh oh!
There was an error while loading. Please reload this page.
Improve the performance of ConditionalWeakTable.TryGetValue - #80059
Conversation
ghost
commented
Dec 30, 2022
Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
It does not guarantee that hash codes are non-zero.
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as outdated.
This comment was marked as outdated.
jkotas
commented
Dec 30, 2022
I would not expect 20% perf regression with the current change. Is it repeatable? Have you looked at the generated code to see what caused it? |
AustinWise
commented
Dec 30, 2022
My bad, the benchmark runner was not using the correct runtime, because I did not pass the |
AustinWise
commented
Dec 30, 2022
I updated the benchmark to properly read arguments and try a few different number of objects. It now shows that trying to get a value that is not in the usingSystem.Runtime.CompilerServices;usingBenchmarkDotNet.Attributes;usingBenchmarkDotNet.Running;namespaceMyBenchmarks{publicclassTryGetHashCode{privatereadonlyList<object>mRootedObjects=new();privatereadonlyConditionalWeakTable<object,object>mWeakTable=new();privateobjectmAnObjectInTheTable=null!;[Params(1,100,1000,10000)]publicintNumberOfObjects;[GlobalSetup]publicvoidSetup(){for(inti=0;i<NumberOfObjects;i++){varobj=newobject();mRootedObjects.Add(obj);mWeakTable.Add(obj,newobject());mAnObjectInTheTable=obj;}}[Benchmark]publicboolTryGetNonExistentValue(){returnmWeakTable.TryGetValue(newobject(),outobject_);}[Benchmark]publicboolTryGetExistingValue(){returnmWeakTable.TryGetValue(mAnObjectInTheTable,outobject_);}}publicclassProgram{publicstaticvoidMain(string[]args){varsummary=BenchmarkRunner.Run<TryGetHashCode>(null!,args);}}}BenchmarkDotNet=v0.13.3, OS=ubuntu 22.04
AMD Ryzen Threadripper PRO 3955WX 16-Cores, 1 CPU, 32 logical and 16 physical cores
.NET SDK=7.0.101
[Host] : .NET 7.0.1 (7.0.122.56804), X64 RyuJIT AVX2
Job-FOVPQH : .NET 8.0.0 (42.42.42.42424), X64 RyuJIT AVX2
Job-WAHSHU : .NET 8.0.0 (42.42.42.42424), X64 RyuJIT AVX2
// * Warnings *
MultimodalDistribution
TryGetHashCode.TryGetExistingValue: Toolchain=merge-base -> It seems that the distribution is bimodal (mValue = 3.29)
|
…erServices/ConditionalWeakTable.cs Co-authored-by: Jan Kotas <jkotas@microsoft.com>
This reverts commit 6a13d23.
AustinWise
commented
Dec 31, 2022
I added an implementation for Mono. One thing to note is that unlike CoreCLR, the hashcodes generated for objects are not deterministic. So the hash table could potentially have a different number of collisions run-to-run. I ran the benchmarks twice and confirmed the ratio between merge-base and PR were roughly the same. Here is the results for running Mono on x64 Linux. I used these directions to run the benchmarks. I used #80082 to include BenchmarkDotNet=v0.13.3, OS=ubuntu 22.04
AMD Ryzen Threadripper PRO 3955WX 16-Cores, 1 CPU, 32 logical and 16 physical cores
.NET SDK=7.0.101
[Host] : .NET 7.0.1 (7.0.122.56804), X64 RyuJIT AVX2
Job-PGRQPW : .NET 8.0.0 (42.42.42.42424) using MonoVM, X64 VectorSize=128
Job-SWPJPT : .NET 8.0.0 (42.42.42.42424) using MonoVM, X64 VectorSize=128
I also benchmarked WASM running on V8. I followed these directions to build the runtime. I modfied my benchmark to run against the WASM runtime. See this branch: https://github.com/AustinWise/TryGetHashCodeBenchmark/tree/wasm BenchmarkDotNet=v0.13.3, OS=ubuntu 22.04
AMD Ryzen Threadripper PRO 3955WX 16-Cores, 1 CPU, 32 logical and 16 physical cores
.NET SDK=7.0.101
[Host] : .NET 7.0.1 (7.0.122.56804), X64 RyuJIT AVX2
PR : .NET Core (Mono) 8.0.0-dev, Wasm AOT
merge-base : .NET Core (Mono) 8.0.0-dev, Wasm AOT
Runtime=Wasm IterationCount=3 LaunchCount=1 WarmupCount=3 V8 version 11.1.92
|
jkotas
commented
Jan 1, 2023
@vargaz@lambdageek Could you please review Mono changes? |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
This is dead code because this method no longer lives on System.Object.
AustinWise
commented
Jan 2, 2023
With the interpreter transforms actually kicking in, the improvments for Mono WASM are even better. At least I assume that is the reason, I could not figure out how run the interpreter under a debugger. BenchmarkDotNet=v0.13.3, OS=ubuntu 22.04
AMD Ryzen Threadripper PRO 3955WX 16-Cores, 1 CPU, 32 logical and 16 physical cores
.NET SDK=7.0.101
[Host] : .NET 7.0.1 (7.0.122.56804), X64 RyuJIT AVX2
PR : .NET Core (Mono) 8.0.0-dev, Wasm AOT
merge-base : .NET Core (Mono) 8.0.0-dev, Wasm AOT
Runtime=Wasm IterationCount=3 LaunchCount=1 WarmupCount=3
V8 version 11.1.92
|
jkotas
commented
Jan 4, 2023
@AustinWise Could you please resolve the merge conflict? |
jkotas
commented
Jan 5, 2023
@AustinWise Thank you! |
VSadov
commented
Jan 5, 2023
@AustinWise Thanks for getting this through!! |
AustinWise
commented
Jan 6, 2023
Thanks for all the help with reviewing! Perhaps this PR should be labeled-with |
I don't look at the labels. I look at every pr that comes through and track them on a list of prs to consider... this one is already on my list :) |
Also fixes Objective-C reference tracking in NativeAOT, which was broken by #79519.
Fixes#80032
Related issue: #77472