From b0d0c8c65b25a7e1efb743f20684244f67000940 Mon Sep 17 00:00:00 2001 From: Ilia Shuliatikov Date: Wed, 1 Oct 2025 23:44:45 +0200 Subject: [PATCH 1/4] Implement benchmarks for runtime member info with the same parent class in a HashSet --- .../System.Reflection/RuntimeEventInfo.cs | 61 +++++++++++++++++++ .../System.Reflection/RuntimeFieldInfo.cs | 55 +++++++++++++++++ .../System.Reflection/RuntimeMethodInfo.cs | 55 +++++++++++++++++ .../System.Reflection/RuntimePropertyInfo.cs | 55 +++++++++++++++++ 4 files changed, 226 insertions(+) create mode 100644 src/benchmarks/micro/runtime/System.Reflection/RuntimeEventInfo.cs create mode 100644 src/benchmarks/micro/runtime/System.Reflection/RuntimeFieldInfo.cs create mode 100644 src/benchmarks/micro/runtime/System.Reflection/RuntimeMethodInfo.cs create mode 100644 src/benchmarks/micro/runtime/System.Reflection/RuntimePropertyInfo.cs diff --git a/src/benchmarks/micro/runtime/System.Reflection/RuntimeEventInfo.cs b/src/benchmarks/micro/runtime/System.Reflection/RuntimeEventInfo.cs new file mode 100644 index 00000000000..9cb23d4124d --- /dev/null +++ b/src/benchmarks/micro/runtime/System.Reflection/RuntimeEventInfo.cs @@ -0,0 +1,61 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Reflection.Emit; +using BenchmarkDotNet.Attributes; +using MicroBenchmarks; + +namespace System.Reflection +{ + [BenchmarkCategory(Categories.Runtime, Categories.Reflection)] + public class RuntimeEventInfo + { + private const int Iterations = 1200; + private readonly List _events = new(Iterations); + + [GlobalSetup] + public void Setup() + { + var baseType = typeof(RuntimeEventInfoTestClass); + var eventsPerType = baseType.GetEvents().Length; + + var assemblyName = new AssemblyName(baseType.Namespace + ".DynamicAssembly"); + var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); + var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name); + + for (var i = 0; i < Iterations; i += eventsPerType) + { + var typeBuilder = moduleBuilder.DefineType($"RuntimeDerivedClass{i}", TypeAttributes.Public, baseType); + + var derivedType = typeBuilder.CreateType(); + _events.AddRange(derivedType.GetEvents()); + } + } + + [Benchmark(OperationsPerInvoke = Iterations)] + public void AddToHashSet() + { + var set = new HashSet(); + + for (int i = 0; i < _events.Count; i++) + { + set.Add(_events[i]); + } + } + } + + public class RuntimeEventInfoTestClass + { + public event EventHandler event1; + public event EventHandler event2; + public event EventHandler event3; + + protected virtual void OnEvent1() => event1?.Invoke(this, EventArgs.Empty); + + protected virtual void OnEvent2() => event2?.Invoke(this, EventArgs.Empty); + + protected virtual void OnEvent3() => event3?.Invoke(this, EventArgs.Empty); + } +} \ No newline at end of file diff --git a/src/benchmarks/micro/runtime/System.Reflection/RuntimeFieldInfo.cs b/src/benchmarks/micro/runtime/System.Reflection/RuntimeFieldInfo.cs new file mode 100644 index 00000000000..2c62816b4aa --- /dev/null +++ b/src/benchmarks/micro/runtime/System.Reflection/RuntimeFieldInfo.cs @@ -0,0 +1,55 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Reflection.Emit; +using BenchmarkDotNet.Attributes; +using MicroBenchmarks; + +namespace System.Reflection +{ + [BenchmarkCategory(Categories.Runtime, Categories.Reflection)] + public class RuntimeFieldInfo + { + private const int Iterations = 1200; + private readonly List _fields = new(Iterations); + + [GlobalSetup] + public void Setup() + { + var baseType = typeof(RuntimeFieldInfoTestClass); + var fieldsPerType = baseType.GetFields().Length; + + var assemblyName = new AssemblyName(baseType.Namespace + ".DynamicAssembly"); + var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); + var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name); + + for (var i = 0; i < Iterations; i += fieldsPerType) + { + var typeBuilder = moduleBuilder.DefineType($"RuntimeDerivedClass{i}", TypeAttributes.Public, baseType); + + var derivedType = typeBuilder.CreateType(); + _fields.AddRange(derivedType.GetFields()); + } + } + + [Benchmark(OperationsPerInvoke = Iterations)] + public void AddToHashSet() + { + var set = new HashSet(); + + for (int i = 0; i < _fields.Count; i++) + { + set.Add(_fields[i]); + } + } + } + + public class RuntimeFieldInfoTestClass + { + public int Field1; + public string Field2; + public DateTime Field3; + } +} \ No newline at end of file diff --git a/src/benchmarks/micro/runtime/System.Reflection/RuntimeMethodInfo.cs b/src/benchmarks/micro/runtime/System.Reflection/RuntimeMethodInfo.cs new file mode 100644 index 00000000000..ad103c4b0f2 --- /dev/null +++ b/src/benchmarks/micro/runtime/System.Reflection/RuntimeMethodInfo.cs @@ -0,0 +1,55 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Reflection.Emit; +using BenchmarkDotNet.Attributes; +using MicroBenchmarks; + +namespace System.Reflection +{ + [BenchmarkCategory(Categories.Runtime, Categories.Reflection)] + public class RuntimeMethodInfo + { + private const int Iterations = 1200; + private readonly List _methods = new(Iterations); + + [GlobalSetup] + public void Setup() + { + var baseType = typeof(RuntimeMethodInfoTestClass); + var methodsPerType = baseType.GetMethods().Length; + + var assemblyName = new AssemblyName(baseType.Namespace + ".DynamicAssembly"); + var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); + var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name); + + for (var i = 0; i < Iterations; i += methodsPerType) + { + var typeBuilder = moduleBuilder.DefineType($"RuntimeDerivedClass{i}", TypeAttributes.Public, baseType); + + var derivedType = typeBuilder.CreateType(); + _methods.AddRange(derivedType.GetMethods()); + } + } + + [Benchmark(OperationsPerInvoke = Iterations)] + public void AddToHashSet() + { + var set = new HashSet(); + + for (int i = 0; i < _methods.Count; i++) + { + set.Add(_methods[i]); + } + } + } + + public class RuntimeMethodInfoTestClass + { + public int Method1() => throw new NotImplementedException(); + public string Method2() => throw new NotImplementedException(); + public DateTime Method3() => throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/src/benchmarks/micro/runtime/System.Reflection/RuntimePropertyInfo.cs b/src/benchmarks/micro/runtime/System.Reflection/RuntimePropertyInfo.cs new file mode 100644 index 00000000000..15fe60c7183 --- /dev/null +++ b/src/benchmarks/micro/runtime/System.Reflection/RuntimePropertyInfo.cs @@ -0,0 +1,55 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Reflection.Emit; +using BenchmarkDotNet.Attributes; +using MicroBenchmarks; + +namespace System.Reflection +{ + [BenchmarkCategory(Categories.Runtime, Categories.Reflection)] + public class RuntimePropertyInfo + { + private const int Iterations = 1200; + private readonly List _properties = new(Iterations); + + [GlobalSetup] + public void Setup() + { + var baseType = typeof(RuntimePropertyInfoTestClass); + var propertiesPerType = baseType.GetProperties().Length; + + var assemblyName = new AssemblyName(baseType.Namespace + ".DynamicAssembly"); + var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); + var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name); + + for (var i = 0; i < Iterations; i += propertiesPerType) + { + var typeBuilder = moduleBuilder.DefineType($"RuntimeDerivedClass{i}", TypeAttributes.Public, baseType); + + var derivedType = typeBuilder.CreateType(); + _properties.AddRange(derivedType.GetProperties()); + } + } + + [Benchmark(OperationsPerInvoke = Iterations)] + public void AddToHashSet() + { + var set = new HashSet(); + + for (int i = 0; i < _properties.Count; i++) + { + set.Add(_properties[i]); + } + } + } + + public class RuntimePropertyInfoTestClass + { + public int Property1 { get; set; } + public string Property2 { get; set; } + public DateTime Property3 { get; set; } + } +} \ No newline at end of file From ef4d2064bcb60b8b0086361dcebb55835e679c99 Mon Sep 17 00:00:00 2001 From: Ilia Shuliatikov Date: Thu, 2 Oct 2025 00:55:01 +0200 Subject: [PATCH 2/4] Ensure the dynamic assembly can be unloaded and the hashset is returned to prevent dead code elimination --- .../runtime/System.Reflection/RuntimeEventInfo.cs | 12 ++++++++++-- .../runtime/System.Reflection/RuntimeFieldInfo.cs | 12 ++++++++++-- .../runtime/System.Reflection/RuntimeMethodInfo.cs | 13 +++++++++++-- .../System.Reflection/RuntimePropertyInfo.cs | 12 ++++++++++-- 4 files changed, 41 insertions(+), 8 deletions(-) diff --git a/src/benchmarks/micro/runtime/System.Reflection/RuntimeEventInfo.cs b/src/benchmarks/micro/runtime/System.Reflection/RuntimeEventInfo.cs index 9cb23d4124d..63c7603103d 100644 --- a/src/benchmarks/micro/runtime/System.Reflection/RuntimeEventInfo.cs +++ b/src/benchmarks/micro/runtime/System.Reflection/RuntimeEventInfo.cs @@ -22,7 +22,7 @@ public void Setup() var eventsPerType = baseType.GetEvents().Length; var assemblyName = new AssemblyName(baseType.Namespace + ".DynamicAssembly"); - var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); + var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndCollect); var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name); for (var i = 0; i < Iterations; i += eventsPerType) @@ -34,8 +34,14 @@ public void Setup() } } + [GlobalCleanup] + public void Cleanup() + { + _events.Clear(); + } + [Benchmark(OperationsPerInvoke = Iterations)] - public void AddToHashSet() + public HashSet AddToHashSet() { var set = new HashSet(); @@ -43,6 +49,8 @@ public void AddToHashSet() { set.Add(_events[i]); } + + return set; } } diff --git a/src/benchmarks/micro/runtime/System.Reflection/RuntimeFieldInfo.cs b/src/benchmarks/micro/runtime/System.Reflection/RuntimeFieldInfo.cs index 2c62816b4aa..8f3d0232125 100644 --- a/src/benchmarks/micro/runtime/System.Reflection/RuntimeFieldInfo.cs +++ b/src/benchmarks/micro/runtime/System.Reflection/RuntimeFieldInfo.cs @@ -22,7 +22,7 @@ public void Setup() var fieldsPerType = baseType.GetFields().Length; var assemblyName = new AssemblyName(baseType.Namespace + ".DynamicAssembly"); - var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); + var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndCollect); var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name); for (var i = 0; i < Iterations; i += fieldsPerType) @@ -34,8 +34,14 @@ public void Setup() } } + [GlobalCleanup] + public void Cleanup() + { + _fields.Clear(); + } + [Benchmark(OperationsPerInvoke = Iterations)] - public void AddToHashSet() + public HashSet AddToHashSet() { var set = new HashSet(); @@ -43,6 +49,8 @@ public void AddToHashSet() { set.Add(_fields[i]); } + + return set; } } diff --git a/src/benchmarks/micro/runtime/System.Reflection/RuntimeMethodInfo.cs b/src/benchmarks/micro/runtime/System.Reflection/RuntimeMethodInfo.cs index ad103c4b0f2..ab6752c7e7c 100644 --- a/src/benchmarks/micro/runtime/System.Reflection/RuntimeMethodInfo.cs +++ b/src/benchmarks/micro/runtime/System.Reflection/RuntimeMethodInfo.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; +using System.Linq; using System.Reflection.Emit; using BenchmarkDotNet.Attributes; using MicroBenchmarks; @@ -22,7 +23,7 @@ public void Setup() var methodsPerType = baseType.GetMethods().Length; var assemblyName = new AssemblyName(baseType.Namespace + ".DynamicAssembly"); - var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); + var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndCollect); var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name); for (var i = 0; i < Iterations; i += methodsPerType) @@ -34,8 +35,14 @@ public void Setup() } } + [GlobalCleanup] + public void Cleanup() + { + _methods.Clear(); + } + [Benchmark(OperationsPerInvoke = Iterations)] - public void AddToHashSet() + public HashSet AddToHashSet() { var set = new HashSet(); @@ -43,6 +50,8 @@ public void AddToHashSet() { set.Add(_methods[i]); } + + return set; } } diff --git a/src/benchmarks/micro/runtime/System.Reflection/RuntimePropertyInfo.cs b/src/benchmarks/micro/runtime/System.Reflection/RuntimePropertyInfo.cs index 15fe60c7183..89eb6463567 100644 --- a/src/benchmarks/micro/runtime/System.Reflection/RuntimePropertyInfo.cs +++ b/src/benchmarks/micro/runtime/System.Reflection/RuntimePropertyInfo.cs @@ -22,7 +22,7 @@ public void Setup() var propertiesPerType = baseType.GetProperties().Length; var assemblyName = new AssemblyName(baseType.Namespace + ".DynamicAssembly"); - var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); + var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndCollect); var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name); for (var i = 0; i < Iterations; i += propertiesPerType) @@ -34,8 +34,14 @@ public void Setup() } } + [GlobalCleanup] + public void Cleanup() + { + _properties.Clear(); + } + [Benchmark(OperationsPerInvoke = Iterations)] - public void AddToHashSet() + public HashSet AddToHashSet() { var set = new HashSet(); @@ -43,6 +49,8 @@ public void AddToHashSet() { set.Add(_properties[i]); } + + return set; } } From 7947394c8080d3789f5c66776f9ad4cf62d4f4eb Mon Sep 17 00:00:00 2001 From: Ilia Shuliatikov Date: Thu, 2 Oct 2025 01:15:02 +0200 Subject: [PATCH 3/4] Remove unnecessary using directive --- .../micro/runtime/System.Reflection/RuntimeMethodInfo.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/benchmarks/micro/runtime/System.Reflection/RuntimeMethodInfo.cs b/src/benchmarks/micro/runtime/System.Reflection/RuntimeMethodInfo.cs index ab6752c7e7c..51438c47f65 100644 --- a/src/benchmarks/micro/runtime/System.Reflection/RuntimeMethodInfo.cs +++ b/src/benchmarks/micro/runtime/System.Reflection/RuntimeMethodInfo.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using System.Linq; using System.Reflection.Emit; using BenchmarkDotNet.Attributes; using MicroBenchmarks; From 0f304597a99fd685a8468b3ef75faed52edf872b Mon Sep 17 00:00:00 2001 From: Ilia Shuliatikov Date: Fri, 10 Oct 2025 09:31:45 +0200 Subject: [PATCH 4/4] Change benchmarks to GetHashCode to ensure we don't introduce perf regressions --- .../System.Reflection/RuntimeEventInfo.cs | 54 +++---------------- .../System.Reflection/RuntimeFieldInfo.cs | 45 ++-------------- .../System.Reflection/RuntimeMethodInfo.cs | 45 ++-------------- .../System.Reflection/RuntimePropertyInfo.cs | 45 ++-------------- 4 files changed, 18 insertions(+), 171 deletions(-) diff --git a/src/benchmarks/micro/runtime/System.Reflection/RuntimeEventInfo.cs b/src/benchmarks/micro/runtime/System.Reflection/RuntimeEventInfo.cs index 63c7603103d..3fe5046fcf9 100644 --- a/src/benchmarks/micro/runtime/System.Reflection/RuntimeEventInfo.cs +++ b/src/benchmarks/micro/runtime/System.Reflection/RuntimeEventInfo.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Collections.Generic; -using System.Reflection.Emit; using BenchmarkDotNet.Attributes; using MicroBenchmarks; @@ -12,58 +10,18 @@ namespace System.Reflection [BenchmarkCategory(Categories.Runtime, Categories.Reflection)] public class RuntimeEventInfo { - private const int Iterations = 1200; - private readonly List _events = new(Iterations); + private static readonly EventInfo s_eventInfo = typeof(RuntimeEventInfoTestClass).GetEvent(nameof(RuntimeEventInfoTestClass.Event1)); - [GlobalSetup] - public void Setup() + [Benchmark] + public int GetHashCodeBenchmark() { - var baseType = typeof(RuntimeEventInfoTestClass); - var eventsPerType = baseType.GetEvents().Length; - - var assemblyName = new AssemblyName(baseType.Namespace + ".DynamicAssembly"); - var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndCollect); - var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name); - - for (var i = 0; i < Iterations; i += eventsPerType) - { - var typeBuilder = moduleBuilder.DefineType($"RuntimeDerivedClass{i}", TypeAttributes.Public, baseType); - - var derivedType = typeBuilder.CreateType(); - _events.AddRange(derivedType.GetEvents()); - } - } - - [GlobalCleanup] - public void Cleanup() - { - _events.Clear(); - } - - [Benchmark(OperationsPerInvoke = Iterations)] - public HashSet AddToHashSet() - { - var set = new HashSet(); - - for (int i = 0; i < _events.Count; i++) - { - set.Add(_events[i]); - } - - return set; + return s_eventInfo.GetHashCode(); } } public class RuntimeEventInfoTestClass { - public event EventHandler event1; - public event EventHandler event2; - public event EventHandler event3; - - protected virtual void OnEvent1() => event1?.Invoke(this, EventArgs.Empty); - - protected virtual void OnEvent2() => event2?.Invoke(this, EventArgs.Empty); - - protected virtual void OnEvent3() => event3?.Invoke(this, EventArgs.Empty); + public event EventHandler Event1; + protected virtual void OnEvent1() => Event1?.Invoke(this, EventArgs.Empty); } } \ No newline at end of file diff --git a/src/benchmarks/micro/runtime/System.Reflection/RuntimeFieldInfo.cs b/src/benchmarks/micro/runtime/System.Reflection/RuntimeFieldInfo.cs index 8f3d0232125..b69bcdfecdb 100644 --- a/src/benchmarks/micro/runtime/System.Reflection/RuntimeFieldInfo.cs +++ b/src/benchmarks/micro/runtime/System.Reflection/RuntimeFieldInfo.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Collections.Generic; -using System.Reflection.Emit; using BenchmarkDotNet.Attributes; using MicroBenchmarks; @@ -12,52 +10,17 @@ namespace System.Reflection [BenchmarkCategory(Categories.Runtime, Categories.Reflection)] public class RuntimeFieldInfo { - private const int Iterations = 1200; - private readonly List _fields = new(Iterations); + private static readonly FieldInfo s_fieldInfo = typeof(RuntimeFieldInfoTestClass).GetField(nameof(RuntimeFieldInfoTestClass.Field1)); - [GlobalSetup] - public void Setup() + [Benchmark] + public int GetHashCodeBenchmark() { - var baseType = typeof(RuntimeFieldInfoTestClass); - var fieldsPerType = baseType.GetFields().Length; - - var assemblyName = new AssemblyName(baseType.Namespace + ".DynamicAssembly"); - var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndCollect); - var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name); - - for (var i = 0; i < Iterations; i += fieldsPerType) - { - var typeBuilder = moduleBuilder.DefineType($"RuntimeDerivedClass{i}", TypeAttributes.Public, baseType); - - var derivedType = typeBuilder.CreateType(); - _fields.AddRange(derivedType.GetFields()); - } - } - - [GlobalCleanup] - public void Cleanup() - { - _fields.Clear(); - } - - [Benchmark(OperationsPerInvoke = Iterations)] - public HashSet AddToHashSet() - { - var set = new HashSet(); - - for (int i = 0; i < _fields.Count; i++) - { - set.Add(_fields[i]); - } - - return set; + return s_fieldInfo.GetHashCode(); } } public class RuntimeFieldInfoTestClass { public int Field1; - public string Field2; - public DateTime Field3; } } \ No newline at end of file diff --git a/src/benchmarks/micro/runtime/System.Reflection/RuntimeMethodInfo.cs b/src/benchmarks/micro/runtime/System.Reflection/RuntimeMethodInfo.cs index 51438c47f65..239a2cd3d1e 100644 --- a/src/benchmarks/micro/runtime/System.Reflection/RuntimeMethodInfo.cs +++ b/src/benchmarks/micro/runtime/System.Reflection/RuntimeMethodInfo.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Collections.Generic; -using System.Reflection.Emit; using BenchmarkDotNet.Attributes; using MicroBenchmarks; @@ -12,52 +10,17 @@ namespace System.Reflection [BenchmarkCategory(Categories.Runtime, Categories.Reflection)] public class RuntimeMethodInfo { - private const int Iterations = 1200; - private readonly List _methods = new(Iterations); + private static readonly MethodInfo s_methodInfo = typeof(RuntimeMethodInfoTestClass).GetMethod(nameof(RuntimeMethodInfoTestClass.Method1)); - [GlobalSetup] - public void Setup() + [Benchmark] + public int GetHashCodeBenchmark() { - var baseType = typeof(RuntimeMethodInfoTestClass); - var methodsPerType = baseType.GetMethods().Length; - - var assemblyName = new AssemblyName(baseType.Namespace + ".DynamicAssembly"); - var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndCollect); - var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name); - - for (var i = 0; i < Iterations; i += methodsPerType) - { - var typeBuilder = moduleBuilder.DefineType($"RuntimeDerivedClass{i}", TypeAttributes.Public, baseType); - - var derivedType = typeBuilder.CreateType(); - _methods.AddRange(derivedType.GetMethods()); - } - } - - [GlobalCleanup] - public void Cleanup() - { - _methods.Clear(); - } - - [Benchmark(OperationsPerInvoke = Iterations)] - public HashSet AddToHashSet() - { - var set = new HashSet(); - - for (int i = 0; i < _methods.Count; i++) - { - set.Add(_methods[i]); - } - - return set; + return s_methodInfo.GetHashCode(); } } public class RuntimeMethodInfoTestClass { public int Method1() => throw new NotImplementedException(); - public string Method2() => throw new NotImplementedException(); - public DateTime Method3() => throw new NotImplementedException(); } } \ No newline at end of file diff --git a/src/benchmarks/micro/runtime/System.Reflection/RuntimePropertyInfo.cs b/src/benchmarks/micro/runtime/System.Reflection/RuntimePropertyInfo.cs index 89eb6463567..477dbbfdc04 100644 --- a/src/benchmarks/micro/runtime/System.Reflection/RuntimePropertyInfo.cs +++ b/src/benchmarks/micro/runtime/System.Reflection/RuntimePropertyInfo.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Collections.Generic; -using System.Reflection.Emit; using BenchmarkDotNet.Attributes; using MicroBenchmarks; @@ -12,52 +10,17 @@ namespace System.Reflection [BenchmarkCategory(Categories.Runtime, Categories.Reflection)] public class RuntimePropertyInfo { - private const int Iterations = 1200; - private readonly List _properties = new(Iterations); + private static readonly PropertyInfo s_propertyInfo = typeof(RuntimePropertyInfoTestClass).GetProperty(nameof(RuntimePropertyInfoTestClass.Property1)); - [GlobalSetup] - public void Setup() + [Benchmark] + public int GetHashCodeBenchmark() { - var baseType = typeof(RuntimePropertyInfoTestClass); - var propertiesPerType = baseType.GetProperties().Length; - - var assemblyName = new AssemblyName(baseType.Namespace + ".DynamicAssembly"); - var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndCollect); - var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name); - - for (var i = 0; i < Iterations; i += propertiesPerType) - { - var typeBuilder = moduleBuilder.DefineType($"RuntimeDerivedClass{i}", TypeAttributes.Public, baseType); - - var derivedType = typeBuilder.CreateType(); - _properties.AddRange(derivedType.GetProperties()); - } - } - - [GlobalCleanup] - public void Cleanup() - { - _properties.Clear(); - } - - [Benchmark(OperationsPerInvoke = Iterations)] - public HashSet AddToHashSet() - { - var set = new HashSet(); - - for (int i = 0; i < _properties.Count; i++) - { - set.Add(_properties[i]); - } - - return set; + return s_propertyInfo.GetHashCode(); } } public class RuntimePropertyInfoTestClass { public int Property1 { get; set; } - public string Property2 { get; set; } - public DateTime Property3 { get; set; } } } \ No newline at end of file