Skip to content

Commit 974439e

Browse files
committed
Async refactor WIP
1 parent cb5d392 commit 974439e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1532
-869
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using System;
2+
3+
namespace BenchmarkDotNet.Attributes;
4+
5+
/// <summary>
6+
/// When applied to an async benchmark method, overrides the return type of the async method that calls the benchmark method.
7+
/// </summary>
8+
[AttributeUsage(AttributeTargets.Method)]
9+
public sealed class AsyncCallerTypeAttribute(Type asyncCallerType) : Attribute
10+
{
11+
/// <summary>
12+
/// The return type of the async method that calls the benchmark method.
13+
/// </summary>
14+
public Type AsyncCallerType { get; private set; } = asyncCallerType;
15+
}

src/BenchmarkDotNet/Code/CodeGenerator.cs

Lines changed: 24 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -31,29 +31,17 @@ internal static string Generate(BuildPartition buildPartition)
3131
{
3232
var benchmark = buildInfo.BenchmarkCase;
3333

34-
var provider = GetDeclarationsProvider(benchmark.Descriptor);
35-
36-
string passArguments = GetPassArguments(benchmark);
37-
38-
string benchmarkTypeCode = new SmartStringBuilder(ResourceHelper.LoadTemplate("BenchmarkType.txt"))
34+
string benchmarkTypeCode = GetDeclarationsProvider(benchmark)
35+
.ReplaceTemplate(new SmartStringBuilder(ResourceHelper.LoadTemplate("BenchmarkType.txt")))
3936
.Replace("$ID$", buildInfo.Id.ToString())
40-
.Replace("$OperationsPerInvoke$", provider.OperationsPerInvoke)
41-
.Replace("$WorkloadTypeName$", provider.WorkloadTypeName)
42-
.Replace("$GlobalSetupMethodName$", provider.GlobalSetupMethodName)
43-
.Replace("$GlobalCleanupMethodName$", provider.GlobalCleanupMethodName)
44-
.Replace("$IterationSetupMethodName$", provider.IterationSetupMethodName)
45-
.Replace("$IterationCleanupMethodName$", provider.IterationCleanupMethodName)
4637
.Replace("$JobSetDefinition$", GetJobsSetDefinition(benchmark))
4738
.Replace("$ParamsContent$", GetParamsContent(benchmark))
4839
.Replace("$ArgumentsDefinition$", GetArgumentsDefinition(benchmark))
4940
.Replace("$DeclareArgumentFields$", GetDeclareArgumentFields(benchmark))
5041
.Replace("$InitializeArgumentFields$", GetInitializeArgumentFields(benchmark))
51-
.Replace("$LoadArguments$", GetLoadArguments(benchmark))
52-
.Replace("$PassArguments$", passArguments)
5342
.Replace("$EngineFactoryType$", GetEngineFactoryTypeName(benchmark))
5443
.Replace("$RunExtraIteration$", buildInfo.Config.HasExtraIterationDiagnoser(benchmark) ? "true" : "false")
5544
.Replace("$DisassemblerEntryMethodName$", DisassemblerConstants.DisassemblerEntryMethodName)
56-
.Replace("$WorkloadMethodCall$", provider.GetWorkloadMethodCall(passArguments))
5745
.Replace("$InProcessDiagnoserRouters$", GetInProcessDiagnoserRouters(buildInfo))
5846
.ToString();
5947

@@ -122,27 +110,21 @@ private static string GetJobsSetDefinition(BenchmarkCase benchmarkCase)
122110
Replace("; ", ";\n ");
123111
}
124112

125-
private static DeclarationsProvider GetDeclarationsProvider(Descriptor descriptor)
113+
private static DeclarationsProvider GetDeclarationsProvider(BenchmarkCase benchmark)
126114
{
127-
var method = descriptor.WorkloadMethod;
115+
var method = benchmark.Descriptor.WorkloadMethod;
128116

129-
if (method.ReturnType == typeof(Task) || method.ReturnType == typeof(ValueTask))
130-
{
131-
return new AsyncDeclarationsProvider(descriptor);
132-
}
133-
if (method.ReturnType.GetTypeInfo().IsGenericType
134-
&& (method.ReturnType.GetTypeInfo().GetGenericTypeDefinition() == typeof(Task<>)
135-
|| method.ReturnType.GetTypeInfo().GetGenericTypeDefinition() == typeof(ValueTask<>)))
117+
if (method.ReturnType.IsAwaitable())
136118
{
137-
return new AsyncDeclarationsProvider(descriptor);
119+
return new AsyncDeclarationsProvider(benchmark);
138120
}
139121

140122
if (method.ReturnType == typeof(void) && method.HasAttribute<AsyncStateMachineAttribute>())
141123
{
142124
throw new NotSupportedException("async void is not supported by design");
143125
}
144126

145-
return new SyncDeclarationsProvider(descriptor);
127+
return new SyncDeclarationsProvider(benchmark);
146128
}
147129

