Browse Source

initial import of beeees stress code

pull/1687/head
Anton Firszov 5 years ago
parent
commit
f37b46e567
  1. 7
      tests/Directory.Build.targets
  2. 8
      tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj
  3. 221
      tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStressRunner.cs
  4. 52
      tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStress_NonParallel.cs
  5. 48
      tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStress_Parallel.cs
  6. 2
      tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj
  7. 100
      tests/ImageSharp.Tests.ProfilingSandbox/LoadResizeSaveParallelMemoryStress.cs
  8. 4
      tests/ImageSharp.Tests.ProfilingSandbox/Program.cs

7
tests/Directory.Build.targets

@ -29,6 +29,13 @@
<PackageReference Include="runtime.osx.10.10-x64.CoreCompat.System.Drawing" Version="5.8.64" Condition="'$(IsOSX)'=='true'" /> <PackageReference Include="runtime.osx.10.10-x64.CoreCompat.System.Drawing" Version="5.8.64" Condition="'$(IsOSX)'=='true'" />
<PackageReference Update="SharpZipLib" Version="1.3.0" /> <PackageReference Update="SharpZipLib" Version="1.3.0" />
<PackageReference Update="System.Drawing.Common" Version="4.7.0" /> <PackageReference Update="System.Drawing.Common" Version="4.7.0" />
<PackageReference Include="FreeImage.Standard" Version="4.3.8" />
<PackageReference Include="NetVips" Version="2.0.0" />
<PackageReference Include="PhotoSauce.MagicScaler" Version="0.12.1" />
<PackageReference Include="SkiaSharp" Version="2.80.3-preview.93" />
<PackageReference Include="System.Drawing.Common" Version="5.0.2" />
<PackageReference Include="NetVips.Native" Version="8.10.6" />
</ItemGroup> </ItemGroup>
</Project> </Project>

8
tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj

@ -9,7 +9,7 @@
<!--Used to hide test project from dotnet test--> <!--Used to hide test project from dotnet test-->
<IsTestProject>false</IsTestProject> <IsTestProject>false</IsTestProject>
<Configurations>Debug;Release;Debug-InnerLoop;Release-InnerLoop</Configurations> <Configurations>Debug;Release;Debug-InnerLoop;Release-InnerLoop</Configurations>
<LangVersion>9</LangVersion>
<!-- Uncomment this to run benchmarks depending on Colorful or Pfim (colorspaces and TGA): --> <!-- Uncomment this to run benchmarks depending on Colorful or Pfim (colorspaces and TGA): -->
<!--<SignAssembly>false</SignAssembly>--> <!--<SignAssembly>false</SignAssembly>-->
</PropertyGroup> </PropertyGroup>
@ -41,6 +41,12 @@
<PackageReference Include="Pfim" /> <PackageReference Include="Pfim" />
<PackageReference Include="SharpZipLib" /> <PackageReference Include="SharpZipLib" />
<PackageReference Include="System.Drawing.Common" /> <PackageReference Include="System.Drawing.Common" />
<PackageReference Include="FreeImage.Standard" />
<PackageReference Include="NetVips" />
<PackageReference Include="PhotoSauce.MagicScaler" />
<PackageReference Include="SkiaSharp" Version="2.80.3-preview.93" />
<PackageReference Include="NetVips.Native" />
</ItemGroup> </ItemGroup>
<!-- Exclude benchmarks using internals, in case of unsigned benchmark execution: --> <!-- Exclude benchmarks using internals, in case of unsigned benchmark execution: -->

221
tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStressRunner.cs

