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

Opt out of metadata trimming #2020

Merged
merged 3 commits into from
Jun 22, 2022
Merged

Conversation

MichalStrehovsky
Copy link
Member

@MichalStrehovsky MichalStrehovsky commented Jun 16, 2022

Benchmark.NET opts itself into trimming, but it's trim compatible only by accident (it's reflecting on things that are statically referenced and therefore would be kept by IL-based trimming solutions). NativeAOT is able to trim metadata more aggressively - e.g. an accessed field might still have its name and metadata removed and the only thing that is kept is a location in memory that can be read and written.

I'm now seeing Benchmark.NET failing with latest ILCompiler packages after dotnet/runtime#70201 that enabled more aggressive trimming.

It's reflecting on a field that is not used in any other way than by unanalyzable reflection. We would previously keep all fields, irrespective of whether they're used on reflected on dotnet/runtime#70546.

Benchmark.NET should ideally <EnableTrimAnalyzer>true</EnableTrimAnalyzer> in the BenchmarkDotNet.csproj project and fix all the warnings and the problem will go away. But enabling compat mode should help too.

Benchmark.NET opts itself into trimming, but it's trim compatible only by accident (it's reflecting on things that are statically referenced and therefore would be kept by IL-based trimming solutions). NativeAOT is able to trim metadata more aggressively - e.g. an accessed field might still have its name and metadata removed and the only thing that is kept is a location in memory that can be read and written.

I'm now seeing Benchmark.NET failing with latest ILCompiler packages after dotnet/runtime#70201 that enabled more aggressive trimming.

Benchmark.NET should ideally `<EnableTrimAnalyzer>true</EnableTrimAnalyzer>` in the BenchmarkDotNet.csproj project and fix all the warnings and the problem will go away. But enabling compat mode should help too.
@MichalStrehovsky
Copy link
Member Author

MichalStrehovsky commented Jun 16, 2022

The failure looks like this. Normally this would be some silent weird behavior (because the field just be missing), but BenchmarkDotNet is opting into IlcGenerateCompleteTypeMetadata that creates the fields that were trimmed for reflection purposes, but makes them unusable.

2022/06/16 16:40:32][INFO]  ---> EETypeRva:0x00AAFC80(System.Reflection.MissingRuntimeArtifactException): This object cannot be invoked because no code was generated for it: 'BenchmarkDotNet.Jobs.MetaMode.BaselineCharacteristic'.
[2022/06/16 16:40:32][INFO]    at System.Reflection.Runtime.FieldInfos.RuntimeFieldInfo.get_FieldAccessor() + 0x113
[2022/06/16 16:40:32][INFO]    at System.Reflection.Runtime.FieldInfos.RuntimeFieldInfo.GetValue(Object) + 0xd
[2022/06/16 16:40:32][INFO]    at BenchmarkDotNet.Characteristics.CharacteristicHelper.<>c.<GetThisTypeCharacteristicsCore>b__8_1(FieldInfo) + 0x16
[2022/06/16 16:40:32][INFO]    at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext() + 0x6d
[2022/06/16 16:40:32][INFO]    at System.Linq.Enumerable.ConcatIterator`1.MoveNext() + 0x5b
[2022/06/16 16:40:32][INFO]    at System.Collections.Generic.HashSet`1.UnionWith(IEnumerable`1) + 0x3e
[2022/06/16 16:40:32][INFO]    at System.Collections.Generic.HashSet`1..ctor(IEnumerable`1, IEqualityComparer`1) + 0xe8
[2022/06/16 16:40:32][INFO]    at System.Linq.Enumerable.DistinctIterator`1.ToArray() + 0x32
[2022/06/16 16:40:32][INFO]    at System.Linq.Buffer`1..ctor(IEnumerable`1) + 0x30
[2022/06/16 16:40:32][INFO]    at System.Linq.OrderedEnumerable`1.ToArray() + 0x34
[2022/06/16 16:40:32][INFO]    at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey, Func`2) + 0x82
[2022/06/16 16:40:32][INFO]    at BenchmarkDotNet.Characteristics.CharacteristicHelper.FillAllCharacteristicsCore(Type, List`1, HashSet`1) + 0x26
[2022/06/16 16:40:32][INFO]    at BenchmarkDotNet.Characteristics.CharacteristicHelper.FillAllCharacteristicsCore(Type, List`1, HashSet`1) + 0x1d0
[2022/06/16 16:40:32][INFO]    at BenchmarkDotNet.Characteristics.CharacteristicHelper.GetAllCharacteristicsCore(Type) + 0x44
[2022/06/16 16:40:32][INFO]    at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey, Func`2) + 0x82
[2022/06/16 16:40:32][INFO]    at BenchmarkDotNet.Characteristics.CharacteristicObject.GetCharacteristicsToApply(CharacteristicObject) + 0x3c
[2022/06/16 16:40:32][INFO]    at BenchmarkDotNet.Jobs.Job..cctor() + 0x218

Copy link
Member

@adamsitnik adamsitnik left a comment

Choose a reason for hiding this comment

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

LGTM, thank you @MichalStrehovsky !

@adamsitnik adamsitnik merged commit b09431c into dotnet:master Jun 22, 2022
@MichalStrehovsky MichalStrehovsky deleted the patch-1 branch June 22, 2022 20:34
@AndreyAkinshin AndreyAkinshin added this to the v0.13.2 milestone Jun 23, 2022
MichalStrehovsky added a commit to MichalStrehovsky/BenchmarkDotNet that referenced this pull request Jul 20, 2022
Another attempt at fixing the problem I tried to fix in dotnet#2020.

In that pull request, I reflection-rooted all of BenchmarkDotNet, but that looks like it increases the size of the closure too much (dotnet/performance#2532). So here I'm rolling that part back and annotating enough of the `Characteristic` APIs to make it so that we shouldn't run into the original problem.

I basically added `<EnableTrimAnalyzer>true</EnableTrimAnalyzer>` to the BechmarkDotNet project, looked at the trimming warning in https://github.com/dotnet/BenchmarkDotNet/blob/63e28c100a42a6492d09a0b93a8a4c141061bb0d/src/BenchmarkDotNet/Characteristics/CharacteristicHelper.cs#L49-L68 where we were getting the crash and kept getting annotations until it stopped generating new warnings.

We now have an annotation in a spot that should make sure the `Job` class has all fields and properties kept (it's used with one of the annotated `Create` methods).

There are more trimming warnings that I didn't try to solve because they're unrelated to the problem at hand.
adamsitnik pushed a commit that referenced this pull request Jul 20, 2022
* Make a bit of BenchmarkDotNet trimmable

Another attempt at fixing the problem I tried to fix in #2020.

In that pull request, I reflection-rooted all of BenchmarkDotNet, but that looks like it increases the size of the closure too much (dotnet/performance#2532). So here I'm rolling that part back and annotating enough of the `Characteristic` APIs to make it so that we shouldn't run into the original problem.

I basically added `<EnableTrimAnalyzer>true</EnableTrimAnalyzer>` to the BechmarkDotNet project, looked at the trimming warning in https://github.com/dotnet/BenchmarkDotNet/blob/63e28c100a42a6492d09a0b93a8a4c141061bb0d/src/BenchmarkDotNet/Characteristics/CharacteristicHelper.cs#L49-L68 where we were getting the crash and kept getting annotations until it stopped generating new warnings.

We now have an annotation in a spot that should make sure the `Job` class has all fields and properties kept (it's used with one of the annotated `Create` methods).

There are more trimming warnings that I didn't try to solve because they're unrelated to the problem at hand.
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.

3 participants