Repository navigation
Expand file tree
/
Copy pathBatchErrorAggregationBenchmarks.cs
More file actions
186 lines (162 loc) · 6.19 KB
/
Copy pathBatchErrorAggregationBenchmarks.cs
File metadata and controls
186 lines (162 loc) · 6.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Columns;
using BenchmarkDotNet.Engines;
using BenchmarkDotNet.Order;
using RequestBatcher.PendingRequests;
namespace RequestBatcher.Benchmarks.InMemory;
/// <summary>
/// Measures error accounting for shared explicit-batch completion.
/// </summary>
[MemoryDiagnoser]
[RankColumn]
[Orderer(SummaryOrderPolicy.FastestToSlowest)]
[SimpleJob(
RunStrategy.Throughput,
launchCount: 2,
warmupCount: 3,
iterationCount: 8,
id: "BatchErrorAggregation")]
[IterationTime(150)]
public class BatchErrorAggregationBenchmarks
{
[Params(10, 1_000)]
public int GroupSize { get; set; }
private Exception _repeatedException = null!;
private Exception[] _repeatedExceptions = [];
private Exception[] _distinctExceptions = [];
private Exception[] _alternatingExceptions = [];
private BatchSubmissionCompletion? _lastCompletion;
private Exception[]? _lastExpectedExceptions;
[GlobalSetup]
public void GlobalSetup()
{
_repeatedException = new BenchmarkBatchException();
_repeatedExceptions = Enumerable.Repeat(_repeatedException, GroupSize).ToArray();
_distinctExceptions = Enumerable.Range(0, GroupSize)
.Select(static _ => (Exception)new BenchmarkBatchException())
.ToArray();
var first = new BenchmarkBatchException();
var second = new BenchmarkBatchException();
_alternatingExceptions = Enumerable.Range(0, GroupSize)
.Select(index => index % 2 == 0 ? first : second)
.ToArray();
}
[Benchmark(Baseline = true, Description = "Success")]
public Task Success()
{
var completion = StartCompletion(expectedExceptions: null);
for (var index = 0; index < GroupSize; index++)
{
completion.CompleteSuccessfully();
}
return completion.Task;
}
[Benchmark(Description = "Repeated same exception")]
public Task RepeatedSameException()
{
var completion = StartCompletion(_repeatedExceptions);
Complete(completion, _repeatedExceptions);
return ObserveFailure(completion);
}
[Benchmark(Description = "Distinct exception references")]
public Task DistinctExceptionReferences()
{
var completion = StartCompletion(_distinctExceptions);
Complete(completion, _distinctExceptions);
return ObserveFailure(completion);
}
[Benchmark(Description = "Alternating exception references")]
public Task AlternatingExceptionReferences()
{
var completion = StartCompletion(_alternatingExceptions);
Complete(completion, _alternatingExceptions);
return ObserveFailure(completion);
}
[Benchmark(Description = "Concurrent repeated same exception")]
public Task ConcurrentRepeatedSameException()
{
var completion = StartCompletion(_repeatedExceptions);
CompleteConcurrently(completion, _repeatedExceptions);
return ObserveFailure(completion);
}
[Benchmark(Description = "Concurrent distinct exception references")]
public Task ConcurrentDistinctExceptionReferences()
{
var completion = StartCompletion(_distinctExceptions);
CompleteConcurrently(completion, _distinctExceptions);
return ObserveFailure(completion);
}
[GlobalCleanup]
public void ValidateCompletion()
{
var completion = _lastCompletion ??
throw new InvalidOperationException("The benchmark did not create a completion.");
if (_lastExpectedExceptions is null)
{
if (!completion.Task.IsCompletedSuccessfully)
{
throw new InvalidOperationException("The success completion did not complete successfully.");
}
}
else
{
ValidateFailure(completion.Task, _lastExpectedExceptions);
}
_lastCompletion = null;
_lastExpectedExceptions = null;
}
private BatchSubmissionCompletion StartCompletion(Exception[]? expectedExceptions)
{
var completion = new BatchSubmissionCompletion(GroupSize, default);
_lastCompletion = completion;
_lastExpectedExceptions = expectedExceptions;
return completion;
}
private static void Complete(BatchSubmissionCompletion completion, Exception[] exceptions)
{
foreach (var exception in exceptions)
{
completion.CompleteWithError(exception);
}
}
private static void CompleteConcurrently(
BatchSubmissionCompletion completion,
Exception[] exceptions)
{
Parallel.For(
0,
exceptions.Length,
index => completion.CompleteWithError(exceptions[index]));
}
private static Task ObserveFailure(BatchSubmissionCompletion completion)
{
// Observe without rethrowing shared exception instances and growing their stack traces across iterations.
if (completion.Task.IsFaulted && completion.Task.Exception is not null)
{
return Task.CompletedTask;
}
throw new InvalidOperationException("The failure completion unexpectedly succeeded.");
}
private static void ValidateFailure(Task completion, Exception[] expectedExceptions)
{
if (!completion.IsFaulted || completion.Exception is not { } aggregate)
{
throw new InvalidOperationException("The failure completion did not fault.");
}
var actualExceptions = new HashSet<Exception>(
aggregate.InnerExceptions,
ReferenceEqualityComparer.Instance);
var expectedDistinctExceptions = new HashSet<Exception>(
expectedExceptions,
ReferenceEqualityComparer.Instance);
if (actualExceptions.Count != expectedDistinctExceptions.Count ||
actualExceptions.Count != aggregate.InnerExceptions.Count ||
!actualExceptions.SetEquals(expectedDistinctExceptions))
{
throw new InvalidOperationException(
$"The completion aggregated {actualExceptions.Count} exception references; " +
$"expected {expectedDistinctExceptions.Count}.");
}
}
private sealed class BenchmarkBatchException : Exception;
}