@ -0,0 +1,221 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using FreeImageAPI;
using ImageMagick;
using PhotoSauce.MagicScaler;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Tests;
using SkiaSharp;
using ImageSharpImage = SixLabors.ImageSharp.Image;
using ImageSharpSize = SixLabors.ImageSharp.Size;
using NetVipsImage = NetVips.Image;
using SystemDrawingImage = System.Drawing.Image;
namespace SixLabors.ImageSharp.Benchmarks.LoadResizeSave
{
public class LoadResizeSaveStressRunner
{
private const int ThumbnailSize = 150;
private const int Quality = 75;
private const string ImageSharp = nameof(ImageSharp);
private const string SystemDrawing = nameof(SystemDrawing);
private const string MagickNET = nameof(MagickNET);
private const string NetVips = nameof(NetVips);
private const string FreeImage = nameof(FreeImage);
private const string MagicScaler = nameof(MagicScaler);
private const string SkiaSharpCanvas = nameof(SkiaSharpCanvas);
private const string SkiaSharpBitmap = nameof(SkiaSharpBitmap);
// Set the quality for ImagSharp
private readonly JpegEncoder imageSharpJpegEncoder = new () { Quality = Quality };
private readonly ImageCodecInfo systemDrawingJpegCodec =
ImageCodecInfo.GetImageEncoders().First(codec => codec.FormatID == ImageFormat.Jpeg.Guid);
public string[] Images { get; private set; }
private string outputDirectory;
public int ImageCount { get; set; } = int.MaxValue;
public void Init()
{
if (RuntimeInformation.OSArchitecture is Architecture.X86 or Architecture.X64)
{
// Workaround ImageMagick issue
OpenCL.IsEnabled = false;
}
string imageDirectory = Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, "MemoryStress");
if (!Directory.Exists(imageDirectory) || !Directory.EnumerateFiles(imageDirectory).Any())
{
throw new DirectoryNotFoundException($"Copy stress images to: {imageDirectory}");
}
// Get at most this.ImageCount images from there
this.Images = Directory.EnumerateFiles(imageDirectory).Take(this.ImageCount).ToArray();
// Create the output directory next to the images directory
this.outputDirectory = TestEnvironment.CreateOutputDirectory("MemoryStress");
}
private string OutputPath(string inputPath, string postfix) =>
Path.Combine(
this.outputDirectory,
Path.GetFileNameWithoutExtension(inputPath) + "-" + postfix + Path.GetExtension(inputPath));
private (int width, int height) ScaledSize(int inWidth, int inHeight, int outSize)
{
int width, height;
if (inWidth > inHeight)
{
width = outSize;
height = (int)Math.Round(inHeight * outSize / (double)inWidth);
}
else
{
width = (int)Math.Round(inWidth * outSize / (double)inHeight);
height = outSize;
}
return (width, height);
}
public void SystemDrawingResize(string input)
{
using var image = SystemDrawingImage.FromFile(input, true);
(int width, int height) scaled = this.ScaledSize(image.Width, image.Height, ThumbnailSize);
var resized = new Bitmap(scaled.width, scaled.height);
using var graphics = Graphics.FromImage(resized);
using var attributes = new ImageAttributes();
attributes.SetWrapMode(WrapMode.TileFlipXY);
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.AssumeLinear;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.DrawImage(image, System.Drawing.Rectangle.FromLTRB(0, 0, resized.Width, resized.Height), 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, attributes);
// Save the results
using var encoderParams = new EncoderParameters(1);
using var qualityParam = new EncoderParameter(Encoder.Quality, (long)Quality);
encoderParams.Param[0] = qualityParam;
resized.Save(this.OutputPath(input, SystemDrawing), this.systemDrawingJpegCodec, encoderParams);
}
public void ImageSharpResize(string input)
{
using FileStream output = File.Open(this.OutputPath(input, ImageSharp), FileMode.Create);
// Resize it to fit a 150x150 square
using var image = ImageSharpImage.Load(input);
image.Mutate(i => i.Resize(new ResizeOptions
{
Size = new ImageSharpSize(ThumbnailSize, ThumbnailSize),
Mode = ResizeMode.Max
}));
// Reduce the size of the file
image.Metadata.ExifProfile = null;
// Save the results
image.Save(output, this.imageSharpJpegEncoder);
}
public void MagickResize(string input)
{
using var image = new MagickImage(input);
// Resize it to fit a 150x150 square
image.Resize(ThumbnailSize, ThumbnailSize);
// Reduce the size of the file
image.Strip();
// Set the quality
image.Quality = Quality;
// Save the results
image.Write(this.OutputPath(input, MagickNET));
}
public void FreeImageResize(string input)
{
using var original = FreeImageBitmap.FromFile(input);
(int width, int height) scaled = this.ScaledSize(original.Width, original.Height, ThumbnailSize);
var resized = new FreeImageBitmap(original, scaled.width, scaled.height);
// JPEG_QUALITYGOOD is 75 JPEG.
// JPEG_BASELINE strips metadata (EXIF, etc.)
resized.Save(
this.OutputPath(input, FreeImage),
FREE_IMAGE_FORMAT.FIF_JPEG,
FREE_IMAGE_SAVE_FLAGS.JPEG_QUALITYGOOD | FREE_IMAGE_SAVE_FLAGS.JPEG_BASELINE);
}
public void MagicScalerResize(string input)
{
var settings = new ProcessImageSettings()
{
Width = ThumbnailSize,
Height = ThumbnailSize,
ResizeMode = CropScaleMode.Max,
SaveFormat = FileFormat.Jpeg,
JpegQuality = Quality,
JpegSubsampleMode = ChromaSubsampleMode.Subsample420
};
using var output = new FileStream(this.OutputPath(input, MagicScaler), FileMode.Create);
MagicImageProcessor.ProcessImage(input, output, settings);
}
public void SkiaCanvasResize(string input)
{
using var original = SKBitmap.Decode(input);
(int width, int height) scaled = this.ScaledSize(original.Width, original.Height, ThumbnailSize);
using var surface = SKSurface.Create(new SKImageInfo(scaled.width, scaled.height, original.ColorType, original.AlphaType));
using var paint = new SKPaint() { FilterQuality = SKFilterQuality.High };
SKCanvas canvas = surface.Canvas;
canvas.Scale((float)scaled.width / original.Width);
canvas.DrawBitmap(original, 0, 0, paint);
canvas.Flush();
using FileStream output = File.OpenWrite(this.OutputPath(input, SkiaSharpCanvas));
surface.Snapshot()
.Encode(SKEncodedImageFormat.Jpeg, Quality)
.SaveTo(output);
}
public void SkiaBitmapResize(string input)
{
using var original = SKBitmap.Decode(input);
(int width, int height) scaled = this.ScaledSize(original.Width, original.Height, ThumbnailSize);
using var resized = original.Resize(new SKImageInfo(scaled.width, scaled.height), SKFilterQuality.High);
if (resized == null)
{
return;
}
using var image = SKImage.FromBitmap(resized);
using FileStream output = File.OpenWrite(this.OutputPath(input, SkiaSharpBitmap));
image.Encode(SKEncodedImageFormat.Jpeg, Quality)
.SaveTo(output);
}
public void NetVipsResize(string input)
{
// Thumbnail to fit a 150x150 square
using var thumb = NetVipsImage.Thumbnail(input, ThumbnailSize, ThumbnailSize);
// Save the results
thumb.Jpegsave(this.OutputPath(input, NetVips), q: Quality, strip: true);
}
}
}

