Skip to content

Commit

Permalink
Call benchmark method directly instead of via delegate.
Browse files Browse the repository at this point in the history
  • Loading branch information
timcassell committed Jun 20, 2023
1 parent bed071f commit 43367bf
Show file tree
Hide file tree
Showing 5 changed files with 202 additions and 154 deletions.
1 change: 0 additions & 1 deletion src/BenchmarkDotNet/Code/CodeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ internal static string Generate(BuildPartition buildPartition)
.Replace("$ID$", buildInfo.Id.ToString())
.Replace("$OperationsPerInvoke$", provider.OperationsPerInvoke)
.Replace("$WorkloadTypeName$", provider.WorkloadTypeName)
.Replace("$WorkloadMethodDelegate$", provider.WorkloadMethodDelegate(passArguments))
.Replace("$WorkloadMethodReturnType$", provider.WorkloadMethodReturnTypeName)
.Replace("$WorkloadMethodReturnTypeModifiers$", provider.WorkloadMethodReturnTypeModifiers)
.Replace("$OverheadMethodReturnTypeName$", provider.OverheadMethodReturnTypeName)
Expand Down
8 changes: 0 additions & 8 deletions src/BenchmarkDotNet/Code/DeclarationsProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ internal abstract class DeclarationsProvider

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

public virtual string WorkloadMethodDelegate(string passArguments) => Descriptor.WorkloadMethod.Name;

public virtual string WorkloadMethodReturnTypeModifiers => null;

public virtual string GetWorkloadMethodCall(string passArguments) => $"{Descriptor.WorkloadMethod.Name}({passArguments})";
Expand Down Expand Up @@ -151,9 +149,6 @@ internal class TaskDeclarationsProvider : VoidDeclarationsProvider

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

public override string GetWorkloadMethodCall(string passArguments) => $"{Descriptor.WorkloadMethod.Name}({passArguments}).GetAwaiter().GetResult()";

protected override Type WorkloadMethodReturnType => typeof(void);
Expand All @@ -170,9 +165,6 @@ internal class GenericTaskDeclarationsProvider : NonVoidDeclarationsProvider

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

public override string GetWorkloadMethodCall(string passArguments) => $"{Descriptor.WorkloadMethod.Name}({passArguments}).GetAwaiter().GetResult()";
}
}
115 changes: 86 additions & 29 deletions src/BenchmarkDotNet/Templates/BenchmarkType.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// the type name must be in sync with WindowsDisassembler.BuildArguments
public unsafe class Runnable_$ID$ : global::$WorkloadTypeName$
public unsafe sealed class Runnable_$ID$ : global::$WorkloadTypeName$
{
public static void Run(BenchmarkDotNet.Engines.IHost host, System.String benchmarkName)
{
Expand Down Expand Up @@ -51,27 +51,19 @@
}
}

public delegate $OverheadMethodReturnTypeName$ OverheadDelegate($ArgumentsDefinition$);

public delegate $WorkloadMethodReturnTypeModifiers$ $WorkloadMethodReturnType$ WorkloadDelegate($ArgumentsDefinition$);

public Runnable_$ID$()
{
globalSetupAction = $GlobalSetupMethodName$;
globalCleanupAction = $GlobalCleanupMethodName$;
iterationSetupAction = $IterationSetupMethodName$;
iterationCleanupAction = $IterationCleanupMethodName$;
overheadDelegate = __Overhead;
workloadDelegate = $WorkloadMethodDelegate$;
$InitializeArgumentFields$
}

private System.Action globalSetupAction;
private System.Action globalCleanupAction;
private System.Action iterationSetupAction;
private System.Action iterationCleanupAction;
private BenchmarkDotNet.Autogenerated.Runnable_$ID$.OverheadDelegate overheadDelegate;
private BenchmarkDotNet.Autogenerated.Runnable_$ID$.WorkloadDelegate workloadDelegate;
$DeclareArgumentFields$

// this method is used only for the disassembly diagnoser purposes
Expand Down Expand Up @@ -111,6 +103,19 @@

#if RETURNS_CONSUMABLE_$ID$

// Prevent inlining the method invoke.
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining | System.Runtime.CompilerServices.MethodImplOptions.NoOptimization)]
private $OverheadMethodReturnTypeName$ __OverheadWrapper($ArgumentsDefinition$)
{
return __Overhead($PassArguments$);
}

[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining | System.Runtime.CompilerServices.MethodImplOptions.NoOptimization)]
private $WorkloadMethodReturnType$ __WorkloadWrapper($ArgumentsDefinition$)
{
return $WorkloadMethodCall$;
}

private BenchmarkDotNet.Engines.Consumer consumer = new BenchmarkDotNet.Engines.Consumer();

#if NETCOREAPP3_0_OR_GREATER
Expand All @@ -121,7 +126,7 @@
$LoadArguments$
for (System.Int64 i = 0; i < invokeCount; i++)
{
consumer.Consume(overheadDelegate($PassArguments$));@Unroll@
consumer.Consume(__OverheadWrapper($PassArguments$));@Unroll@
}
}

