Skip to content

Commit 7f5de93

Browse files
committed
bench: improve init mechanism
1 parent 14a9aa3 commit 7f5de93

File tree

4 files changed

+191
-131
lines changed

4 files changed

+191
-131
lines changed

src/RESPite.Benchmark/BenchmarkBase.cs

Lines changed: 105 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Collections.Generic;
44
using System.ComponentModel;
55
using System.Diagnostics;
6+
using System.Linq;
67
using System.Reflection;
78
using System.Threading;
89
using System.Threading.Tasks;
@@ -21,12 +22,6 @@ protected const string
2122
SortedSetKey = "myzset",
2223
StreamKey = "mystream";
2324

24-
// how many elements to add for the LRANGE tests
25-
protected const int ListElements = 650;
26-
27-
// how many elements to add for the ZPOPMIN tests
28-
protected const int SortedSetElements = 650;
29-
3025
public PipelineStrategy PipelineMode { get; } =
3126
PipelineStrategy.Batch; // the default, for parity with how redis-benchmark works
3227

@@ -53,9 +48,10 @@ public enum PipelineStrategy
5348
public bool Loop { get; }
5449
public bool Quiet { get; }
5550
public int ClientCount { get; } = 50;
56-
public int OperationsPerClient { get; }
51+
private int _operationsPerClient;
52+
public int OperationsPerClient(int divisor = 1) => _operationsPerClient / divisor;
5753

58-
public int TotalOperations => OperationsPerClient * ClientCount;
54+
public int TotalOperations(int divisor = 1) => OperationsPerClient(divisor) * ClientCount;
5955

6056
protected readonly byte[] Payload;
6157

@@ -119,7 +115,7 @@ protected BenchmarkBase(string[] args)
119115
}
120116
}
121117

122-
OperationsPerClient = operations / ClientCount;
118+
_operationsPerClient = operations / ClientCount;
123119

124120
Payload = "abc"u8.ToArray();
125121
}
@@ -184,9 +180,10 @@ protected virtual void PrepareBatch(TClient client, int count) { }
184180

185181
private async Task<DBNull> PipelineUntyped(
186182
TClient client,
187-
Func<TClient, ValueTask> operation)
183+
Func<TClient, ValueTask> operation,
184+
int divisor)
188185
{
189-
var opsPerClient = OperationsPerClient;
186+
var opsPerClient = OperationsPerClient(divisor);
190187
int i = 0;
191188
try
192189
{
@@ -258,9 +255,9 @@ private async Task<DBNull> PipelineUntyped(
258255
return DBNull.Value;
259256
}
260257

261-
private async Task<T> PipelineTyped<T>(TClient client, Func<TClient, ValueTask<T>> operation)
258+
private async Task<T> PipelineTyped<T>(TClient client, Func<TClient, ValueTask<T>> operation, int divisor)
262259
{
263-
var opsPerClient = OperationsPerClient;
260+
var opsPerClient = OperationsPerClient(divisor);
264261
int i = 0;
265262
T result = default!;
266263
try
@@ -350,31 +347,62 @@ public async Task InitAsync()
350347
protected Task RunAsync<T>(
351348
string? key,
352349
Func<TClient, ValueTask<T>> action,
353-
Func<TClient, ValueTask>? init = null,
354-
string format = "")
350+
bool deleteKey,
351+
int divisor = 1)
355352
=> RunAsyncCore<T>(
356353
key,
357-
action,
354+
GetNameCore(action, out var desc),
355+
desc,
356+
client => action(client).AsUntypedValueTask(),
357+
client => PipelineTyped(client, action, divisor),
358+
[],
359+
deleteKey,
360+
divisor);
361+
362+
protected Task RunAsync<T>(
363+
string? key,
364+
Func<TClient, ValueTask<T>> action,
365+
params string[] consumers)
366+
=> RunAsyncCore<T>(
367+
key,
368+
GetNameCore(action, out var desc),
369+
desc,
358370
client => action(client).AsUntypedValueTask(),
359-
client => PipelineTyped(client, action),
360-
init,
361-
format);
371+
client => PipelineTyped(client, action, 1),
372+
consumers,
373+
consumers.Length != 0,
374+
1);
362375

363-
// ReSharper disable once UnusedMember.Global
364376
protected Task RunAsync(
365377
string? key,
366378
Func<TClient, ValueTask> action,
367-
Func<TClient, ValueTask>? init = null,
368-
string format = "")
369-
=> RunAsyncCore<DBNull>(key, action, action, client => PipelineUntyped(client, action), init, format);
379+
bool deleteKey,
380+
int divisor = 1)
381+
=> RunAsyncCore<DBNull>(
382+
key,
383+
GetNameCore(action, out var desc),
384+
desc,
385+
action,
386+
client => PipelineUntyped(client, action, divisor),
387+
[],
388+
deleteKey,
389+
divisor);
370390