52
tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStress_NonParallel.cs

@ -0,0 +1,52 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
using BenchmarkDotNet.Attributes;
namespace SixLabors.ImageSharp.Benchmarks.LoadResizeSave
{
public class LoadResizeSaveStress_NonParallel
{
private LoadResizeSaveStressRunner benchmarks;
[GlobalSetup]
public void Setup()
{
this.benchmarks = new LoadResizeSaveStressRunner() { ImageCount = 20 };
this.benchmarks.Init();
}
private void ForEachImage(Action<string> action)
{
foreach (string image in this.benchmarks.Images)
{
action(image);
}
}
[Benchmark(Baseline = true, Description = "System.Drawing Load, Resize, Save")]
public void SystemDrawingBenchmark() => this.ForEachImage(this.benchmarks.SystemDrawingResize);
[Benchmark(Description = "ImageSharp Load, Resize, Save")]
public void ImageSharpBenchmark() => this.ForEachImage(this.benchmarks.ImageSharpResize);
[Benchmark(Description = "ImageMagick Load, Resize, Save")]
public void MagickBenchmark() => this.ForEachImage(this.benchmarks.MagickResize);
[Benchmark(Description = "ImageFree Load, Resize, Save")]
public void FreeImageBenchmark() => this.ForEachImage(this.benchmarks.FreeImageResize);
[Benchmark(Description = "MagicScaler Load, Resize, Save")]
public void MagicScalerBenchmark() => this.ForEachImage(this.benchmarks.MagicScalerResize);
[Benchmark(Description = "SkiaSharp Canvas Load, Resize, Save")]
public void SkiaCanvasBenchmark() => this.ForEachImage(this.benchmarks.SkiaCanvasResize);
[Benchmark(Description = "SkiaSharp Bitmap Load, Resize, Save")]
public void SkiaBitmapBenchmark() => this.ForEachImage(this.benchmarks.SkiaBitmapResize);
[Benchmark(Description = "NetVips Load, Resize, Save")]
public void NetVipsBenchmark() => this.ForEachImage(this.benchmarks.NetVipsResize);
}
}

