Skip to content

Commit 43367bf

Browse files
committed
Call benchmark method directly instead of via delegate.
1 parent bed071f commit 43367bf

File tree

5 files changed

+202
-154
lines changed

5 files changed

+202
-154
lines changed

Diff for: src/BenchmarkDotNet/Code/CodeGenerator.cs

-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ internal static string Generate(BuildPartition buildPartition)
4545
.Replace("$ID$", buildInfo.Id.ToString())
4646
.Replace("$OperationsPerInvoke$", provider.OperationsPerInvoke)
4747
.Replace("$WorkloadTypeName$", provider.WorkloadTypeName)
48-
.Replace("$WorkloadMethodDelegate$", provider.WorkloadMethodDelegate(passArguments))
4948
.Replace("$WorkloadMethodReturnType$", provider.WorkloadMethodReturnTypeName)
5049
.Replace("$WorkloadMethodReturnTypeModifiers$", provider.WorkloadMethodReturnTypeModifiers)
5150
.Replace("$OverheadMethodReturnTypeName$", provider.OverheadMethodReturnTypeName)

Diff for: src/BenchmarkDotNet/Code/DeclarationsProvider.cs

-8
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@ internal abstract class DeclarationsProvider
3636

3737
public virtual string WorkloadMethodReturnTypeName => WorkloadMethodReturnType.GetCorrectCSharpTypeName();
3838

39-
public virtual string WorkloadMethodDelegate(string passArguments) => Descriptor.WorkloadMethod.Name;
40-
4139
public virtual string WorkloadMethodReturnTypeModifiers => null;
4240

4341
public virtual string GetWorkloadMethodCall(string passArguments) => $"{Descriptor.WorkloadMethod.Name}({passArguments})";
@@ -151,9 +149,6 @@ public TaskDeclarationsProvider(Descriptor descriptor) : base(descriptor) { }
151149

152150
// we use GetAwaiter().GetResult() because it's fastest way to obtain the result in blocking way,
153151
// and will eventually throw actual exception, not aggregated one
154-
public override string WorkloadMethodDelegate(string passArguments)
155-
=> $"({passArguments}) => {{ {Descriptor.WorkloadMethod.Name}({passArguments}).GetAwaiter().GetResult(); }}";
156-
157152
public override string GetWorkloadMethodCall(string passArguments) => $"{Descriptor.WorkloadMethod.Name}({passArguments}).GetAwaiter().GetResult()";
158153

159154
protected override Type WorkloadMethodReturnType => typeof(void);
@@ -170,9 +165,6 @@ public GenericTaskDeclarationsProvider(Descriptor descriptor) : base(descriptor)
170165

171166
// we use GetAwaiter().GetResult() because it's fastest way to obtain the result in blocking way,
172167
// and will eventually throw actual exception, not aggregated one
173-
public override string WorkloadMethodDelegate(string passArguments)
174-
=> $"({passArguments}) => {{ return {Descriptor.WorkloadMethod.Name}({passArguments}).GetAwaiter().GetResult(); }}";
175-
176168
public override string GetWorkloadMethodCall(string passArguments) => $"{Descriptor.WorkloadMethod.Name}({passArguments}).GetAwaiter().GetResult()";
177169
}
178170
}

Diff for: src/BenchmarkDotNet/Templates/BenchmarkType.txt

+86-29
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 unsafe class Runnable_$ID$ : global::$WorkloadTypeName$
2+
public unsafe sealed class Runnable_$ID$ : global::$WorkloadTypeName$
33
{
44
public static void Run(BenchmarkDotNet.Engines.IHost host, System.String benchmarkName)
55
{
@@ -51,27 +51,19 @@
5151
}
5252
}
5353

54-
public delegate $OverheadMethodReturnTypeName$ OverheadDelegate($ArgumentsDefinition$);
55-
56-
public delegate $WorkloadMethodReturnTypeModifiers$ $WorkloadMethodReturnType$ WorkloadDelegate($ArgumentsDefinition$);
57-
5854
public Runnable_$ID$()
5955
{
6056
globalSetupAction = $GlobalSetupMethodName$;
6157
globalCleanupAction = $GlobalCleanupMethodName$;
6258
iterationSetupAction = $IterationSetupMethodName$;
6359
iterationCleanupAction = $IterationCleanupMethodName$;
64-
overheadDelegate = __Overhead;
65-
workloadDelegate = $WorkloadMethodDelegate$;
6660
$InitializeArgumentFields$
6761
}
6862