Expand All @@ -133,7 +138,7 @@
$LoadArguments$
for (System.Int64 i = 0; i < invokeCount; i++)
{
consumer.Consume(overheadDelegate($PassArguments$));
consumer.Consume(__OverheadWrapper($PassArguments$));
}
}

Expand All @@ -145,7 +150,7 @@
$LoadArguments$
for (System.Int64 i = 0; i < invokeCount; i++)
{
consumer.Consume(workloadDelegate($PassArguments$)$ConsumeField$);@Unroll@
consumer.Consume(__WorkloadWrapper($PassArguments$)$ConsumeField$);@Unroll@
}
}

Expand All @@ -157,7 +162,7 @@
$LoadArguments$
for (System.Int64 i = 0; i < invokeCount; i++)
{
consumer.Consume(workloadDelegate($PassArguments$)$ConsumeField$);
consumer.Consume(__WorkloadWrapper($PassArguments$)$ConsumeField$);
}
}

Expand All @@ -175,6 +180,19 @@

#elif RETURNS_NON_CONSUMABLE_STRUCT_$ID$

// Prevent inlining the method invoke.
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining | System.Runtime.CompilerServices.MethodImplOptions.NoOptimization)]
private $OverheadMethodReturnTypeName$ __OverheadWrapper($ArgumentsDefinition$)
{
return __Overhead($PassArguments$);
}

[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining | System.Runtime.CompilerServices.MethodImplOptions.NoOptimization)]
private $WorkloadMethodReturnType$ __WorkloadWrapper($ArgumentsDefinition$)
{
return $WorkloadMethodCall$;
}

#if NETCOREAPP3_0_OR_GREATER
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveOptimization)]
#endif
Expand All @@ -184,7 +202,7 @@
$OverheadMethodReturnTypeName$ result = default($OverheadMethodReturnTypeName$);
for (System.Int64 i = 0; i < invokeCount; i++)
{
result = overheadDelegate($PassArguments$);@Unroll@
result = __OverheadWrapper($PassArguments$);@Unroll@
}
BenchmarkDotNet.Engines.DeadCodeEliminationHelper.KeepAliveWithoutBoxing(result);
}
Expand All @@ -198,7 +216,7 @@
$OverheadMethodReturnTypeName$ result = default($OverheadMethodReturnTypeName$);
for (System.Int64 i = 0; i < invokeCount; i++)
{
result = overheadDelegate($PassArguments$);
result = __OverheadWrapper($PassArguments$);
}
BenchmarkDotNet.Engines.DeadCodeEliminationHelper.KeepAliveWithoutBoxing(result);
}
Expand All @@ -212,7 +230,7 @@
$WorkloadMethodReturnType$ result = default($WorkloadMethodReturnType$);
for (System.Int64 i = 0; i < invokeCount; i++)
{
result = workloadDelegate($PassArguments$);@Unroll@
result = __WorkloadWrapper($PassArguments$);@Unroll@
}
NonGenericKeepAliveWithoutBoxing(result);
}
Expand All @@ -226,7 +244,7 @@
$WorkloadMethodReturnType$ result = default($WorkloadMethodReturnType$);
for (System.Int64 i = 0; i < invokeCount; i++)
{
result = workloadDelegate($PassArguments$);
result = __WorkloadWrapper($PassArguments$);
}
NonGenericKeepAliveWithoutBoxing(result);
}
Expand All @@ -250,6 +268,19 @@

#elif RETURNS_BYREF_$ID$

// Prevent inlining the method invoke.
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining | System.Runtime.CompilerServices.MethodImplOptions.NoOptimization)]
private $OverheadMethodReturnTypeName$ __OverheadWrapper($ArgumentsDefinition$)
{
return __Overhead($PassArguments$);
}

[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining | System.Runtime.CompilerServices.MethodImplOptions.NoOptimization)]
private ref $WorkloadMethodReturnType$ __WorkloadWrapper($ArgumentsDefinition$)
{
return ref $WorkloadMethodCall$;
}

#if NETCOREAPP3_0_OR_GREATER
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveOptimization)]
#endif
Expand All @@ -259,7 +290,7 @@
$OverheadMethodReturnTypeName$ value = default($OverheadMethodReturnTypeName$);
for (System.Int64 i = 0; i < invokeCount; i++)
{
value = overheadDelegate($PassArguments$);@Unroll@
value = __OverheadWrapper($PassArguments$);@Unroll@
}
BenchmarkDotNet.Engines.DeadCodeEliminationHelper.KeepAliveWithoutBoxing(value);
}
Expand All @@ -273,7 +304,7 @@
$OverheadMethodReturnTypeName$ value = default($OverheadMethodReturnTypeName$);
for (System.Int64 i = 0; i < invokeCount; i++)
{
value = overheadDelegate($PassArguments$);
value = __OverheadWrapper($PassArguments$);
}
BenchmarkDotNet.Engines.DeadCodeEliminationHelper.KeepAliveWithoutBoxing(value);
}
Expand All @@ -289,7 +320,7 @@
ref $WorkloadMethodReturnType$ alias = ref workloadDefaultValueHolder;
for (System.Int64 i = 0; i < invokeCount; i++)
{
alias = workloadDelegate($PassArguments$);@Unroll@
alias = __WorkloadWrapper($PassArguments$);@Unroll@
}
BenchmarkDotNet.Engines.DeadCodeEliminationHelper.KeepAliveWithoutBoxing(ref alias);
}
Expand All @@ -303,7 +334,7 @@
ref $WorkloadMethodReturnType$ alias = ref workloadDefaultValueHolder;
for (System.Int64 i = 0; i < invokeCount; i++)
{
alias = workloadDelegate($PassArguments$);
alias = __WorkloadWrapper($PassArguments$);
}
BenchmarkDotNet.Engines.DeadCodeEliminationHelper.KeepAliveWithoutBoxing(ref alias);
}
Expand All @@ -321,6 +352,19 @@
}
#elif RETURNS_BYREF_READONLY_$ID$