371-
private async Task RunAsyncCore<T>(
391+
protected Task RunAsync(
372392
string? key,
373-
Delegate underlyingAction,
374-
Func<TClient, ValueTask> test,
375-
Func<TClient, Task<T>> pipeline,
376-
Func<TClient, ValueTask>? init = null,
377-
string format = "")
393+
Func<TClient, ValueTask> action,
394+
params string[] consumers)
395+
=> RunAsyncCore<DBNull>(
396+
key,
397+
GetNameCore(action, out var desc),
398+
desc,
399+
action,
400+
client => PipelineUntyped(client, action, 1),
401+
consumers,
402+
consumers.Length != 0,
403+
1);
404+
405+
private static string GetNameCore(Delegate underlyingAction, out string description)
378406
{
379407
string name = underlyingAction.Method.Name;
380408

@@ -386,17 +414,44 @@ private async Task RunAsyncCore<T>(
386414
name = dna.DisplayName;
387415
}
388416

389-
// skip test if not needed
390-
if (!RunTest(name)) return;
391-
392-
// include additional test metadata
393-
string description = "";
417+
description = "";
394418
if (underlyingAction.Method.GetCustomAttribute(typeof(DescriptionAttribute)) is DescriptionAttribute
395419
{
396420
Description: { Length: > 0 }
397421
} da)
398422
{
399-
description = $" ({da.Description})";
423+
description = da.Description;
424+
}
425+
426+
return name;
427+
}
428+
429+
protected static string GetName<T>(Func<TClient, ValueTask<T>> action) => GetNameCore(action, out _);
430+
protected static string GetName(Func<TClient, ValueTask> action) => GetNameCore(action, out _);
431+
432+
private async Task RunAsyncCore<T>(
433+
string? key,
434+
string name,
435+
string description,
436+
Func<TClient, ValueTask> test,
437+
Func<TClient, Task<T>> pipeline,
438+
string[] consumers,
439+
bool deleteKey,
440+
int divisor)
441+
{
442+
// skip test if not needed
443+
string auxReason = "";
444+
if (!RunTest(name))
445+
{
446+
auxReason = string.Join(", ", consumers.Where(x => RunTest(x)));
447+
if (auxReason.Length == 0) return; // not needed by any consumers either
448+
auxReason = $" (required for {auxReason})";
449+
}
450+
451+
// include additional test metadata
452+
if (description is { Length: > 0 })
453+
{
454+
description = $" ({description})";
400455
}
401456

402457
if (Quiet)
@@ -406,7 +461,7 @@ private async Task RunAsyncCore<T>(
406461
else
407462
{
408463
Console.Write(
409-
$"====== {name}{description} ====== (clients: {ClientCount:#,##0}, ops: {TotalOperations:#,##0}");
464+
$"====== {name}{description}{auxReason} ====== (clients: {ClientCount:#,##0}, ops: {TotalOperations(divisor):#,##0}");
410465
if (Multiplexed)
411466
{
412467
Console.Write(", mux");
@@ -425,7 +480,7 @@ private async Task RunAsyncCore<T>(
425480
bool didNotRun = false;
426481
try
427482
{
428-
if (key is not null)
483+
if (key is not null && deleteKey)
429484
{
430485
await DeleteAsync(GetClient(0), key).ConfigureAwait(false);
431486
}
@@ -441,11 +496,6 @@ private async Task RunAsyncCore<T>(
441496
return;
442497
}
443498

444-
if (init is not null)
445-
{
446-
await init(GetClient(0)).ConfigureAwait(false);
447-
}
448-
449499
var pending = new Task<T>[ClientCount];
450500
int index = 0;
451501
#if DEBUG
@@ -465,14 +515,17 @@ private async Task RunAsyncCore<T>(
465515
client = CreateBatch(client);
466516
}
467517

468-
pending[index++] = Task.Run(() => pipeline(WithCancellation(client, cancellationToken)), cancellationToken);
518+
pending[index++] = Task.Run(
519+
() => pipeline(WithCancellation(client, cancellationToken)),
520+
cancellationToken);
469521
}
470522

471523
await Task.WhenAll(pending).ConfigureAwait(false);
472524
watch.Stop();
473525

474526
var seconds = watch.Elapsed.TotalSeconds;
475-
var rate = TotalOperations / seconds;
527+
// ReSharper disable once PossibleLossOfFraction
528+
var rate = TotalOperations(divisor) / seconds;
476529
if (Quiet)
477530
{
478531
Console.WriteLine($"\t{rate:###,###,##0} requests per second");
@@ -481,15 +534,12 @@ private async Task RunAsyncCore<T>(
481534
else
482535
{
483536
Console.WriteLine(
484-
$"{TotalOperations:###,###,##0} requests completed in {seconds:0.00} seconds, {rate:###,###,##0} ops/sec");
537+
$"{TotalOperations(divisor):###,###,##0} requests completed in {seconds:0.00} seconds, {rate:###,###,##0} ops/sec");
485538
}
486539

487540
if (!Quiet & typeof(T) != typeof(DBNull))
488541
{
489-
if (string.IsNullOrWhiteSpace(format))
490-
{
491-
format = "Typical result: {0}";
492-
}
542+
const string format = "Typical result: {0}";
493543

494544
T result = await pending[^1];
495545
Console.WriteLine(format, result);
@@ -575,9 +625,13 @@ private async Task RunAsyncCore<T>(
575625

576626
if (counters.BatchBufferLeaseCount != 0 | counters.BatchMultiRootMessageCount != 0)
577627
{
578-
Console.Write($"Multi-message batching: {counters.BatchMultiRootMessageCount:#,###,##0} batches, {counters.BatchMultiChildMessageCount:#,###,##0} sub-messages");
628+
Console.Write(
629+
$"Multi-message batching: {counters.BatchMultiRootMessageCount:#,###,##0} batches, {counters.BatchMultiChildMessageCount:#,###,##0} sub-messages");
579630
if (counters.BatchBufferLeaseCount != 0)
580-
Console.Write($"; {counters.BatchBufferLeaseCount:#,###,##0} blocks leased, {counters.BatchBufferReturnCount:#,###,##0} blocks returned, {counters.BatchBufferElementsOutstanding:#,###,##0} elements outstanding");
631+
{
632+
Console.Write(
633+
$"; {counters.BatchBufferLeaseCount:#,###,##0} blocks leased, {counters.BatchBufferReturnCount:#,###,##0} blocks returned, {counters.BatchBufferElementsOutstanding:#,###,##0} elements outstanding");
634+
}
581635
Console.WriteLine();
582636
}
583637

0 commit comments

Comments
 (0)