48
tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStress_Parallel.cs

@ -0,0 +1,48 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;
namespace SixLabors.ImageSharp.Benchmarks.LoadResizeSave
{
[MemoryDiagnoser]
public class LoadResizeSaveStress_Parallel
{
private LoadResizeSaveStressRunner benchmarks;
[GlobalSetup]
public void Setup()
{
this.benchmarks = new LoadResizeSaveStressRunner() { ImageCount = 20 };
this.benchmarks.Init();
}
private void ForEachImage(Action<string> action) => Parallel.ForEach(this.benchmarks.Images, action);
[Benchmark(Baseline = true, Description = "System.Drawing Load, Resize, Save - Parallel")]
public void SystemDrawingBenchmarkParallel() => this.ForEachImage(this.benchmarks.SystemDrawingResize);
[Benchmark(Description = "ImageSharp Load, Resize, Save - Parallel")]
public void ImageSharpBenchmarkParallel() => this.ForEachImage(this.benchmarks.ImageSharpResize);
[Benchmark(Description = "ImageMagick Load, Resize, Save - Parallel")]
public void MagickBenchmarkParallel() => this.ForEachImage(this.benchmarks.MagickResize);
[Benchmark(Description = "ImageFree Load, Resize, Save - Parallel")]
public void FreeImageBenchmarkParallel() => this.ForEachImage(this.benchmarks.FreeImageResize);
[Benchmark(Description = "MagicScaler Load, Resize, Save - Parallel")]
public void MagicScalerBenchmarkParallel() => this.ForEachImage(this.benchmarks.MagicScalerResize);
[Benchmark(Description = "SkiaSharp Canvas Load, Resize, Save - Parallel")]
public void SkiaCanvasBenchmarkParallel() => this.ForEachImage(this.benchmarks.SkiaCanvasResize);
[Benchmark(Description = "SkiaSharp Bitmap Load, Resize, Save - Parallel")]
public void SkiaBitmapBenchmarkParallel() => this.ForEachImage(this.benchmarks.SkiaBitmapResize);
[Benchmark(Description = "NetVips Load, Resize, Save - Parallel")]
public void NetVipsBenchmarkParallel() => this.ForEachImage(this.benchmarks.NetVipsResize);
}
}

2
tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj

@ -14,6 +14,7 @@
<EnsureNETCoreAppRuntime>false</EnsureNETCoreAppRuntime> <EnsureNETCoreAppRuntime>false</EnsureNETCoreAppRuntime>
<Configurations>Debug;Release;Debug-InnerLoop;Release-InnerLoop</Configurations> <Configurations>Debug;Release;Debug-InnerLoop;Release-InnerLoop</Configurations>
<ValidateExecutableReferencesMatchSelfContained>false</ValidateExecutableReferencesMatchSelfContained> <ValidateExecutableReferencesMatchSelfContained>false</ValidateExecutableReferencesMatchSelfContained>
<LangVersion>9</LangVersion>
</PropertyGroup> </PropertyGroup>
<Choose> <Choose>
@ -31,6 +32,7 @@
<ItemGroup> <ItemGroup>
<Compile Remove="..\ImageSharp.Tests\IO\LocalFileSystem.cs" /> <Compile Remove="..\ImageSharp.Tests\IO\LocalFileSystem.cs" />
<Compile Include="..\ImageSharp.Benchmarks\LoadResizeSave\LoadResizeSaveStressRunner.cs" Link="LoadResizeSaveStressRunner.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