// Prevent inlining the method invoke.
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining | System.Runtime.CompilerServices.MethodImplOptions.NoOptimization)]
private $OverheadMethodReturnTypeName$ __OverheadWrapper($ArgumentsDefinition$)
{
return __Overhead($PassArguments$);
}

[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining | System.Runtime.CompilerServices.MethodImplOptions.NoOptimization)]
private ref readonly $WorkloadMethodReturnType$ __WorkloadWrapper($ArgumentsDefinition$)
{
return ref $WorkloadMethodCall$;
}

#if NETCOREAPP3_0_OR_GREATER
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveOptimization)]
#endif
Expand All @@ -330,7 +374,7 @@
$OverheadMethodReturnTypeName$ value = default($OverheadMethodReturnTypeName$);
for (System.Int64 i = 0; i < invokeCount; i++)
{
value = overheadDelegate($PassArguments$);@Unroll@
value = __OverheadWrapper($PassArguments$);@Unroll@
}
BenchmarkDotNet.Engines.DeadCodeEliminationHelper.KeepAliveWithoutBoxing(value);
}
Expand All @@ -344,7 +388,7 @@
$OverheadMethodReturnTypeName$ value = default($OverheadMethodReturnTypeName$);
for (System.Int64 i = 0; i < invokeCount; i++)
{
value = overheadDelegate($PassArguments$);
value = __OverheadWrapper($PassArguments$);
}
BenchmarkDotNet.Engines.DeadCodeEliminationHelper.KeepAliveWithoutBoxing(value);
}
Expand All @@ -360,7 +404,7 @@
ref $WorkloadMethodReturnType$ alias = ref workloadDefaultValueHolder;
for (System.Int64 i = 0; i < invokeCount; i++)
{
alias = workloadDelegate($PassArguments$);@Unroll@
alias = __WorkloadWrapper($PassArguments$);@Unroll@
}
BenchmarkDotNet.Engines.DeadCodeEliminationHelper.KeepAliveWithoutBoxingReadonly(alias);
}
Expand All @@ -374,7 +418,7 @@
ref $WorkloadMethodReturnType$ alias = ref workloadDefaultValueHolder;
for (System.Int64 i = 0; i < invokeCount; i++)
{
alias = workloadDelegate($PassArguments$);
alias = __WorkloadWrapper($PassArguments$);
}
BenchmarkDotNet.Engines.DeadCodeEliminationHelper.KeepAliveWithoutBoxingReadonly(alias);
}
Expand All @@ -392,6 +436,19 @@
}
#elif RETURNS_VOID_$ID$

// Prevent inlining the method invoke.
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining | System.Runtime.CompilerServices.MethodImplOptions.NoOptimization)]
private void __OverheadWrapper($ArgumentsDefinition$)
{
__Overhead($PassArguments$);
}

[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining | System.Runtime.CompilerServices.MethodImplOptions.NoOptimization)]
private void __WorkloadWrapper($ArgumentsDefinition$)
{
$WorkloadMethodCall$;
}

#if NETCOREAPP3_0_OR_GREATER
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveOptimization)]
#endif
Expand All @@ -400,7 +457,7 @@
$LoadArguments$
for (System.Int64 i = 0; i < invokeCount; i++)
{
overheadDelegate($PassArguments$);@Unroll@
__OverheadWrapper($PassArguments$);@Unroll@
}
}

Expand All @@ -412,7 +469,7 @@
$LoadArguments$
for (System.Int64 i = 0; i < invokeCount; i++)
{
overheadDelegate($PassArguments$);
__OverheadWrapper($PassArguments$);
}
}

Expand All @@ -424,7 +481,7 @@
$LoadArguments$
for (System.Int64 i = 0; i < invokeCount; i++)
{
workloadDelegate($PassArguments$);@Unroll@
__WorkloadWrapper($PassArguments$);@Unroll@
}
}

Expand All @@ -436,7 +493,7 @@
$LoadArguments$
for (System.Int64 i = 0; i < invokeCount; i++)
{
workloadDelegate($PassArguments$);
__WorkloadWrapper($PassArguments$);
}
}

Expand Down

0 comments on commit 43367bf

Please sign in to comment.