6963
private System.Action globalSetupAction;
7064
private System.Action globalCleanupAction;
7165
private System.Action iterationSetupAction;
7266
private System.Action iterationCleanupAction;
73-
private BenchmarkDotNet.Autogenerated.Runnable_$ID$.OverheadDelegate overheadDelegate;
74-
private BenchmarkDotNet.Autogenerated.Runnable_$ID$.WorkloadDelegate workloadDelegate;
7567
$DeclareArgumentFields$
7668

7769
// this method is used only for the disassembly diagnoser purposes
@@ -111,6 +103,19 @@
111103

112104
#if RETURNS_CONSUMABLE_$ID$
113105

106+
// Prevent inlining the method invoke.
107+
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining | System.Runtime.CompilerServices.MethodImplOptions.NoOptimization)]
108+
private $OverheadMethodReturnTypeName$ __OverheadWrapper($ArgumentsDefinition$)
109+
{
110+
return __Overhead($PassArguments$);
111+
}
112+
113+
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining | System.Runtime.CompilerServices.MethodImplOptions.NoOptimization)]
114+
private $WorkloadMethodReturnType$ __WorkloadWrapper($ArgumentsDefinition$)
115+
{
116+
return $WorkloadMethodCall$;
117+
}
118+
114119
private BenchmarkDotNet.Engines.Consumer consumer = new BenchmarkDotNet.Engines.Consumer();
115120

116121
#if NETCOREAPP3_0_OR_GREATER
@@ -121,7 +126,7 @@
121126
$LoadArguments$
122127
for (System.Int64 i = 0; i < invokeCount; i++)
123128
{
124-
consumer.Consume(overheadDelegate($PassArguments$));@Unroll@
129+
consumer.Consume(__OverheadWrapper($PassArguments$));@Unroll@
125130
}
126131
}
127132

@@ -133,7 +138,7 @@
133138
$LoadArguments$
134139
for (System.Int64 i = 0; i < invokeCount; i++)
135140
{
136-
consumer.Consume(overheadDelegate($PassArguments$));
141+
consumer.Consume(__OverheadWrapper($PassArguments$));
137142
}
138143
}
139144

@@ -145,7 +150,7 @@
145150
$LoadArguments$
146151
for (System.Int64 i = 0; i < invokeCount; i++)
147152
{
148-
consumer.Consume(workloadDelegate($PassArguments$)$ConsumeField$);@Unroll@
153+
consumer.Consume(__WorkloadWrapper($PassArguments$)$ConsumeField$);@Unroll@
149154
}
150155
}
151156

@@ -157,7 +162,7 @@
157162
$LoadArguments$
158163
for (System.Int64 i = 0; i < invokeCount; i++)
159164
{
160-
consumer.Consume(workloadDelegate($PassArguments$)$ConsumeField$);
165+
consumer.Consume(__WorkloadWrapper($PassArguments$)$ConsumeField$);
161166
}
162167
}
163168

@@ -175,6 +180,19 @@
175180

176181
#elif RETURNS_NON_CONSUMABLE_STRUCT_$ID$
177182

183+
// Prevent inlining the method invoke.
184+
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining | System.Runtime.CompilerServices.MethodImplOptions.NoOptimization)]
185+
private $OverheadMethodReturnTypeName$ __OverheadWrapper($ArgumentsDefinition$)
186+
{
187+
return __Overhead($PassArguments$);
188+
}
189+
190+
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining | System.Runtime.CompilerServices.MethodImplOptions.NoOptimization)]
191+
private $WorkloadMethodReturnType$ __WorkloadWrapper($ArgumentsDefinition$)
192+
{
193+
return $WorkloadMethodCall$;
194+
}
195+
178196
#if NETCOREAPP3_0_OR_GREATER
179197
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveOptimization)]
180198
#endif
@@ -184,7 +202,7 @@
184202
$OverheadMethodReturnTypeName$ result = default($OverheadMethodReturnTypeName$);
185203
for (System.Int64 i = 0; i < invokeCount; i++)
186204
{
187-
result = overheadDelegate($PassArguments$);@Unroll@
205+
result = __OverheadWrapper($PassArguments$);@Unroll@
188206
}
189207
BenchmarkDotNet.Engines.DeadCodeEliminationHelper.KeepAliveWithoutBoxing(result);
190208
}
@@ -198,7 +216,7 @@
198216
$OverheadMethodReturnTypeName$ result = default($OverheadMethodReturnTypeName$);
199217
for (System.Int64 i = 0; i < invokeCount; i++)
200218
{
201-
result = overheadDelegate($PassArguments$);
219+
result = __OverheadWrapper($PassArguments$);
202220
}
203221
BenchmarkDotNet.Engines.DeadCodeEliminationHelper.KeepAliveWithoutBoxing(result);
204222
}
@@ -212,7 +230,7 @@
212230
$WorkloadMethodReturnType$ result = default($WorkloadMethodReturnType$);
213231
for (System.Int64 i = 0; i < invokeCount; i++)
214232
{
215-
result = workloadDelegate($PassArguments$);@Unroll@
233+
result = __WorkloadWrapper($PassArguments$);@Unroll@
216234
}
217235
NonGenericKeepAliveWithoutBoxing(result);
218236
}
@@ -226,7 +244,7 @@
226244
$WorkloadMethodReturnType$ result = default($WorkloadMethodReturnType$);
227245
for (System.Int64 i = 0; i < invokeCount; i++)
228246
{
229-
result = workloadDelegate($PassArguments$);
247+
result = __WorkloadWrapper($PassArguments$);
230248
}
231249
NonGenericKeepAliveWithoutBoxing(result);
232250
}
@@ -250,6 +268,19 @@
250268

