Repository navigation
[NativeAOT] Hash relocations in method body folding keys - #135943
Conversation
MethodInternKey only hashed code, GC info, frame infos and EH bytes, so bodies that only differ in relocation targets (e.g. AsyncStateMachineBox MoveNext instantiated over thousands of struct state machines) all got the same hash, making method body deduplication quadratic. Hash relocation type/offset and the target consistently with MethodInternComparer.AreSame.
|
Azure Pipelines: Successfully started running 3 pipeline(s). 13 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
|
Tagging subscribers to this area: @dotnet/crossgen-contrib |
@dotnet-policy-service agree |
|
Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib |
agocke
left a comment
There was a problem hiding this comment.
LGTM, thanks!
I also noticed that in large apps we repeatedly run passes even though most of the benefit is in the first pass, but after your change this doesn't seem to matter too much.
|
/ba-g all failures known |
|
/backport to release/11.0 |
|
Started backporting to |
Fixes #135942
Problem
MethodInternKeyhashes code bytes, GC info, frame infos and EH bytes, but not relocations, so bodies that differ only in their relocation targets always share a hash code.AsyncStateMachineBox<TResult, TSM>.MoveNext,AsyncMethodBuilderCore.Start<TSM>, etc.HashSetbucket, and each insertion runsAreSameagainst every earlier copy, so deduplication is O(n²) per method family, per pass.Change
Relocations are mixed into the hash, consistently with
MethodInternComparer.AreSame:AreSame.MethodReadOnlyDataNodetargets: their data bytes.AreSamecompares them by content, and the hash covers a subset of what is compared.AreSametreatst1andt2as equal whenremapping[t1] == t2(or vice versa).id(t2).Why the output does not change:
Equalsaccepts is unchanged; only the bucket distribution changes.GetCompiledMethodBodies().ISymbolNodes already hash by identity.Results
Measured with the same change on v10.0.13 (osx-arm64 host, M1 Pro):
--methodbodyfolding:noneasync Task<int>methods,dotnet publish.o(two runs) and the sample's.o.__managedcodekeeps the folding savings (69.3 MB vs 80.0 MB without folding).Repro: https://github.com/andrew-kulikov/runtime-samples/tree/master/nativeaot-async-folding