100
tests/ImageSharp.Tests.ProfilingSandbox/LoadResizeSaveParallelMemoryStress.cs

@ -0,0 +1,100 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Benchmarks.LoadResizeSave;
namespace SixLabors.ImageSharp.Tests.ProfilingSandbox
{
internal class LoadResizeSaveParallelMemoryStress
{
private readonly LoadResizeSaveStressRunner benchmarks;
public LoadResizeSaveParallelMemoryStress()
{
this.benchmarks = new LoadResizeSaveStressRunner();
this.benchmarks.Init();
}
public static void Run()
{
Console.WriteLine(@"Choose a library for image resizing stress test:
1. System.Drawing
2. ImageSharp
3. MagicScaler
4. SkiaSharp
5. NetVips
6. ImageMagick
7. FreeImage
");
ConsoleKey key = Console.ReadKey().Key;
if (key < ConsoleKey.D1 || key > ConsoleKey.D7)
{
Console.WriteLine("Unrecognized command.");
return;
}
try
{
var lrs = new LoadResizeSaveParallelMemoryStress();
Console.WriteLine("\nRunning...");
var timer = new Stopwatch();
timer.Start();
switch (key)
{
case ConsoleKey.D1:
lrs.SystemDrawingBenchmarkParallel();
break;
case ConsoleKey.D2:
lrs.ImageSharpBenchmarkParallel();
break;
case ConsoleKey.D3:
lrs.MagicScalerBenchmarkParallel();
break;
case ConsoleKey.D4:
lrs.SkiaCanvasBenchmarkParallel();
break;
case ConsoleKey.D5:
lrs.NetVipsBenchmarkParallel();
break;
case ConsoleKey.D6:
lrs.MagickBenchmarkParallel();
break;
case ConsoleKey.D7:
lrs.FreeImageBenchmarkParallel();
break;
}
timer.Stop();
Console.WriteLine($"Completed in {timer.ElapsedMilliseconds / 1000.0:f3}sec");
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
private void ForEachImage(Action<string> action) => Parallel.ForEach(this.benchmarks.Images, action);
private void SystemDrawingBenchmarkParallel() => this.ForEachImage(this.benchmarks.SystemDrawingResize);
private void ImageSharpBenchmarkParallel() => this.ForEachImage(this.benchmarks.ImageSharpResize);
private void MagickBenchmarkParallel() => this.ForEachImage(this.benchmarks.MagickResize);
private void FreeImageBenchmarkParallel() => this.ForEachImage(this.benchmarks.FreeImageResize);
private void MagicScalerBenchmarkParallel() => this.ForEachImage(this.benchmarks.MagicScalerResize);
private void SkiaCanvasBenchmarkParallel() => this.ForEachImage(this.benchmarks.SkiaCanvasResize);
private void SkiaBitmapBenchmarkParallel() => this.ForEachImage(this.benchmarks.SkiaBitmapResize);
private void NetVipsBenchmarkParallel() => this.ForEachImage(this.benchmarks.NetVipsResize);
}
}

4
tests/ImageSharp.Tests.ProfilingSandbox/Program.cs

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Diagnostics;
using SixLabors.ImageSharp.Tests.Formats.Jpg; using SixLabors.ImageSharp.Tests.Formats.Jpg;
using SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations; using SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations;
using SixLabors.ImageSharp.Tests.ProfilingBenchmarks; using SixLabors.ImageSharp.Tests.ProfilingBenchmarks;
@ -31,7 +32,8 @@ namespace SixLabors.ImageSharp.Tests.ProfilingSandbox
/// </param> /// </param>
public static void Main(string[] args) public static void Main(string[] args)
{ {
RunJpegEncoderProfilingTests(); LoadResizeSaveParallelMemoryStress.Run();
// RunJpegEncoderProfilingTests();
// RunJpegColorProfilingTests(); // RunJpegColorProfilingTests();
// RunDecodeJpegProfilingTests(); // RunDecodeJpegProfilingTests();
// RunToVector4ProfilingTest(); // RunToVector4ProfilingTest();

Loading…
Cancel
Save