251269
#elif RETURNS_BYREF_$ID$
252270

271+
// Prevent inlining the method invoke.
272+
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining | System.Runtime.CompilerServices.MethodImplOptions.NoOptimization)]
273+
private $OverheadMethodReturnTypeName$ __OverheadWrapper($ArgumentsDefinition$)
274+
{
275+
return __Overhead($PassArguments$);
276+
}
277+
278+
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining | System.Runtime.CompilerServices.MethodImplOptions.NoOptimization)]
279+
private ref $WorkloadMethodReturnType$ __WorkloadWrapper($ArgumentsDefinition$)
280+
{
281+
return ref $WorkloadMethodCall$;
282+
}
283+
253284
#if NETCOREAPP3_0_OR_GREATER
254285
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveOptimization)]
255286
#endif
@@ -259,7 +290,7 @@
259290
$OverheadMethodReturnTypeName$ value = default($OverheadMethodReturnTypeName$);
260291
for (System.Int64 i = 0; i < invokeCount; i++)
261292
{
262-
value = overheadDelegate($PassArguments$);@Unroll@
293+
value = __OverheadWrapper($PassArguments$);@Unroll@
263294
}
264295
BenchmarkDotNet.Engines.DeadCodeEliminationHelper.KeepAliveWithoutBoxing(value);
265296
}
@@ -273,7 +304,7 @@
273304
$OverheadMethodReturnTypeName$ value = default($OverheadMethodReturnTypeName$);
274305
for (System.Int64 i = 0; i < invokeCount; i++)
275306
{
276-
value = overheadDelegate($PassArguments$);
307+
value = __OverheadWrapper($PassArguments$);
277308
}
278309
BenchmarkDotNet.Engines.DeadCodeEliminationHelper.KeepAliveWithoutBoxing(value);
279310
}
@@ -289,7 +320,7 @@
289320
ref $WorkloadMethodReturnType$ alias = ref workloadDefaultValueHolder;
290321
for (System.Int64 i = 0; i < invokeCount; i++)
291322
{
292-
alias = workloadDelegate($PassArguments$);@Unroll@
323+
alias = __WorkloadWrapper($PassArguments$);@Unroll@
293324
}
294325
BenchmarkDotNet.Engines.DeadCodeEliminationHelper.KeepAliveWithoutBoxing(ref alias);
295326
}
@@ -303,7 +334,7 @@
303334
ref $WorkloadMethodReturnType$ alias = ref workloadDefaultValueHolder;
304335
for (System.Int64 i = 0; i < invokeCount; i++)
305336
{
306-
alias = workloadDelegate($PassArguments$);
337+
alias = __WorkloadWrapper($PassArguments$);
307338
}
308339
BenchmarkDotNet.Engines.DeadCodeEliminationHelper.KeepAliveWithoutBoxing(ref alias);
309340
}
@@ -321,6 +352,19 @@
321352
}
322353
#elif RETURNS_BYREF_READONLY_$ID$
323354