148130
// internal for tests
@@ -158,31 +140,19 @@ private static string GetArgumentsDefinition(BenchmarkCase benchmarkCase)
158140
=> string.Join(
159141
", ",
160142
benchmarkCase.Descriptor.WorkloadMethod.GetParameters()
161-
.Select((parameter, index) => $"{GetParameterModifier(parameter)} {parameter.ParameterType.GetCorrectCSharpTypeName()} arg{index}"));
143+
.Select((parameter, index) => $"{GetParameterModifier(parameter)} {parameter.ParameterType.GetCorrectCSharpTypeName()} arg{index}"));
162144

163145
private static string GetDeclareArgumentFields(BenchmarkCase benchmarkCase)
164146
=> string.Join(
165147
Environment.NewLine,
166148
benchmarkCase.Descriptor.WorkloadMethod.GetParameters()
167-
.Select((parameter, index) => $"private {GetFieldType(parameter.ParameterType, benchmarkCase.Parameters.GetArgument(parameter.Name)).GetCorrectCSharpTypeName()} __argField{index};"));
149+
.Select((parameter, index) => $"public {GetFieldType(parameter.ParameterType, benchmarkCase.Parameters.GetArgument(parameter.Name)).GetCorrectCSharpTypeName()} __argField{index};"));
168150

169151
private static string GetInitializeArgumentFields(BenchmarkCase benchmarkCase)
170152
=> string.Join(
171153
Environment.NewLine,
172154
benchmarkCase.Descriptor.WorkloadMethod.GetParameters()
173-
.Select((parameter, index) => $"this.__argField{index} = {benchmarkCase.Parameters.GetArgument(parameter.Name).ToSourceCode()};")); // we init the fields in ctor to provoke all possible allocations and overhead of other type
174-
175-
private static string GetLoadArguments(BenchmarkCase benchmarkCase)
176-
=> string.Join(
177-
Environment.NewLine,
178-
benchmarkCase.Descriptor.WorkloadMethod.GetParameters()
179-
.Select((parameter, index) => $"{(parameter.ParameterType.IsByRef ? "ref" : string.Empty)} {parameter.ParameterType.GetCorrectCSharpTypeName()} arg{index} = {(parameter.ParameterType.IsByRef ? "ref" : string.Empty)} this.__argField{index};"));
180-
181-
private static string GetPassArguments(BenchmarkCase benchmarkCase)
182-
=> string.Join(
183-
", ",
184-
benchmarkCase.Descriptor.WorkloadMethod.GetParameters()
185-
.Select((parameter, index) => $"{GetParameterModifier(parameter)} arg{index}"));
155+
.Select((parameter, index) => $"this.__fieldsContainer.__argField{index} = {benchmarkCase.Parameters.GetArgument(parameter.Name).ToSourceCode()};")); // we init the fields in ctor to provoke all possible allocations and overhead of other type
186156

187157
private static string GetExtraAttributes(BuildPartition buildPartition)
188158
{
@@ -236,7 +206,7 @@ private static string GetInProcessDiagnoserRouters(BenchmarkBuildInfo buildInfo)
236206
}
237207
}
238208

239-
private static string GetParameterModifier(ParameterInfo parameterInfo)
209+
internal static string GetParameterModifier(ParameterInfo parameterInfo)
240210
{
241211
if (!parameterInfo.ParameterType.IsByRef)
242212
return string.Empty;
@@ -260,28 +230,21 @@ private static Type GetFieldType(Type argumentType, ParameterInstance argument)
260230

261231
return argumentType;
262232
}
233+
}
263234

264-
private class SmartStringBuilder
265-
{
266-
private readonly string originalText;
267-
private readonly StringBuilder builder;
268-
269-
public SmartStringBuilder(string text)
270-
{
271-
originalText = text;
272-
builder = new StringBuilder(text);
273-
}
274-
275-
public SmartStringBuilder Replace(string oldValue, string? newValue)
276-
{
277-
if (originalText.Contains(oldValue))
278-
builder.Replace(oldValue, newValue);
279-
else
280-
builder.Append($"\n// '{oldValue}' not found");
281-
return this;
282-
}
235+
internal class SmartStringBuilder(string text)
236+
{
237+
private readonly StringBuilder builder = new(text);
283238

284-
public override string ToString() => builder.ToString();
239+
public SmartStringBuilder Replace(string oldValue, string? newValue)
240+
{
241+
if (text.Contains(oldValue))
242+
builder.Replace(oldValue, newValue);
243+
else
244+
builder.Append($"\n// '{oldValue}' not found");
245+
return this;
285246
}
247+
248+
public override string ToString() => builder.ToString();
286249
}
287250
}

0 commit comments

Comments
 (0)