1
+ using System ;
2
+ using System . Reflection ;
3
+ using System . Runtime . CompilerServices ;
4
+ using System . Threading . Tasks ;
5
+
6
+ using BenchmarkDotNet . Extensions ;
7
+ using BenchmarkDotNet . Running ;
8
+
9
+ using JetBrains . Annotations ;
10
+
11
+ namespace BenchmarkDotNet . Toolchains . InProcess . NoEmit
12
+ {
13
+ /// <summary>Helper class that creates <see cref="BenchmarkAction"/> instances. </summary>
14
+ public static partial class BenchmarkActionFactory
15
+ {
16
+ /// <summary>
17
+ /// Dispatch method that creates <see cref="BenchmarkAction"/> using
18
+ /// <paramref name="targetMethod"/> or <paramref name="fallbackIdleSignature"/> to find correct implementation.
19
+ /// Either <paramref name="targetMethod"/> or <paramref name="fallbackIdleSignature"/> should be not <c>null</c>.
20
+ /// </summary>
21
+ private static BenchmarkAction CreateCore (
22
+ [ NotNull ] object instance ,
23
+ [ CanBeNull ] MethodInfo targetMethod ,
24
+ [ CanBeNull ] MethodInfo fallbackIdleSignature ,
25
+ int unrollFactor )
26
+ {
27
+ PrepareInstanceAndResultType ( instance , targetMethod , fallbackIdleSignature , out var resultInstance , out var resultType ) ;
28
+
29
+ if ( resultType == typeof ( void ) )
30
+ return new BenchmarkActionVoid ( resultInstance , targetMethod , unrollFactor ) ;
31
+
32
+ if ( resultType == typeof ( Task ) )
33
+ return new BenchmarkActionTask ( resultInstance , targetMethod , unrollFactor ) ;
34
+
35
+ if ( resultType . GetTypeInfo ( ) . IsGenericType )
36
+ {
37
+ var genericType = resultType . GetGenericTypeDefinition ( ) ;
38
+ var argType = resultType . GenericTypeArguments [ 0 ] ;
39
+ if ( typeof ( Task < > ) == genericType )
40
+ return Create (
41
+ typeof ( BenchmarkActionTask < > ) . MakeGenericType ( argType ) ,
42
+ resultInstance ,
43
+ targetMethod ,
44
+ unrollFactor ) ;
45
+
46
+ if ( typeof ( ValueTask < > ) . IsAssignableFrom ( genericType ) )
47
+ return Create (
48
+ typeof ( BenchmarkActionValueTask < > ) . MakeGenericType ( argType ) ,
49
+ resultInstance ,
50
+ targetMethod ,
51
+ unrollFactor ) ;
52
+ }
53
+
54
+ if ( targetMethod == null && resultType . GetTypeInfo ( ) . IsValueType )
55
+ // for Idle: we return int because creating bigger ValueType could take longer than benchmarked method itself.
56
+ resultType = typeof ( int ) ;
57
+
58
+ return Create (
59
+ typeof ( BenchmarkAction < > ) . MakeGenericType ( resultType ) ,
60
+ resultInstance ,
61
+ targetMethod ,
62
+ unrollFactor ) ;
63
+ }
64
+
65
+ private static void PrepareInstanceAndResultType (
66
+ object instance , MethodInfo targetMethod , MethodInfo fallbackIdleSignature ,
67
+ out object resultInstance , out Type resultType )
68
+ {
69
+ var signature = targetMethod ?? fallbackIdleSignature ;
70
+ if ( signature == null )
71
+ throw new ArgumentNullException (
72
+ nameof ( fallbackIdleSignature ) ,
73
+ $ "Either { nameof ( targetMethod ) } or { nameof ( fallbackIdleSignature ) } should be not null.") ;
74
+
75
+ if ( ! signature . IsStatic && instance == null )
76
+ throw new ArgumentNullException (
77
+ nameof ( instance ) ,
78
+ $ "The { nameof ( instance ) } parameter should be not null as invocation method is instance method.") ;
79
+
80
+ resultInstance = signature . IsStatic ? null : instance ;
81
+ resultType = signature . ReturnType ;
82
+
83
+ if ( resultType == typeof ( void ) )
84
+ {
85
+ // DONTTOUCH: async should be checked for target method
86
+ // as fallbackIdleSignature used for result type detection only.
87
+ bool isUsingAsyncKeyword = targetMethod ? . HasAttribute < AsyncStateMachineAttribute > ( ) ?? false ;
88
+ if ( isUsingAsyncKeyword )
89
+ throw new NotSupportedException ( "Async void is not supported by design." ) ;
90
+ }
91
+ }
92
+
93
+ /// <summary>Helper to enforce .ctor signature.</summary>
94
+ private static BenchmarkActionBase Create ( Type actionType , object instance , MethodInfo method , int unrollFactor ) =>
95
+ ( BenchmarkActionBase ) Activator . CreateInstance ( actionType , instance , method , unrollFactor ) ;
96
+
97
+ private static void FallbackMethod ( ) { }
98
+ private static readonly MethodInfo FallbackSignature = new Action ( FallbackMethod ) . GetMethodInfo ( ) ;
99
+ private static readonly MethodInfo DummyMethod = typeof ( DummyInstance ) . GetMethod ( nameof ( DummyInstance . Dummy ) ) ;
100
+
101
+ /// <summary>Creates run benchmark action.</summary>
102
+ /// <param name="descriptor">Descriptor info.</param>
103
+ /// <param name="instance">Instance of target.</param>
104
+ /// <param name="unrollFactor">Unroll factor.</param>
105
+ /// <returns>Run benchmark action.</returns>
106
+ public static BenchmarkAction CreateWorkload ( Descriptor descriptor , object instance , int unrollFactor ) =>
107
+ CreateCore ( instance , descriptor . WorkloadMethod , null , unrollFactor ) ;
108
+
109
+ /// <summary>Creates idle benchmark action.</summary>
110
+ /// <param name="descriptor">Descriptor info.</param>
111
+ /// <param name="instance">Instance of target.</param>
112
+ /// <param name="unrollFactor">Unroll factor.</param>
113
+ /// <returns>Idle benchmark action.</returns>
114
+ public static BenchmarkAction CreateOverhead ( Descriptor descriptor , object instance , int unrollFactor ) =>
115
+ CreateCore ( instance , null , descriptor . WorkloadMethod , unrollFactor ) ;
116
+
117
+ /// <summary>Creates global setup benchmark action.</summary>
118
+ /// <param name="descriptor">Descriptor info.</param>
119
+ /// <param name="instance">Instance of target.</param>
120
+ /// <returns>Setup benchmark action.</returns>
121
+ public static BenchmarkAction CreateGlobalSetup ( Descriptor descriptor , object instance ) =>
122
+ CreateCore ( instance , descriptor . GlobalSetupMethod , FallbackSignature , 1 ) ;
123
+
124
+ /// <summary>Creates global cleanup benchmark action.</summary>
125
+ /// <param name="descriptor">Descriptor info.</param>
126
+ /// <param name="instance">Instance of target.</param>
127
+ /// <returns>Cleanup benchmark action.</returns>
128
+ public static BenchmarkAction CreateGlobalCleanup ( Descriptor descriptor , object instance ) =>
129
+ CreateCore ( instance , descriptor . GlobalCleanupMethod , FallbackSignature , 1 ) ;
130
+
131
+ /// <summary>Creates global setup benchmark action.</summary>
132
+ /// <param name="descriptor">Descriptor info.</param>
133
+ /// <param name="instance">Instance of target.</param>
134
+ /// <returns>Setup benchmark action.</returns>
135
+ public static BenchmarkAction CreateIterationSetup ( Descriptor descriptor , object instance ) =>
136
+ CreateCore ( instance , descriptor . IterationSetupMethod , FallbackSignature , 1 ) ;
137
+
138
+ /// <summary>Creates global cleanup benchmark action.</summary>
139
+ /// <param name="descriptor">Descriptor info.</param>
140
+ /// <param name="instance">Instance of target.</param>
141
+ /// <returns>Cleanup benchmark action.</returns>
142
+ public static BenchmarkAction CreateIterationCleanup ( Descriptor descriptor , object instance ) =>
143
+ CreateCore ( instance , descriptor . IterationCleanupMethod , FallbackSignature , 1 ) ;
144
+
145
+ /// <summary>Creates a dummy benchmark action.</summary>
146
+ /// <returns>Dummy benchmark action.</returns>
147
+ public static BenchmarkAction CreateDummy ( ) =>
148
+ CreateCore ( new DummyInstance ( ) , DummyMethod , null , 1 ) ;
149
+ }
150
+ }
0 commit comments