Skip to content

Commit 96b3764

Browse files
Make a bit of BenchmarkDotNet trimmable (#2046)
* 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.
1 parent 118135e commit 96b3764

File tree

11 files changed

+61
-36
lines changed

11 files changed

+61
-36
lines changed

src/BenchmarkDotNet.Annotations/Attributes/DynamicallyAccessedMembersAttribute.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ namespace System.Diagnostics.CodeAnalysis
2323
/// </remarks>
2424
[AttributeUsage(
2525
AttributeTargets.Field | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter |
26-
AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Method,
26+
AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Class,
2727
Inherited = false)]
2828
internal sealed class DynamicallyAccessedMembersAttribute : Attribute
2929
{

src/BenchmarkDotNet/BenchmarkDotNet.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@
4444
<ItemGroup>
4545
<ProjectReference Include="..\BenchmarkDotNet.Annotations\BenchmarkDotNet.Annotations.csproj" />
4646
</ItemGroup>
47+
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
48+
<Compile Include="..\BenchmarkDotNet.Annotations\Attributes\DynamicallyAccessedMembersAttribute.cs" Link="Properties\DynamicallyAccessedMembersAttribute.cs" />
49+
<Compile Include="..\BenchmarkDotNet.Annotations\Attributes\DynamicallyAccessedMemberTypes.cs" Link="Properties\DynamicallyAccessedMemberTypes.cs" />
50+
</ItemGroup>
4751
<ItemGroup>
4852
<Compile Include="..\BenchmarkDotNet.Disassembler.x64\DataContracts.cs" Link="Disassemblers\DataContracts.cs" />
4953
</ItemGroup>

src/BenchmarkDotNet/Characteristics/Characteristic.cs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Diagnostics.CodeAnalysis;
23
using static BenchmarkDotNet.Characteristics.CharacteristicHelper;
34

45
namespace BenchmarkDotNet.Characteristics
@@ -7,39 +8,39 @@ public abstract class Characteristic
78
{
89
public static readonly object EmptyValue = new object();
910

10-
public static Characteristic<T> Create<TOwner, T>(string memberName)
11+
public static Characteristic<T> Create<TOwner, [DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] T>(string memberName)
1112
where TOwner : CharacteristicObject
1213
=> new Characteristic<T>(
1314
memberName,
1415
typeof(TOwner),
1516
null, default,
1617
false);
1718

18-
public static Characteristic<T> Create<TOwner, T>(string memberName, T fallbackValue)
19+
public static Characteristic<T> Create<TOwner, [DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] T>(string memberName, T fallbackValue)
1920
where TOwner : CharacteristicObject
2021
=> new Characteristic<T>(
2122
memberName,
2223
typeof(TOwner),
2324
null, fallbackValue,
2425
false);
2526

26-
public static Characteristic<T> Create<TOwner, T>(string memberName, Func<CharacteristicObject, T, T> resolver, T fallbackValue, bool ignoreOnApply)
27+
public static Characteristic<T> Create<TOwner, [DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] T>(string memberName, Func<CharacteristicObject, T, T> resolver, T fallbackValue, bool ignoreOnApply)
2728
where TOwner : CharacteristicObject
2829
=> new Characteristic<T>(
2930
memberName,
3031
typeof(TOwner),
3132
resolver, fallbackValue,
3233
ignoreOnApply);
3334

34-
public static Characteristic<T> CreateHidden<TOwner, T>(string memberName)
35+
public static Characteristic<T> CreateHidden<TOwner, [DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] T>(string memberName)
3536
where TOwner : CharacteristicObject
3637
=> new Characteristic<T>(
3738
memberName,
3839
typeof(TOwner),
3940
null, default,
4041
false, true);
4142

42-
public static Characteristic<T> CreateIgnoreOnApply<TOwner, T>(string memberName)
43+
public static Characteristic<T> CreateIgnoreOnApply<TOwner, [DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] T>(string memberName)
4344
where TOwner : CharacteristicObject
4445
=> new Characteristic<T>(
4546
memberName,
@@ -49,7 +50,7 @@ public static Characteristic<T> CreateIgnoreOnApply<TOwner, T>(string memberName
4950

5051
protected Characteristic(
5152
string id,
52-
Type characteristicType,
53+
[DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] Type characteristicType,
5354
Type declaringType,
5455
object fallbackValue,
5556
bool ignoreOnApply,
@@ -78,6 +79,7 @@ protected Characteristic(
7879

7980
public bool DontShowInSummary { get; }
8081

82+
[DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)]
8183
public Type CharacteristicType { get; }
8284

8385
public Type DeclaringType { get; }

src/BenchmarkDotNet/Characteristics/CharacteristicHelper.cs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Concurrent;
33
using System.Collections.Generic;
4+
using System.Diagnostics.CodeAnalysis;
45
using System.Linq;
56
using System.Reflection;
67
using JetBrains.Annotations;
@@ -39,14 +40,16 @@ public static bool IsPresentableCharacteristic(this Characteristic c, bool inclu
3940
[PublicAPI] public static IReadOnlyList<Characteristic> GetThisTypeCharacteristics(this CharacteristicObject obj) =>
4041
GetThisTypeCharacteristics(obj.GetType());
4142

42-
public static IReadOnlyList<Characteristic> GetThisTypeCharacteristics(Type characteristicObjectType)
43+
public static IReadOnlyList<Characteristic> GetThisTypeCharacteristics(
44+
[DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] Type characteristicObjectType)
4345
{
4446
if (!IsCharacteristicObjectSubclass(characteristicObjectType))
4547
return EmptyCharacteristics;
4648
return ThisTypeCharacteristics.GetOrAdd(characteristicObjectType, GetThisTypeCharacteristicsCore);
4749
}
4850

49-
private static IReadOnlyList<Characteristic> GetThisTypeCharacteristicsCore(Type characteristicObjectType)
51+
private static IReadOnlyList<Characteristic> GetThisTypeCharacteristicsCore(
52+
[DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] Type characteristicObjectType)
5053
{
5154
var fieldValues = characteristicObjectType.GetTypeInfo()
5255
.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy | BindingFlags.Static)
@@ -73,14 +76,16 @@ private static IReadOnlyList<Characteristic> GetThisTypeCharacteristicsCore(Type
7376
public static IReadOnlyList<Characteristic> GetAllCharacteristics(this CharacteristicObject obj) =>
7477
GetAllCharacteristics(obj.GetType());
7578

76-
public static IReadOnlyList<Characteristic> GetAllCharacteristics(Type characteristicObjectType)
79+
public static IReadOnlyList<Characteristic> GetAllCharacteristics(
80+
[DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] Type characteristicObjectType)
7781
{
7882
if (!IsCharacteristicObjectSubclass(characteristicObjectType))
7983
return EmptyCharacteristics;
8084
return AllTypeCharacteristics.GetOrAdd(characteristicObjectType, GetAllCharacteristicsCore);
8185
}
8286

83-
private static IReadOnlyList<Characteristic> GetAllCharacteristicsCore(Type characteristicObjectType)
87+
private static IReadOnlyList<Characteristic> GetAllCharacteristicsCore(
88+
[DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] Type characteristicObjectType)
8489
{
8590
var result = new List<Characteristic>();
8691

@@ -90,7 +95,8 @@ private static IReadOnlyList<Characteristic> GetAllCharacteristicsCore(Type char
9095
}
9196

9297
private static void FillAllCharacteristicsCore(
93-
Type characteristicObjectType, List<Characteristic> result, HashSet<Characteristic> visited)
98+
[DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] Type characteristicObjectType,
99+
List<Characteristic> result, HashSet<Characteristic> visited)
94100
{
95101
// DONTTOUCH: DO NOT change the order of characteristic as it may break logic of some operations.
96102

@@ -113,7 +119,9 @@ private static void FillAllCharacteristicsCore(
113119
}
114120
}
115121

116-
public static IReadOnlyList<Characteristic> GetAllPresentableCharacteristics(Type characteristicObjectType, bool includeIgnoreOnApply = false) =>
122+
public static IReadOnlyList<Characteristic> GetAllPresentableCharacteristics(
123+
[DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] Type characteristicObjectType,
124+
bool includeIgnoreOnApply = false) =>
117125
GetAllCharacteristics(characteristicObjectType)
118126
.Where(c => c.IsPresentableCharacteristic(includeIgnoreOnApply))
119127
.ToArray();

src/BenchmarkDotNet/Characteristics/CharacteristicObject.cs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Diagnostics.CodeAnalysis;
34
using System.Linq;
45
using System.Reflection;
56
using JetBrains.Annotations;
67

8+
using NotNullAttribute = JetBrains.Annotations.NotNullAttribute;
9+
710
namespace BenchmarkDotNet.Characteristics
811
{
912
// TODO: better naming.
13+
[DynamicallyAccessedMembers(CharacteristicMemberTypes)]
1014
public abstract class CharacteristicObject
1115
{
1216
#region IdCharacteristic
1317

18+
internal const DynamicallyAccessedMemberTypes CharacteristicMemberTypes =
19+
DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties
20+
| DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields;
21+
1422
protected static string ResolveId(CharacteristicObject obj, string actual)
1523
{
1624
if (!string.IsNullOrEmpty(actual) && actual != IdCharacteristic.FallbackValue)
@@ -134,7 +142,7 @@ public bool HasValue(Characteristic characteristic)
134142
return false;
135143
}
136144

137-
internal T GetValue<T>(Characteristic<T> characteristic)
145+
internal T GetValue<[DynamicallyAccessedMembers(CharacteristicMemberTypes)] T>(Characteristic<T> characteristic)
138146
{
139147
return (T)GetValue((Characteristic)characteristic);
140148
}
@@ -154,12 +162,12 @@ private object ResolveCore(Characteristic characteristic, object result)
154162
#endregion
155163

156164
#region Resolve
157-
public T ResolveValue<T>(Characteristic<T> characteristic, IResolver resolver)
165+
public T ResolveValue<[DynamicallyAccessedMembers(CharacteristicMemberTypes)] T>(Characteristic<T> characteristic, IResolver resolver)
158166
{
159167
return resolver.Resolve(this, characteristic);
160168
}
161169

162-
public T ResolveValue<T>(Characteristic<T> characteristic, IResolver resolver, T defaultValue)
170+
public T ResolveValue<[DynamicallyAccessedMembers(CharacteristicMemberTypes)] T>(Characteristic<T> characteristic, IResolver resolver, T defaultValue)
163171
{
164172
return resolver.Resolve(this, characteristic, defaultValue);
165173
}
@@ -174,7 +182,7 @@ public object ResolveValue(Characteristic characteristic, IResolver resolver, ob
174182
return resolver.Resolve(this, characteristic, defaultValue);
175183
}
176184

177-
public T ResolveValue<T>(Characteristic<T> characteristic, T defaultValue)
185+
public T ResolveValue<[DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] T>(Characteristic<T> characteristic, T defaultValue)
178186
{
179187
return HasValue(characteristic) ? GetValue(characteristic) : (T)characteristic.ResolveValueCore(this, defaultValue);
180188
}
@@ -185,14 +193,14 @@ public object ResolveValue(Characteristic characteristic, object defaultValue)
185193
return HasValue(characteristic) ? GetValue(characteristic) : characteristic.ResolveValueCore(this, defaultValue);
186194
}
187195

188-
public T? ResolveValueAsNullable<T>(Characteristic<T> characteristic) where T : struct
196+
public T? ResolveValueAsNullable<[DynamicallyAccessedMembers(CharacteristicMemberTypes)] T>(Characteristic<T> characteristic) where T : struct
189197
{
190198
return HasValue(characteristic) ? GetValue(characteristic) : (T?)null;
191199
}
192200
#endregion
193201

194202
#region Set value
195-
internal void SetValue<T>(Characteristic<T> characteristic, T value)
203+
internal void SetValue<[DynamicallyAccessedMembers(CharacteristicMemberTypes)] T>(Characteristic<T> characteristic, T value)
196204
{
197205
SetValue((Characteristic)characteristic, value);
198206
}

src/BenchmarkDotNet/Characteristics/CharacteristicObject`1.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using JetBrains.Annotations;
1+
using System.Diagnostics.CodeAnalysis;
2+
using JetBrains.Annotations;
23

34
namespace BenchmarkDotNet.Characteristics
45
{
@@ -32,10 +33,10 @@ public T Apply(params CharacteristicObject[] others)
3233

3334
public new T UnfreezeCopy() => (T)UnfreezeCopyCore();
3435

35-
protected static Characteristic<TC> CreateCharacteristic<TC>(string memberName) => Characteristic.Create<T, TC>(memberName);
36+
protected static Characteristic<TC> CreateCharacteristic<[DynamicallyAccessedMembers(CharacteristicMemberTypes)] TC>(string memberName) => Characteristic.Create<T, TC>(memberName);
3637

37-
protected static Characteristic<TC> CreateHiddenCharacteristic<TC>(string memberName) => Characteristic.CreateHidden<T, TC>(memberName);
38+
protected static Characteristic<TC> CreateHiddenCharacteristic<[DynamicallyAccessedMembers(CharacteristicMemberTypes)] TC>(string memberName) => Characteristic.CreateHidden<T, TC>(memberName);
3839

39-
protected static Characteristic<TC> CreateIgnoreOnApplyCharacteristic<TC>(string memberName) => Characteristic.CreateIgnoreOnApply<T, TC>(memberName);
40+
protected static Characteristic<TC> CreateIgnoreOnApplyCharacteristic<[DynamicallyAccessedMembers(CharacteristicMemberTypes)] TC>(string memberName) => Characteristic.CreateIgnoreOnApply<T, TC>(memberName);
4041
}
4142
}

src/BenchmarkDotNet/Characteristics/Characteristic`1.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
using System;
2+
using System.Diagnostics.CodeAnalysis;
23

34
namespace BenchmarkDotNet.Characteristics
45
{
5-
public class Characteristic<T> : Characteristic
6+
public class Characteristic<[DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] T> : Characteristic
67
{
78
internal Characteristic(
89
string id,

src/BenchmarkDotNet/Characteristics/CompositeResolver.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Diagnostics.CodeAnalysis;
23
using System.Linq;
34

45
namespace BenchmarkDotNet.Characteristics
@@ -25,7 +26,7 @@ public object Resolve(CharacteristicObject obj, Characteristic characteristic)
2526
throw new InvalidOperationException($"There is no default resolver for {characteristic.FullId}");
2627
}
2728

28-
public T Resolve<T>(CharacteristicObject obj, Characteristic<T> characteristic)
29+
public T Resolve<[DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] T>(CharacteristicObject obj, Characteristic<T> characteristic)
2930
{
3031
if (obj.HasValue(characteristic))
3132
return characteristic[obj];
@@ -47,7 +48,7 @@ public object Resolve(CharacteristicObject obj, Characteristic characteristic, o
4748
return defaultValue;
4849
}
4950

50-
public T Resolve<T>(CharacteristicObject obj, Characteristic<T> characteristic, T defaultValue)
51+
public T Resolve<[DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] T>(CharacteristicObject obj, Characteristic<T> characteristic, T defaultValue)
5152
{
5253
if (obj.HasValue(characteristic))
5354
return characteristic[obj];
Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
namespace BenchmarkDotNet.Characteristics
1+
using System.Diagnostics.CodeAnalysis;
2+
3+
namespace BenchmarkDotNet.Characteristics
24
{
35
/// <summary>
46
/// An entity which can resolve default values of <see cref="Characteristic{T}"/>.
@@ -9,10 +11,10 @@ public interface IResolver
911

1012
object Resolve(CharacteristicObject obj, Characteristic characteristic);
1113

12-
T Resolve<T>(CharacteristicObject obj, Characteristic<T> characteristic);
14+
T Resolve<[DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] T>(CharacteristicObject obj, Characteristic<T> characteristic);
1315

1416
object Resolve(CharacteristicObject obj, Characteristic characteristic, object defaultValue);
1517

16-
T Resolve<T>(CharacteristicObject obj, Characteristic<T> characteristic, T defaultValue);
18+
T Resolve<[DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] T>(CharacteristicObject obj, Characteristic<T> characteristic, T defaultValue);
1719
}
1820
}

src/BenchmarkDotNet/Characteristics/Resolver.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Diagnostics.CodeAnalysis;
34

45
namespace BenchmarkDotNet.Characteristics
56
{
67
public class Resolver : IResolver
78
{
89
private readonly Dictionary<Characteristic, Func<CharacteristicObject, object>> resolvers = new Dictionary<Characteristic, Func<CharacteristicObject, object>>();
910

10-
protected void Register<T>(Characteristic<T> characteristic, Func<T> resolver) =>
11+
protected void Register<[DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] T>(Characteristic<T> characteristic, Func<T> resolver) =>
1112
resolvers[characteristic] = obj => resolver();
1213

13-
protected void Register<T>(Characteristic<T> characteristic, Func<CharacteristicObject, T> resolver) =>
14+
protected void Register<[DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] T>(Characteristic<T> characteristic, Func<CharacteristicObject, T> resolver) =>
1415
resolvers[characteristic] = obj => resolver(obj);
1516

1617
public bool CanResolve(Characteristic characteristic) => resolvers.ContainsKey(characteristic);
@@ -25,7 +26,7 @@ public object Resolve(CharacteristicObject obj, Characteristic characteristic)
2526
throw new InvalidOperationException($"There is no default resolver for {characteristic.FullId}");
2627
}
2728

28-
public T Resolve<T>(CharacteristicObject obj, Characteristic<T> characteristic)
29+
public T Resolve<[DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] T>(CharacteristicObject obj, Characteristic<T> characteristic)
2930
{
3031
if (obj.HasValue(characteristic))
3132
return characteristic[obj];
@@ -46,7 +47,7 @@ public object Resolve(CharacteristicObject obj, Characteristic characteristic, o
4647
return defaultValue;
4748
}
4849

49-
public T Resolve<T>(CharacteristicObject obj, Characteristic<T> characteristic, T defaultValue)
50+
public T Resolve<[DynamicallyAccessedMembers(CharacteristicObject.CharacteristicMemberTypes)] T>(CharacteristicObject obj, Characteristic<T> characteristic, T defaultValue)
5051
{
5152
if (obj.HasValue(characteristic))
5253
return characteristic[obj];

0 commit comments

Comments
 (0)