355+
// Prevent inlining the method invoke.
356+
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining | System.Runtime.CompilerServices.MethodImplOptions.NoOptimization)]
357+
private $OverheadMethodReturnTypeName$ __OverheadWrapper($ArgumentsDefinition$)
358+
{
359+
return __Overhead($PassArguments$);
360+
}
361+
362+
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining | System.Runtime.CompilerServices.MethodImplOptions.NoOptimization)]
363+
private ref readonly $WorkloadMethodReturnType$ __WorkloadWrapper($ArgumentsDefinition$)
364+
{
365+
return ref $WorkloadMethodCall$;
366+
}
367+
324368
#if NETCOREAPP3_0_OR_GREATER
325369
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveOptimization)]
326370
#endif
@@ -330,7 +374,7 @@
330374
$OverheadMethodReturnTypeName$ value = default($OverheadMethodReturnTypeName$);
331375
for (System.Int64 i = 0; i < invokeCount; i++)
332376
{
333-
value = overheadDelegate($PassArguments$);@Unroll@
377+
value = __OverheadWrapper($PassArguments$);@Unroll@
334378
}
335379
BenchmarkDotNet.Engines.DeadCodeEliminationHelper.KeepAliveWithoutBoxing(value);
336380
}
@@ -344,7 +388,7 @@
344388
$OverheadMethodReturnTypeName$ value = default($OverheadMethodReturnTypeName$);
345389
for (System.Int64 i = 0; i < invokeCount; i++)
346390
{
347-
value = overheadDelegate($PassArguments$);
391+
value = __OverheadWrapper($PassArguments$);
348392
}
349393
BenchmarkDotNet.Engines.DeadCodeEliminationHelper.KeepAliveWithoutBoxing(value);
350394
}
@@ -360,7 +404,7 @@
360404
ref $WorkloadMethodReturnType$ alias = ref workloadDefaultValueHolder;
361405
for (System.Int64 i = 0; i < invokeCount; i++)
362406
{
363-
alias = workloadDelegate($PassArguments$);@Unroll@
407+
alias = __WorkloadWrapper($PassArguments$);@Unroll@
364408
}
365409
BenchmarkDotNet.Engines.DeadCodeEliminationHelper.KeepAliveWithoutBoxingReadonly(alias);
366410
}
@@ -374,7 +418,7 @@
374418
ref $WorkloadMethodReturnType$ alias = ref workloadDefaultValueHolder;
375419
for (System.Int64 i = 0; i < invokeCount; i++)
376420
{
377-
alias = workloadDelegate($PassArguments$);
421+
alias = __WorkloadWrapper($PassArguments$);
378422
}
379423
BenchmarkDotNet.Engines.DeadCodeEliminationHelper.KeepAliveWithoutBoxingReadonly(alias);
380424
}
@@ -392,6 +436,19 @@
392436
}
393437
#elif RETURNS_VOID_$ID$
394438

439+
// Prevent inlining the method invoke.
440+
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining | System.Runtime.CompilerServices.MethodImplOptions.NoOptimization)]
441+
private void __OverheadWrapper($ArgumentsDefinition$)
442+
{
443+
__Overhead($PassArguments$);
444+
}
445+
446+
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining | System.Runtime.CompilerServices.MethodImplOptions.NoOptimization)]
447+
private void __WorkloadWrapper($ArgumentsDefinition$)
448+
{
449+
$WorkloadMethodCall$;
450+
}
451+
395452
#if NETCOREAPP3_0_OR_GREATER
396453
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveOptimization)]
397454
#endif
@@ -400,7 +457,7 @@
400457
$LoadArguments$
401458
for (System.Int64 i = 0; i < invokeCount; i++)
402459
{
403-
overheadDelegate($PassArguments$);@Unroll@
460+
__OverheadWrapper($PassArguments$);@Unroll@
404461
}
405462
}
406463

@@ -412,7 +469,7 @@
412469
$LoadArguments$
413470
for (System.Int64 i = 0; i < invokeCount; i++)
414471
{
415-
overheadDelegate($PassArguments$);
472+
__OverheadWrapper($PassArguments$);
416473
}
417474
}
418475

@@ -424,7 +481,7 @@
424481
$LoadArguments$
425482
for (System.Int64 i = 0; i < invokeCount; i++)
426483
{
427-
workloadDelegate($PassArguments$);@Unroll@
484+
__WorkloadWrapper($PassArguments$);@Unroll@
428485
}
429486
}
430487

@@ -436,7 +493,7 @@
436493
$LoadArguments$
437494
for (System.Int64 i = 0; i < invokeCount; i++)
438495
{
439-
workloadDelegate($PassArguments$);
496+
__WorkloadWrapper($PassArguments$);
440497
}
441498
}
442499

0 commit comments

Comments
 (0)