Skip to content

Commit faea7d0

Browse files
antonfirsovkroymann
authored andcommitted
AsyncImageSharp option for load testing
1 parent b54db18 commit faea7d0

File tree

2 files changed

+69
-3
lines changed

2 files changed

+69
-3
lines changed

tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStressRunner.cs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22
// Licensed under the Apache License, Version 2.0.
33

44
using System;
5+
using System.Collections.Generic;
56
using System.Drawing;
67
using System.Drawing.Drawing2D;
78
using System.Drawing.Imaging;
89
using System.IO;
910
using System.Linq;
1011
using System.Runtime.CompilerServices;
1112
using System.Runtime.InteropServices;
13+
using System.Threading;
1214
using System.Threading.Tasks;
1315
using ImageMagick;
1416
using PhotoSauce.MagicScaler;
@@ -124,6 +126,32 @@ public void ForEachImageParallel(Action<string> action) => Parallel.ForEach(
124126
new ParallelOptions { MaxDegreeOfParallelism = this.MaxDegreeOfParallelism },
125127
action);
126128

129+
public Task ForEachImageParallelAsync(Func<string, Task> action)
130+
{
131+
int maxDegreeOfParallelism = this.MaxDegreeOfParallelism > 0
132+
? this.MaxDegreeOfParallelism
133+
: Environment.ProcessorCount;
134+
int partitionSize = (int)Math.Ceiling((double)this.Images.Length / maxDegreeOfParallelism);
135+
136+
List<Task> tasks = new();
137+
for (int i = 0; i < this.Images.Length; i += partitionSize)
138+
{
139+
int end = Math.Min(i + partitionSize, this.Images.Length);
140+
Task task = RunPartition(i, end);
141+
tasks.Add(task);
142+
}
143+
144+
return Task.WhenAll(tasks);
145+
146+
Task RunPartition(int start, int end) => Task.Run(async () =>
147+
{
148+
for (int i = start; i < end; i++)
149+
{
150+
await action(this.Images[i]);
151+
}
152+
});
153+
}
154+
127155
private void LogImageProcessed(int width, int height)
128156
{
129157
this.LastProcessedImageSize = new Size(width, height);
@@ -197,6 +225,26 @@ public void ImageSharpResize(string input)
197225
image.Save(output, this.imageSharpJpegEncoder);
198226
}
199227

228+
public async Task ImageSharpResizeAsync(string input)
229+
{
230+
using FileStream output = File.Open(this.OutputPath(input), FileMode.Create);
231+
// Resize it to fit a 150x150 square
232+
using var image = await ImageSharpImage.LoadAsync(input);
233+
this.LogImageProcessed(image.Width, image.Height);
234+
235+
image.Mutate(i => i.Resize(new ResizeOptions
236+
{
237+
Size = new ImageSharpSize(this.ThumbnailSize, this.ThumbnailSize),
238+
Mode = ResizeMode.Max
239+
}));
240+
241+
// Reduce the size of the file
242+
image.Metadata.ExifProfile = null;
243+
244+
// Save the results
245+
await image.SaveAsync(output, this.imageSharpJpegEncoder);
246+
}
247+
200248
public void MagickResize(string input)
201249
{
202250
using var image = new MagickImage(input);

tests/ImageSharp.Tests.ProfilingSandbox/LoadResizeSaveParallelMemoryStress.cs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public static void Run(string[] args)
5151
Console.WriteLine($"\nEnvironment.ProcessorCount={Environment.ProcessorCount}");
5252
Stopwatch timer;
5353

54-
if (options == null || !options.ImageSharp)
54+
if (options == null || !(options.ImageSharp || options.AsyncImageSharp))
5555
{
5656
RunBenchmarkSwitcher(lrs, out timer);
5757
}
@@ -74,7 +74,16 @@ public static void Run(string[] args)
7474
{
7575
for (int i = 0; i < options.RepeatCount; i++)
7676
{
77-
lrs.ImageSharpBenchmarkParallel();
77+
if (options.AsyncImageSharp)
78+
{
79+
lrs.ImageSharpBenchmarkParallelAsync();
80+
}
81+
else
82+
{
83+
lrs.ImageSharpBenchmarkParallel();
84+
}
85+
86+
Console.WriteLine("OK");
7887
}
7988
}
8089
catch (Exception ex)
@@ -221,6 +230,9 @@ public string GetMarkdown()
221230

222231
private class CommandLineOptions
223232
{
233+
[Option('a', "async-imagesharp", Required = false, Default = false, HelpText = "Async ImageSharp without benchmark switching")]
234+
public bool AsyncImageSharp { get; set; }
235+
224236
[Option('i', "imagesharp", Required = false, Default = false, HelpText = "Test ImageSharp without benchmark switching")]
225237
public bool ImageSharp { get; set; }
226238

@@ -277,7 +289,7 @@ public static CommandLineOptions Parse(string[] args)
277289
}
278290

279291
public override string ToString() =>
280-
$"p({this.MaxDegreeOfParallelism})_i({this.ImageSharp})_d({this.KeepDefaultAllocator})_m({this.MaxContiguousPoolBufferMegaBytes})_s({this.MaxPoolSizeMegaBytes})_u({this.MaxCapacityOfNonPoolBuffersMegaBytes})_r({this.RepeatCount})_g({this.GcFrequency})_e({this.ReleaseRetainedResourcesAtEnd})_l({this.LeakFrequency})";
292+
$"p({this.MaxDegreeOfParallelism})_i({this.ImageSharp})_a({this.AsyncImageSharp})_d({this.KeepDefaultAllocator})_m({this.MaxContiguousPoolBufferMegaBytes})_s({this.MaxPoolSizeMegaBytes})_u({this.MaxCapacityOfNonPoolBuffersMegaBytes})_r({this.RepeatCount})_g({this.GcFrequency})_e({this.ReleaseRetainedResourcesAtEnd})_l({this.LeakFrequency})";
281293

282294
public MemoryAllocator CreateMemoryAllocator()
283295
{
@@ -330,11 +342,17 @@ private void ImageSharpBenchmarkParallel() =>
330342
}
331343
});
332344

345+
private void ImageSharpBenchmarkParallelAsync() =>
346+
this.Benchmarks.ForEachImageParallelAsync(f => this.Benchmarks.ImageSharpResizeAsync(f))
347+
.GetAwaiter()
348+
.GetResult();
349+
333350
private void MagickBenchmarkParallel() => this.ForEachImage(this.Benchmarks.MagickResize);
334351

335352
private void MagicScalerBenchmarkParallel() => this.ForEachImage(this.Benchmarks.MagicScalerResize);
336353

337354
private void SkiaBitmapBenchmarkParallel() => this.ForEachImage(this.Benchmarks.SkiaBitmapResize);
355+
338356
private void SkiaBitmapDecodeToTargetSizeBenchmarkParallel() => this.ForEachImage(this.Benchmarks.SkiaBitmapDecodeToTargetSize);
339357

340358
private void NetVipsBenchmarkParallel() => this.ForEachImage(this.Benchmarks.NetVipsResize);

0 commit comments

Comments
 (0)