Skip to content

Commit c51c486

Browse files
committed
Added missing ValueTask (non-generic) to InProcess (no emit) toolchains.
1 parent 43138da commit c51c486

File tree

3 files changed

+205
-21
lines changed

3 files changed

+205
-21
lines changed

src/BenchmarkDotNet/Toolchains/InProcess/NoEmit/BenchmarkActionFactory.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ private static BenchmarkAction CreateCore(
3232
if (resultType == typeof(Task))
3333
return new BenchmarkActionTask(resultInstance, targetMethod, unrollFactor);
3434

35+
if (resultType == typeof(ValueTask))
36+
return new BenchmarkActionValueTask(resultInstance, targetMethod, unrollFactor);
37+
3538
if (resultType.GetTypeInfo().IsGenericType)
3639
{
3740
var genericType = resultType.GetGenericTypeDefinition();

src/BenchmarkDotNet/Toolchains/InProcess/NoEmit/BenchmarkActionFactory_Implementations.cs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,45 @@ private void InvokeMultipleHardcoded(long repeatCount)
148148
public override object LastRunResult => result;
149149
}
150150

151+
internal class BenchmarkActionValueTask : BenchmarkActionBase
152+
{
153+
private readonly Func<ValueTask> startTaskCallback;
154+
private readonly Action callback;
155+
private readonly Action unrolledCallback;
156+
157+
public BenchmarkActionValueTask(object instance, MethodInfo method, int unrollFactor)
158+
{
159+
bool isIdle = method == null;
160+
if (!isIdle)
161+
{
162+
startTaskCallback = CreateWorkload<Func<ValueTask>>(instance, method);
163+
callback = ExecuteBlocking;
164+
}
165+
else
166+
{
167+
callback = Overhead;
168+
}
169+
170+
InvokeSingle = callback;
171+
172+
unrolledCallback = Unroll(callback, unrollFactor);
173+
InvokeMultiple = InvokeMultipleHardcoded;
174+
175+
}
176+
177+
// must be kept in sync with VoidDeclarationsProvider.IdleImplementation
178+
private void Overhead() { }
179+
180+
// must be kept in sync with TaskDeclarationsProvider.TargetMethodDelegate
181+
private void ExecuteBlocking() => Helpers.AwaitHelper.GetResult(startTaskCallback.Invoke());
182+
183+
private void InvokeMultipleHardcoded(long repeatCount)
184+
{
185+
for (long i = 0; i < repeatCount; i++)
186+
unrolledCallback();
187+
}
188+
}
189+
151190
internal class BenchmarkActionValueTask<T> : BenchmarkActionBase
152191
{
153192
private readonly Func<ValueTask<T>> startTaskCallback;

tests/BenchmarkDotNet.IntegrationTests/InProcessTest.cs

Lines changed: 163 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ public InProcessTest(ITestOutputHelper output) : base(output)
4545
[Fact]
4646
public void BenchmarkActionTaskSupported() => TestInvoke(x => x.InvokeOnceTaskAsync(), UnrollFactor, null);
4747

48+
[Fact]
49+
public void BenchmarkActionValueTaskSupported() => TestInvoke(x => x.InvokeOnceValueTaskAsync(), UnrollFactor, null);
50+
4851
[Fact]
4952
public void BenchmarkActionRefTypeSupported() => TestInvoke(x => x.InvokeOnceRefType(), UnrollFactor, StringResult);
5053

@@ -57,6 +60,18 @@ public InProcessTest(ITestOutputHelper output) : base(output)
5760
[Fact]
5861
public void BenchmarkActionValueTaskOfTSupported() => TestInvoke(x => x.InvokeOnceValueTaskOfT(), UnrollFactor, DecimalResult);
5962

63+
[Fact]
64+
public void BenchmarkActionGlobalSetupTaskSupported() => TestInvokeSetupCleanupTask(x => BenchmarkSetupCleanupTask.GlobalSetup(), UnrollFactor);
65+
66+
[Fact]
67+
public void BenchmarkActionGlobalCleanupTaskSupported() => TestInvokeSetupCleanupTask(x => x.GlobalCleanup(), UnrollFactor);
68+
69+
[Fact]
70+
public void BenchmarkActionGlobalSetupValueTaskSupported() => TestInvokeSetupCleanupValueTask(x => BenchmarkSetupCleanupValueTask.GlobalSetup(), UnrollFactor);
71+
72+
[Fact]
73+
public void BenchmarkActionGlobalCleanupValueTaskSupported() => TestInvokeSetupCleanupValueTask(x => x.GlobalCleanup(), UnrollFactor);
74+
6075
[Fact]
6176
public void BenchmarkDifferentPlatformReturnsValidationError()
6277
{
@@ -83,30 +98,30 @@ private void TestInvoke(Expression<Action<BenchmarkAllCases>> methodCall, int un
8398

8499
// Run mode
85100
var action = BenchmarkActionFactory.CreateWorkload(descriptor, new BenchmarkAllCases(), unrollFactor);
86-
TestInvoke(action, unrollFactor, false, null);
101+
TestInvoke(action, unrollFactor, false, null, ref BenchmarkAllCases.Counter);
87102

88103
// Idle mode
89104
action = BenchmarkActionFactory.CreateOverhead(descriptor, new BenchmarkAllCases(), unrollFactor);
90-
TestInvoke(action, unrollFactor, true, null);
105+
TestInvoke(action, unrollFactor, true, null, ref BenchmarkAllCases.Counter);
91106

92107
// GlobalSetup/GlobalCleanup
93108
action = BenchmarkActionFactory.CreateGlobalSetup(descriptor, new BenchmarkAllCases());
94-
TestInvoke(action, 1, false, null);
109+
TestInvoke(action, 1, false, null, ref BenchmarkAllCases.Counter);
95110
action = BenchmarkActionFactory.CreateGlobalCleanup(descriptor, new BenchmarkAllCases());
96-
TestInvoke(action, 1, false, null);
111+
TestInvoke(action, 1, false, null, ref BenchmarkAllCases.Counter);
97112

98113
// GlobalSetup/GlobalCleanup (empty)
99114
descriptor = new Descriptor(typeof(BenchmarkAllCases), targetMethod);
100115
action = BenchmarkActionFactory.CreateGlobalSetup(descriptor, new BenchmarkAllCases());
101-
TestInvoke(action, unrollFactor, true, null);
116+
TestInvoke(action, unrollFactor, true, null, ref BenchmarkAllCases.Counter);
102117
action = BenchmarkActionFactory.CreateGlobalCleanup(descriptor, new BenchmarkAllCases());
103-
TestInvoke(action, unrollFactor, true, null);
118+
TestInvoke(action, unrollFactor, true, null, ref BenchmarkAllCases.Counter);
104119

105120
// Dummy (just in case something may broke)
106121
action = BenchmarkActionFactory.CreateDummy();
107-
TestInvoke(action, unrollFactor, true, null);
122+
TestInvoke(action, unrollFactor, true, null, ref BenchmarkAllCases.Counter);
108123
action = BenchmarkActionFactory.CreateDummy();
109-
TestInvoke(action, unrollFactor, true, null);
124+
TestInvoke(action, unrollFactor, true, null, ref BenchmarkAllCases.Counter);
110125
}
111126

112127
[AssertionMethod]
@@ -117,7 +132,7 @@ private void TestInvoke<T>(Expression<Func<BenchmarkAllCases, T>> methodCall, in
117132

118133
// Run mode
119134
var action = BenchmarkActionFactory.CreateWorkload(descriptor, new BenchmarkAllCases(), unrollFactor);
120-
TestInvoke(action, unrollFactor, false, expectedResult);
135+
TestInvoke(action, unrollFactor, false, expectedResult, ref BenchmarkAllCases.Counter);
121136

122137
// Idle mode
123138

@@ -126,15 +141,83 @@ private void TestInvoke<T>(Expression<Func<BenchmarkAllCases, T>> methodCall, in
126141
object idleExpected;
127142
if (isValueTask)
128143
idleExpected = GetDefault(typeof(T).GetGenericArguments()[0]);
144+
else if (expectedResult == null || typeof(T) == typeof(Task) || typeof(T) == typeof(ValueTask))
145+
idleExpected = null;
129146
else if (typeof(T).GetTypeInfo().IsValueType)
130147
idleExpected = 0;
131-
else if (expectedResult == null || typeof(T) == typeof(Task))
132-
idleExpected = null;
133148
else
134149
idleExpected = GetDefault(expectedResult.GetType());
135150

136151
action = BenchmarkActionFactory.CreateOverhead(descriptor, new BenchmarkAllCases(), unrollFactor);
137-
TestInvoke(action, unrollFactor, true, idleExpected);
152+
TestInvoke(action, unrollFactor, true, idleExpected, ref BenchmarkAllCases.Counter);
153+
}
154+
155+
[AssertionMethod]
156+
private void TestInvokeSetupCleanupTask(Expression<Func<BenchmarkSetupCleanupTask, Task>> methodCall, int unrollFactor)
157+
{
158+
var targetMethod = ((MethodCallExpression) methodCall.Body).Method;
159+
var descriptor = new Descriptor(typeof(BenchmarkSetupCleanupTask), targetMethod, targetMethod, targetMethod, targetMethod, targetMethod);
160+
161+
// Run mode
162+
var action = BenchmarkActionFactory.CreateWorkload(descriptor, new BenchmarkSetupCleanupTask(), unrollFactor);
163+
TestInvoke(action, unrollFactor, false, null, ref BenchmarkSetupCleanupTask.Counter);
164+
165+
// Idle mode
166+
action = BenchmarkActionFactory.CreateOverhead(descriptor, new BenchmarkSetupCleanupTask(), unrollFactor);
167+
TestInvoke(action, unrollFactor, true, null, ref BenchmarkSetupCleanupTask.Counter);
168+
169+
// GlobalSetup/GlobalCleanup
170+
action = BenchmarkActionFactory.CreateGlobalSetup(descriptor, new BenchmarkSetupCleanupTask());
171+
TestInvoke(action, 1, false, null, ref BenchmarkSetupCleanupTask.Counter);
172+
action = BenchmarkActionFactory.CreateGlobalCleanup(descriptor, new BenchmarkSetupCleanupTask());
173+
TestInvoke(action, 1, false, null, ref BenchmarkSetupCleanupTask.Counter);
174+
175+
// GlobalSetup/GlobalCleanup (empty)
176+
descriptor = new Descriptor(typeof(BenchmarkSetupCleanupTask), targetMethod);
177+
action = BenchmarkActionFactory.CreateGlobalSetup(descriptor, new BenchmarkSetupCleanupTask());
178+
TestInvoke(action, unrollFactor, true, null, ref BenchmarkSetupCleanupTask.Counter);
179+
action = BenchmarkActionFactory.CreateGlobalCleanup(descriptor, new BenchmarkSetupCleanupTask());
180+
TestInvoke(action, unrollFactor, true, null, ref BenchmarkSetupCleanupTask.Counter);
181+
182+
// Dummy (just in case something may broke)
183+
action = BenchmarkActionFactory.CreateDummy();
184+
TestInvoke(action, unrollFactor, true, null, ref BenchmarkSetupCleanupTask.Counter);
185+
action = BenchmarkActionFactory.CreateDummy();
186+
TestInvoke(action, unrollFactor, true, null, ref BenchmarkSetupCleanupTask.Counter);
187+
}
188+
189+
[AssertionMethod]
190+
private void TestInvokeSetupCleanupValueTask(Expression<Func<BenchmarkSetupCleanupValueTask, ValueTask>> methodCall, int unrollFactor)
191+
{
192+
var targetMethod = ((MethodCallExpression) methodCall.Body).Method;
193+
var descriptor = new Descriptor(typeof(BenchmarkSetupCleanupValueTask), targetMethod, targetMethod, targetMethod, targetMethod, targetMethod);
194+
195+
// Run mode
196+
var action = BenchmarkActionFactory.CreateWorkload(descriptor, new BenchmarkSetupCleanupValueTask(), unrollFactor);
197+
TestInvoke(action, unrollFactor, false, null, ref BenchmarkSetupCleanupValueTask.Counter);
198+
199+
// Idle mode
200+
action = BenchmarkActionFactory.CreateOverhead(descriptor, new BenchmarkSetupCleanupValueTask(), unrollFactor);
201+
TestInvoke(action, unrollFactor, true, null, ref BenchmarkSetupCleanupValueTask.Counter);
202+
203+
// GlobalSetup/GlobalCleanup
204+
action = BenchmarkActionFactory.CreateGlobalSetup(descriptor, new BenchmarkSetupCleanupValueTask());
205+
TestInvoke(action, 1, false, null, ref BenchmarkSetupCleanupValueTask.Counter);
206+
action = BenchmarkActionFactory.CreateGlobalCleanup(descriptor, new BenchmarkSetupCleanupValueTask());
207+
TestInvoke(action, 1, false, null, ref BenchmarkSetupCleanupValueTask.Counter);
208+
209+
// GlobalSetup/GlobalCleanup (empty)
210+
descriptor = new Descriptor(typeof(BenchmarkSetupCleanupValueTask), targetMethod);
211+
action = BenchmarkActionFactory.CreateGlobalSetup(descriptor, new BenchmarkSetupCleanupValueTask());
212+
TestInvoke(action, unrollFactor, true, null, ref BenchmarkSetupCleanupValueTask.Counter);
213+
action = BenchmarkActionFactory.CreateGlobalCleanup(descriptor, new BenchmarkSetupCleanupValueTask());
214+
TestInvoke(action, unrollFactor, true, null, ref BenchmarkSetupCleanupValueTask.Counter);
215+
216+
// Dummy (just in case something may broke)
217+
action = BenchmarkActionFactory.CreateDummy();
218+
TestInvoke(action, unrollFactor, true, null, ref BenchmarkSetupCleanupValueTask.Counter);
219+
action = BenchmarkActionFactory.CreateDummy();
220+
TestInvoke(action, unrollFactor, true, null, ref BenchmarkSetupCleanupValueTask.Counter);
138221
}
139222

140223
private static object GetDefault(Type type)
@@ -147,36 +230,36 @@ private static object GetDefault(Type type)
147230
}
148231

149232
[AssertionMethod]
150-
private void TestInvoke(BenchmarkAction benchmarkAction, int unrollFactor, bool isIdle, object expectedResult)
233+
private void TestInvoke(BenchmarkAction benchmarkAction, int unrollFactor, bool isIdle, object expectedResult, ref int counter)
151234
{
152235
try
153236
{
154-
BenchmarkAllCases.Counter = 0;
237+
counter = 0;
155238

156239
if (isIdle)
157240
{
158241
benchmarkAction.InvokeSingle();
159-
Assert.Equal(0, BenchmarkAllCases.Counter);
242+
Assert.Equal(0, counter);
160243
benchmarkAction.InvokeMultiple(0);
161-
Assert.Equal(0, BenchmarkAllCases.Counter);
244+
Assert.Equal(0, counter);
162245
benchmarkAction.InvokeMultiple(11);
163-
Assert.Equal(0, BenchmarkAllCases.Counter);
246+
Assert.Equal(0, counter);
164247
}
165248
else
166249
{
167250
benchmarkAction.InvokeSingle();
168-
Assert.Equal(1, BenchmarkAllCases.Counter);
251+
Assert.Equal(1, counter);
169252
benchmarkAction.InvokeMultiple(0);
170-
Assert.Equal(1, BenchmarkAllCases.Counter);
253+
Assert.Equal(1, counter);
171254
benchmarkAction.InvokeMultiple(11);
172-
Assert.Equal(BenchmarkAllCases.Counter, 1 + unrollFactor * 11);
255+
Assert.Equal(1 + unrollFactor * 11, counter);
173256
}
174257

175258
Assert.Equal(benchmarkAction.LastRunResult, expectedResult);
176259
}
177260
finally
178261
{
179-
BenchmarkAllCases.Counter = 0;
262+
counter = 0;
180263
}
181264
}
182265

@@ -244,6 +327,13 @@ public async Task InvokeOnceTaskAsync()
244327
Interlocked.Increment(ref Counter);
245328
}
246329

330+
[Benchmark]
331+
public async ValueTask InvokeOnceValueTaskAsync()
332+
{
333+
await Task.Yield();
334+
Interlocked.Increment(ref Counter);
335+
}
336+
247337
[Benchmark]
248338
public string InvokeOnceRefType()
249339
{
@@ -273,5 +363,57 @@ public ValueTask<decimal> InvokeOnceValueTaskOfT()
273363
return new ValueTask<decimal>(DecimalResult);
274364
}
275365
}
366+
367+
[UsedImplicitly(ImplicitUseTargetFlags.WithMembers)]
368+
public class BenchmarkSetupCleanupTask
369+
{
370+
public static int Counter;
371+
372+
[GlobalSetup]
373+
public static async Task GlobalSetup()
374+
{
375+
await Task.Yield();
376+
Interlocked.Increment(ref Counter);
377+
}
378+
379+
[GlobalCleanup]
380+
public async Task GlobalCleanup()
381+
{
382+
await Task.Yield();
383+
Interlocked.Increment(ref Counter);
384+
}
385+
386+
[Benchmark]
387+
public void InvokeOnceVoid()
388+
{
389+
Interlocked.Increment(ref Counter);
390+
}
391+
}
392+
393+
[UsedImplicitly(ImplicitUseTargetFlags.WithMembers)]
394+
public class BenchmarkSetupCleanupValueTask
395+
{
396+
public static int Counter;
397+
398+
[GlobalSetup]
399+
public static async ValueTask GlobalSetup()
400+
{
401+
await Task.Yield();
402+
Interlocked.Increment(ref Counter);
403+
}
404+
405+
[GlobalCleanup]
406+
public async ValueTask GlobalCleanup()
407+
{
408+
await Task.Yield();
409+
Interlocked.Increment(ref Counter);
410+
}
411+
412+
[Benchmark]
413+
public void InvokeOnceVoid()
414+
{
415+
Interlocked.Increment(ref Counter);
416+
}
417+
}
276418
}
277419
}

0 commit comments

Comments
 (0)