BenchmarkDotNet
BenchmarkDotNet copied to clipboard
Add grouping by type
Fixes #1164 Fixes #2022
Look at "Update existing tests" and "Update new tests" to see what has changed.
Fixes:
https://github.com/dotnet/BenchmarkDotNet/issues/1164#issue-448217544
Master:
| Type | Method | Mean | Error | StdDev | Ratio |
|----------- |------- |---------:|---------:|---------:|------:|
| Formatting | Old | 15.52 ms | 0.306 ms | 0.017 ms | 1.00 |
| Parsing | Old | 15.54 ms | 1.847 ms | 0.101 ms | 1.00 |
| Formatting | New | 15.48 ms | 2.415 ms | 0.132 ms | 1.00 |
| Parsing | New | 15.49 ms | 1.244 ms | 0.068 ms | 1.00 |
PR:
| Type | Method | Mean | Error | StdDev | Ratio |
|----------- |------- |---------:|---------:|---------:|------:|
| Formatting | Old | 15.46 ms | 0.039 ms | 0.035 ms | 1.00 |
| Formatting | New | 15.62 ms | 0.081 ms | 0.075 ms | 1.01 |
| | | | | | |
| Parsing | Old | 15.59 ms | 0.039 ms | 0.036 ms | 1.00 |
| Parsing | New | 15.54 ms | 0.076 ms | 0.071 ms | 1.00 |
https://github.com/dotnet/BenchmarkDotNet/issues/2022#issue-1279202717
Master:
Type | Method | Pending | Mean | Error | StdDev | LogicalGroup |
------------- |------------- |-------- |---------:|--------:|--------:|------------- |
AsyncAwait | Callback | False | 102.0 ns | 6.09 ns | 1.58 ns | * |
ContinueWith | Callback | False | 102.0 ns | 6.09 ns | 1.58 ns | * |
AsyncAwait | ProtoPromise | False | 202.0 ns | 6.09 ns | 1.58 ns | * |
ContinueWith | ProtoPromise | False | 202.0 ns | 6.09 ns | 1.58 ns | * |
AsyncAwait | RsgPromise | False | 302.0 ns | 6.09 ns | 1.58 ns | * |
ContinueWith | RsgPromise | False | 302.0 ns | 6.09 ns | 1.58 ns | * |
AsyncAwait | Task | False | 402.0 ns | 6.09 ns | 1.58 ns | * |
ContinueWith | Task | False | 402.0 ns | 6.09 ns | 1.58 ns | * |
AsyncAwait | UniTask | False | 502.0 ns | 6.09 ns | 1.58 ns | * |
ContinueWith | UniTask | False | 502.0 ns | 6.09 ns | 1.58 ns | * |
AsyncAwait | ValueTask | False | 602.0 ns | 6.09 ns | 1.58 ns | * |
ContinueWith | ValueTask | False | 602.0 ns | 6.09 ns | 1.58 ns | * |
PR
Type | Method | Pending | Mean | Error | StdDev | LogicalGroup |
------------- |------------- |-------- |---------:|--------:|--------:|------------- |
AsyncAwait | Callback | False | 102.0 ns | 6.09 ns | 1.58 ns | AsyncAwait |
AsyncAwait | ProtoPromise | False | 202.0 ns | 6.09 ns | 1.58 ns | AsyncAwait |
AsyncAwait | RsgPromise | False | 302.0 ns | 6.09 ns | 1.58 ns | AsyncAwait |
AsyncAwait | Task | False | 402.0 ns | 6.09 ns | 1.58 ns | AsyncAwait |
AsyncAwait | UniTask | False | 502.0 ns | 6.09 ns | 1.58 ns | AsyncAwait |
AsyncAwait | ValueTask | False | 602.0 ns | 6.09 ns | 1.58 ns | AsyncAwait |
| | | | | | |
ContinueWith | Callback | False | 102.0 ns | 6.09 ns | 1.58 ns | ContinueWith |
ContinueWith | ProtoPromise | False | 202.0 ns | 6.09 ns | 1.58 ns | ContinueWith |
ContinueWith | RsgPromise | False | 302.0 ns | 6.09 ns | 1.58 ns | ContinueWith |
ContinueWith | Task | False | 402.0 ns | 6.09 ns | 1.58 ns | ContinueWith |
ContinueWith | UniTask | False | 502.0 ns | 6.09 ns | 1.58 ns | ContinueWith |
ContinueWith | ValueTask | False | 602.0 ns | 6.09 ns | 1.58 ns | ContinueWith |
https://github.com/dotnet/BenchmarkDotNet/issues/1864#issuecomment-1001346715
Master
Type | Method | N | Mean | Error | StdDev | LogicalGroup |
---------------------- |---------------- |---- |---------:|--------:|--------:|------------- |
AsyncPending | ProtoPromise_V1 | 100 | 102.0 ns | 6.09 ns | 1.58 ns | * |
AsyncResolved | ProtoPromise_V1 | 100 | 102.0 ns | 6.09 ns | 1.58 ns | * |
AwaitPending | ProtoPromise_V1 | 100 | 102.0 ns | 6.09 ns | 1.58 ns | * |
AwaitResolved | ProtoPromise_V1 | 100 | 102.0 ns | 6.09 ns | 1.58 ns | * |
ContinueWithFromValue | ProtoPromise_V1 | 100 | 102.0 ns | 6.09 ns | 1.58 ns | * |
ContinueWithPending | ProtoPromise_V1 | 100 | 102.0 ns | 6.09 ns | 1.58 ns | * |
ContinueWithResolved | ProtoPromise_V1 | 100 | 102.0 ns | 6.09 ns | 1.58 ns | * |
AsyncPending | ProtoPromise_V2 | 100 | 202.0 ns | 6.09 ns | 1.58 ns | * |
AsyncResolved | ProtoPromise_V2 | 100 | 202.0 ns | 6.09 ns | 1.58 ns | * |
AwaitPending | ProtoPromise_V2 | 100 | 202.0 ns | 6.09 ns | 1.58 ns | * |
AwaitResolved | ProtoPromise_V2 | 100 | 202.0 ns | 6.09 ns | 1.58 ns | * |
ContinueWithFromValue | ProtoPromise_V2 | 100 | 202.0 ns | 6.09 ns | 1.58 ns | * |
ContinueWithPending | ProtoPromise_V2 | 100 | 202.0 ns | 6.09 ns | 1.58 ns | * |
ContinueWithResolved | ProtoPromise_V2 | 100 | 202.0 ns | 6.09 ns | 1.58 ns | * |
PR
Type | Method | N | Mean | Error | StdDev | LogicalGroup |
---------------------- |---------------- |---- |---------:|--------:|--------:|---------------------- |
AsyncPending | ProtoPromise_V1 | 100 | 102.0 ns | 6.09 ns | 1.58 ns | AsyncPending |
AsyncPending | ProtoPromise_V2 | 100 | 202.0 ns | 6.09 ns | 1.58 ns | AsyncPending |
| | | | | | |
AsyncResolved | ProtoPromise_V1 | 100 | 102.0 ns | 6.09 ns | 1.58 ns | AsyncResolved |
AsyncResolved | ProtoPromise_V2 | 100 | 202.0 ns | 6.09 ns | 1.58 ns | AsyncResolved |
| | | | | | |
AwaitPending | ProtoPromise_V1 | 100 | 102.0 ns | 6.09 ns | 1.58 ns | AwaitPending |
AwaitPending | ProtoPromise_V2 | 100 | 202.0 ns | 6.09 ns | 1.58 ns | AwaitPending |
| | | | | | |
AwaitResolved | ProtoPromise_V1 | 100 | 102.0 ns | 6.09 ns | 1.58 ns | AwaitResolved |
AwaitResolved | ProtoPromise_V2 | 100 | 202.0 ns | 6.09 ns | 1.58 ns | AwaitResolved |
| | | | | | |
ContinueWithFromValue | ProtoPromise_V1 | 100 | 102.0 ns | 6.09 ns | 1.58 ns | ContinueWithFromValue |
ContinueWithFromValue | ProtoPromise_V2 | 100 | 202.0 ns | 6.09 ns | 1.58 ns | ContinueWithFromValue |
| | | | | | |
ContinueWithPending | ProtoPromise_V1 | 100 | 102.0 ns | 6.09 ns | 1.58 ns | ContinueWithPending |
ContinueWithPending | ProtoPromise_V2 | 100 | 202.0 ns | 6.09 ns | 1.58 ns | ContinueWithPending |
| | | | | | |
ContinueWithResolved | ProtoPromise_V1 | 100 | 102.0 ns | 6.09 ns | 1.58 ns | ContinueWithResolved |
ContinueWithResolved | ProtoPromise_V2 | 100 | 202.0 ns | 6.09 ns | 1.58 ns | ContinueWithResolved |
https://github.com/dotnet/BenchmarkDotNet/issues/1864#issuecomment-1031364986
Master
Type | Method | Mean | Error | StdDev | LogicalGroup |
--------------------- |----------------- |---------:|--------:|--------:|------------- |
ArrayBenchmarks | Empty | 102.0 ns | 6.09 ns | 1.58 ns | * |
EmptyBenchmarks | EnumerableEmpty | 102.0 ns | 6.09 ns | 1.58 ns | * |
EnumerableBenchmarks | Empty | 102.0 ns | 6.09 ns | 1.58 ns | * |
StringBenchmarks | ConstructorArray | 102.0 ns | 6.09 ns | 1.58 ns | * |
EmptyBenchmarks | ArrayEmpty | 202.0 ns | 6.09 ns | 1.58 ns | * |
StringBenchmarks | ConstructorSpan | 202.0 ns | 6.09 ns | 1.58 ns | * |
PR
Type | Method | Mean | Error | StdDev | LogicalGroup |
--------------------- |----------------- |---------:|--------:|--------:|--------------------- |
ArrayBenchmarks | Empty | 102.0 ns | 6.09 ns | 1.58 ns | ArrayBenchmarks |
| | | | | |
EmptyBenchmarks | EnumerableEmpty | 102.0 ns | 6.09 ns | 1.58 ns | EmptyBenchmarks |
EmptyBenchmarks | ArrayEmpty | 202.0 ns | 6.09 ns | 1.58 ns | EmptyBenchmarks |
| | | | | |
EnumerableBenchmarks | Empty | 102.0 ns | 6.09 ns | 1.58 ns | EnumerableBenchmarks |
| | | | | |
StringBenchmarks | ConstructorArray | 102.0 ns | 6.09 ns | 1.58 ns | StringBenchmarks |
StringBenchmarks | ConstructorSpan | 202.0 ns | 6.09 ns | 1.58 ns | StringBenchmarks |
Tests
Yes, that's a lot of tests, but now it's easy to change the ordering logic as there are a lot of cases covered.
For example, this change produces a better output, but it breaks output for OneBaseline in some test (it starts display baseline numbers instead a question mark):
- if (hasMultipleTypes)
+ if (hasMultipleTypes && explicitRules.IsEmpty())
Question
What is the correct table for this?
[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByMethod)]
[LogicalGroupColumn, CategoriesColumn, BaselineColumn]
[BenchmarkCategory("A")]
[SimpleJob(id: "Job1"), SimpleJob(id: "Job2")]
public class Bench1
{
[Params(10, 20)] public int Param;
[Benchmark(Baseline = true)] public void Foo() { }
[Benchmark] public void Bar() { }
}
[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByMethod)]
[LogicalGroupColumn, CategoriesColumn, BaselineColumn]
[BenchmarkCategory("B")]
public class Bench2
{
[Params(10, 20)] public int Param;
[Benchmark(Baseline = true)] public void Foo() { }
[Benchmark] public void Bar() { }
}
Master/PR output is:
Type | Method | Job | Categories | Param | Mean | Error | StdDev | Ratio | RatioSD | LogicalGroup | Baseline |
------- |------- |----------- |----------- |------ |---------:|--------:|--------:|------:|--------:|--------------------------------- |--------- |
Bench1 | Foo | Job1 | A | 10 | 102.0 ns | 6.09 ns | 1.58 ns | 1.00 | 0.00 | Foo-Bench1-[Param=10]-Job1 | Yes | ^
| | | | | | | | | | | |
Bench1 | Foo | Job2 | A | 10 | 302.0 ns | 6.09 ns | 1.58 ns | 1.00 | 0.00 | Foo-Bench1-[Param=10]-Job2 | Yes |
| | | | | | | | | | | |
Bench1 | Foo | Job1 | A | 20 | 502.0 ns | 6.09 ns | 1.58 ns | 1.00 | 0.00 | Foo-Bench1-[Param=20]-Job1 | Yes | ^
| | | | | | | | | | | |
Bench1 | Foo | Job2 | A | 20 | 702.0 ns | 6.09 ns | 1.58 ns | 1.00 | 0.00 | Foo-Bench1-[Param=20]-Job2 | Yes |
| | | | | | | | | | | |
Bench2 | Foo | DefaultJob | B | 10 | 102.0 ns | 6.09 ns | 1.58 ns | 1.00 | 0.00 | Foo-Bench2-[Param=10]-DefaultJob | Yes | ^
| | | | | | | | | | | |
Bench2 | Foo | DefaultJob | B | 20 | 302.0 ns | 6.09 ns | 1.58 ns | 1.00 | 0.00 | Foo-Bench2-[Param=20]-DefaultJob | Yes | ^
| | | | | | | | | | | |
Bench1 | Bar | Job1 | A | 10 | 202.0 ns | 6.09 ns | 1.58 ns | ? | ? | Bar-Bench1-[Param=10]-Job1 | No | ^
| | | | | | | | | | | |
Bench1 | Bar | Job2 | A | 10 | 402.0 ns | 6.09 ns | 1.58 ns | ? | ? | Bar-Bench1-[Param=10]-Job2 | No |
| | | | | | | | | | | |
Bench1 | Bar | Job1 | A | 20 | 602.0 ns | 6.09 ns | 1.58 ns | ? | ? | Bar-Bench1-[Param=20]-Job1 | No | ^
| | | | | | | | | | | |
Bench1 | Bar | Job2 | A | 20 | 802.0 ns | 6.09 ns | 1.58 ns | ? | ? | Bar-Bench1-[Param=20]-Job2 | No |
| | | | | | | | | | | |
Bench2 | Bar | DefaultJob | B | 10 | 202.0 ns | 6.09 ns | 1.58 ns | ? | ? | Bar-Bench2-[Param=10]-DefaultJob | No | ^
| | | | | | | | | | | |
Bench2 | Bar | DefaultJob | B | 20 | 402.0 ns | 6.09 ns | 1.58 ns | ? | ? | Bar-Bench2-[Param=20]-DefaultJob | No | ^
Question
What is the correct table for this?
Old, wrong answer
If [GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByMethod)] just moves that order in front, and the other defaults remain in the same order, and if we add ByType so the order should be [ByMethod, ByType, ByCategory, ByParams, ByJob], I think it should look like this:
Type | Method | Job | Categories | Param | Mean | Error | StdDev | Ratio | RatioSD | LogicalGroup | Baseline |
------- |------- |----------- |----------- |------ |---------:|--------:|--------:|------:|--------:|--------------------------------- |--------- |
Bench1 | Foo | Job1 | A | 10 | 102.0 ns | 6.09 ns | 1.58 ns | 1.00 | 0.00 | Foo-Bench1-[Param=10]-Job1 | Yes | ^
| | | | | | | | | | | |
Bench1 | Foo | Job2 | A | 10 | 302.0 ns | 6.09 ns | 1.58 ns | 1.00 | 0.00 | Foo-Bench1-[Param=10]-Job2 | Yes |
| | | | | | | | | | | |
Bench1 | Foo | Job1 | A | 20 | 502.0 ns | 6.09 ns | 1.58 ns | 1.00 | 0.00 | Foo-Bench1-[Param=20]-Job1 | Yes | ^
| | | | | | | | | | | |
Bench1 | Foo | Job2 | A | 20 | 702.0 ns | 6.09 ns | 1.58 ns | 1.00 | 0.00 | Foo-Bench1-[Param=20]-Job2 | Yes |
| | | | | | | | | | | |
Bench2 | Foo | DefaultJob | B | 10 | 102.0 ns | 6.09 ns | 1.58 ns | 1.00 | 0.00 | Foo-Bench2-[Param=10]-DefaultJob | Yes | ^
| | | | | | | | | | | |
Bench2 | Foo | DefaultJob | B | 20 | 302.0 ns | 6.09 ns | 1.58 ns | 1.00 | 0.00 | Foo-Bench2-[Param=20]-DefaultJob | Yes | ^
| | | | | | | | | | | |
Bench1 | Bar | Job1 | A | 10 | 202.0 ns | 6.09 ns | 1.58 ns | ? | ? | Bar-Bench1-[Param=10]-Job1 | No | ^
| | | | | | | | | | | |
Bench1 | Bar | Job2 | A | 10 | 402.0 ns | 6.09 ns | 1.58 ns | ? | ? | Bar-Bench1-[Param=10]-Job2 | No |
| | | | | | | | | | | |
Bench1 | Bar | Job1 | A | 20 | 602.0 ns | 6.09 ns | 1.58 ns | ? | ? | Bar-Bench1-[Param=20]-Job1 | No | ^
| | | | | | | | | | | |
Bench1 | Bar | Job2 | A | 20 | 802.0 ns | 6.09 ns | 1.58 ns | ? | ? | Bar-Bench1-[Param=20]-Job2 | No |
| | | | | | | | | | | |
Bench2 | Bar | DefaultJob | B | 10 | 202.0 ns | 6.09 ns | 1.58 ns | ? | ? | Bar-Bench2-[Param=10]-DefaultJob | No | ^
| | | | | | | | | | | |
Bench2 | Bar | DefaultJob | B | 20 | 402.0 ns | 6.09 ns | 1.58 ns | ? | ? | Bar-Bench2-[Param=20]-DefaultJob | No | ^
[Edit] Oh wait, I think I misunderstood the question. Because the [GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByMethod)] could be applied to one Type, and a different [GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByParams)] could be applied to a different type, so how should the table look then?
In that case, I think ByType should always be first, unless the group rule is overridden in the config for the entire run (not per type). And each Type should have its own group rule set, since they can be set individually on each Type.
With that said, I think that table should look like this:
Type | Method | Job | Categories | Param | Mean | Error | StdDev | Ratio | RatioSD | LogicalGroup | Baseline |
------- |------- |----------- |----------- |------ |---------:|--------:|--------:|------:|--------:|--------------------------------- |--------- |
Bench1 | Foo | Job1 | A | 10 | 102.0 ns | 6.09 ns | 1.58 ns | 1.00 | 0.00 | Foo-Bench1-[Param=10]-Job1 | Yes | ^
| | | | | | | | | | | |
Bench1 | Foo | Job2 | A | 10 | 302.0 ns | 6.09 ns | 1.58 ns | 1.00 | 0.00 | Foo-Bench1-[Param=10]-Job2 | Yes |
| | | | | | | | | | | |
Bench1 | Foo | Job1 | A | 20 | 502.0 ns | 6.09 ns | 1.58 ns | 1.00 | 0.00 | Foo-Bench1-[Param=20]-Job1 | Yes | ^
| | | | | | | | | | | |
Bench1 | Foo | Job2 | A | 20 | 702.0 ns | 6.09 ns | 1.58 ns | 1.00 | 0.00 | Foo-Bench1-[Param=20]-Job2 | Yes |
| | | | | | | | | | | |
Bench1 | Bar | Job1 | A | 10 | 202.0 ns | 6.09 ns | 1.58 ns | ? | ? | Bar-Bench1-[Param=10]-Job1 | No | ^
| | | | | | | | | | | |
Bench1 | Bar | Job2 | A | 10 | 402.0 ns | 6.09 ns | 1.58 ns | ? | ? | Bar-Bench1-[Param=10]-Job2 | No |
| | | | | | | | | | | |
Bench1 | Bar | Job1 | A | 20 | 602.0 ns | 6.09 ns | 1.58 ns | ? | ? | Bar-Bench1-[Param=20]-Job1 | No | ^
| | | | | | | | | | | |
Bench1 | Bar | Job2 | A | 20 | 802.0 ns | 6.09 ns | 1.58 ns | ? | ? | Bar-Bench1-[Param=20]-Job2 | No |
| | | | | | | | | | | |
Bench2 | Foo | DefaultJob | B | 10 | 102.0 ns | 6.09 ns | 1.58 ns | 1.00 | 0.00 | Foo-Bench2-[Param=10]-DefaultJob | Yes | ^
| | | | | | | | | | | |
Bench2 | Bar | DefaultJob | B | 10 | 202.0 ns | 6.09 ns | 1.58 ns | ? | ? | Bar-Bench2-[Param=10]-DefaultJob | No | ^
| | | | | | | | | | | |
Bench2 | Foo | DefaultJob | B | 20 | 302.0 ns | 6.09 ns | 1.58 ns | 1.00 | 0.00 | Foo-Bench2-[Param=20]-DefaultJob | Yes | ^
| | | | | | | | | | | |
Bench2 | Bar | DefaultJob | B | 20 | 402.0 ns | 6.09 ns | 1.58 ns | ? | ? | Bar-Bench2-[Param=20]-DefaultJob | No | ^
A follow-up to this may want to add a ByRuntime group rule, which by default should be ordered before ByType.
I don't like that grouping ByMethod groups them into separate groups, but this seems to be the correct behavior:
How the grouping works:
-
Look at the
LogicalGroupcolumn. It shows the keys to sort by (the keys are truncated from the right if ALL keys in the table are the same) -
There is default grouping order:
ByType, ByCategory, ByParams, ByJob, ByMethod -
When we add a grouping manually (
[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByMethod)]) it adds this key to the left. So it turns out that the groups consist of 1 element.
I'm converting it to draft until I figure out why nothing changes due to swapping ByCategory<->ByType
[Edit] There is no difference in order because we always break them into groups if there are multiple types.
I made the most conservative mode. I don't like that there were more groups than I expected (look at the last commit)
assign to @AndreyAkinshin
@YegorStepanov I tried these changes and, while it looks better, there's still some weirdness with the table:
| Type | Method | Pending | Mean | Ratio |
|------------- |------------- |-------- |-----------:|------:|
| AsyncAwait | Callback | False | 358.8 ns | 1.00 |
| AsyncAwait | ProtoPromise | False | 378.7 ns | 1.05 |
| AsyncAwait | RsgPromise | False | NA | ? |
| AsyncAwait | Task | False | 357.7 ns | 1.00 |
| AsyncAwait | UniTask | False | 392.3 ns | 1.09 |
| AsyncAwait | UnityFxAsync | False | 538.7 ns | 1.50 |
| AsyncAwait | ValueTask | False | 522.7 ns | 1.46 |
| ContinueWith | Callback | False | 347.8 ns | 0.97 |
| ContinueWith | ProtoPromise | False | 529.0 ns | 1.47 |
| ContinueWith | RsgPromise | False | 707.7 ns | 1.97 |
| ContinueWith | Task | False | 2,372.0 ns | 6.61 |
| ContinueWith | UniTask | False | 742.5 ns | 2.07 |
| ContinueWith | UnityFxAsync | False | 1,807.4 ns | 5.03 |
| ContinueWith | ValueTask | False | NA | ? |
| | | | | |
| AsyncAwait | Callback | True | 417.9 ns | 1.00 |
| AsyncAwait | ProtoPromise | True | 2,166.3 ns | 5.05 |
| AsyncAwait | RsgPromise | True | NA | ? |
| AsyncAwait | Task | True | 2,710.6 ns | 6.27 |
| AsyncAwait | UniTask | True | 1,910.4 ns | 4.44 |
| AsyncAwait | UnityFxAsync | True | 2,436.0 ns | 5.64 |
| AsyncAwait | ValueTask | True | 3,120.2 ns | 7.26 |
| ContinueWith | Callback | True | 396.3 ns | 0.92 |
| ContinueWith | ProtoPromise | True | 2,380.8 ns | 5.55 |
| ContinueWith | RsgPromise | True | 6,537.0 ns | 15.58 |
| ContinueWith | Task | True | 3,122.0 ns | 7.22 |
| ContinueWith | UniTask | True | 3,172.6 ns | 7.34 |
| ContinueWith | UnityFxAsync | True | 2,749.3 ns | 6.36 |
| ContinueWith | ValueTask | True | NA | ? |
It seems to be grouping the parameter ahead of the type, and the ratio column is not segregated for each type (it's shared for the entire parameter, regardless of type).
public abstract class AsyncBenchmark
{
[Params(true, false)]
public bool Pending;
}
public partial class AsyncAwait : AsyncBenchmark
{
}
public partial class ContinueWith : AsyncBenchmark
{
}