Skip to content

Commit c3fb7b9

Browse files
authored
Add support for returning unmanaged types from benchmarks (#1739)
- `System.Void*` is not supported as type in C#, so I map to `void*` in GetCorrectCSharpTypeName similarly to regular `void` - `System.Void*` and other pointer types cannot be consumed, so I have to add two Consume functions. I do not mark them as `[PublicAPI]` since this is too would be much liberty from me. - I mark whole autogenerated class as `unsafe` to not introduce special checks for unsafe types when generate code. Hopefully this is accepteable. Closes #1720
1 parent 141ef74 commit c3fb7b9

File tree

4 files changed

+11
-1
lines changed

4 files changed

+11
-1
lines changed

src/BenchmarkDotNet/Engines/Consumer.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ private static readonly HashSet<Type> SupportedTypes
3232
private ulong ulongHolder;
3333
private string stringHolder;
3434
private object objectHolder;
35+
private IntPtr ptrHolder;
3536

3637
[MethodImpl(MethodImplOptions.AggressiveInlining)]
3738
[PublicAPI]
@@ -98,6 +99,12 @@ private static readonly HashSet<Type> SupportedTypes
9899
public void Consume<T>(T objectValue) where T : class // class constraint prevents from boxing structs
99100
=> Volatile.Write(ref objectHolder, objectValue);
100101

102+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
103+
public unsafe void Consume<T>(T* ptrValue) where T: unmanaged => Volatile.Write(ref ptrHolder, (IntPtr)ptrValue);
104+
105+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
106+
public unsafe void Consume(void* ptrValue) => Volatile.Write(ref ptrHolder, (IntPtr)ptrValue);
107+
101108
[MethodImpl(MethodImplOptions.AggressiveInlining)]
102109
public void Consume<T>(in T value)
103110
{

src/BenchmarkDotNet/Extensions/ReflectionExtensions.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ internal static string GetCorrectCSharpTypeName(this Type type, bool includeName
4545

4646
if (type == typeof(void))
4747
return "void";
48+
if (type == typeof(void*))
49+
return "void*";
4850
string prefix = "";
4951
if (!string.IsNullOrEmpty(type.Namespace) && includeNamespace)
5052
prefix += type.Namespace + ".";

src/BenchmarkDotNet/Templates/BenchmarkType.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// the type name must be in sync with WindowsDisassembler.BuildArguments
2-
public class Runnable_$ID$ : global::$WorkloadTypeName$
2+
public unsafe class Runnable_$ID$ : global::$WorkloadTypeName$
33
{
44
public static void Run(BenchmarkDotNet.Engines.IHost host, System.String benchmarkName)
55
{

tests/BenchmarkDotNet.Tests/ReflectionTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public void GetCorrectCSharpTypeNameReturnsCSharpFriendlyTypeName()
2121
CheckCorrectTypeName("System.Tuple<System.Int32, System.Int32>[]", typeof(Tuple<int, int>[]));
2222
CheckCorrectTypeName("System.ValueTuple<System.Int32, System.Int32>[]", typeof(ValueTuple<int, int>[]));
2323
CheckCorrectTypeName("void", typeof(void));
24+
CheckCorrectTypeName("void*", typeof(void*));
2425
CheckCorrectTypeName("System.IEquatable<T>", typeof(IEquatable<>));
2526
CheckCorrectTypeName("BenchmarkDotNet.Tests.ReflectionTests.NestedNonGeneric1.NestedNonGeneric2", typeof(NestedNonGeneric1.NestedNonGeneric2));
2627
CheckCorrectTypeName("BenchmarkDotNet.Tests.ReflectionTests.NestedNonGeneric1.NestedGeneric2<System.Int16, System.Boolean, System.Decimal>",

0 commit comments

Comments
 (0)