From d922602a26fa139b97dee86681b7dfcec188df68 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 27 Feb 2020 12:54:51 +0100 Subject: [PATCH] Introduced single row parallel helpers --- .../Advanced/ParallelRowIterator.cs | 138 +++++++++++++++++- 1 file changed, 134 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Advanced/ParallelRowIterator.cs b/src/ImageSharp/Advanced/ParallelRowIterator.cs index 70b48aee9..86442ede7 100644 --- a/src/ImageSharp/Advanced/ParallelRowIterator.cs +++ b/src/ImageSharp/Advanced/ParallelRowIterator.cs @@ -17,6 +17,137 @@ namespace SixLabors.ImageSharp.Advanced /// public static partial class ParallelRowIterator { + /// + /// Iterate through the rows of a rectangle in optimized batches. + /// + /// The type of row operation to perform. + /// The to get the parallel settings from. + /// The . + /// The operation defining the iteration logic on a single row. + [MethodImpl(InliningOptions.ShortMethod)] + public static void IterateRows(Configuration configuration, Rectangle rectangle, in T operation) + where T : struct, IRowOperation + { + var parallelSettings = ParallelExecutionSettings.FromConfiguration(configuration); + IterateRows(rectangle, in parallelSettings, in operation); + } + + /// + /// Iterate through the rows of a rectangle in optimized batches. + /// + /// The type of row operation to perform. + /// The . + /// The . + /// The operation defining the iteration logic on a single row. + public static void IterateRows( + Rectangle rectangle, + in ParallelExecutionSettings parallelSettings, + in T operation) + where T : struct, IRowOperation + { + ValidateRectangle(rectangle); + + int top = rectangle.Top; + int bottom = rectangle.Bottom; + int width = rectangle.Width; + int height = rectangle.Height; + + int maxSteps = DivideCeil(width * height, parallelSettings.MinimumPixelsProcessedPerTask); + int numOfSteps = Math.Min(parallelSettings.MaxDegreeOfParallelism, maxSteps); + + // Avoid TPL overhead in this trivial case: + if (numOfSteps == 1) + { + for (int y = top; y < bottom; y++) + { + Unsafe.AsRef(operation).Invoke(y); + } + + return; + } + + int verticalStep = DivideCeil(rectangle.Height, numOfSteps); + var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = numOfSteps }; + var info = new IterationParameters(top, bottom, verticalStep); + var wrappingOperation = new RowOperationWrapper(in info, in operation); + + Parallel.For( + 0, + numOfSteps, + parallelOptions, + wrappingOperation.Invoke); + } + + /// + /// Iterate through the rows of a rectangle in optimized batches. + /// instantiating a temporary buffer for each invocation. + /// + /// The type of row operation to perform. + /// The type of buffer elements. + /// The to get the parallel settings from. + /// The . + /// The operation defining the iteration logic on a single row. + public static void IterateRows(Configuration configuration, Rectangle rectangle, in T operation) + where T : struct, IRowOperation + where TBuffer : unmanaged + { + var parallelSettings = ParallelExecutionSettings.FromConfiguration(configuration); + IterateRows(rectangle, in parallelSettings, in operation); + } + + /// + /// Iterate through the rows of a rectangle in optimized batches. + /// instantiating a temporary buffer for each invocation. + /// + /// The type of row operation to perform. + /// The type of buffer elements. + /// The . + /// The . + /// The operation defining the iteration logic on a single row. + public static void IterateRows( + Rectangle rectangle, + in ParallelExecutionSettings parallelSettings, + in T operation) + where T : struct, IRowOperation + where TBuffer : unmanaged + { + ValidateRectangle(rectangle); + + int top = rectangle.Top; + int bottom = rectangle.Bottom; + int width = rectangle.Width; + int height = rectangle.Height; + + int maxSteps = DivideCeil(width * height, parallelSettings.MinimumPixelsProcessedPerTask); + int numOfSteps = Math.Min(parallelSettings.MaxDegreeOfParallelism, maxSteps); + MemoryAllocator allocator = parallelSettings.MemoryAllocator; + + // Avoid TPL overhead in this trivial case: + if (numOfSteps == 1) + { + using IMemoryOwner buffer = allocator.Allocate(width); + Span span = buffer.Memory.Span; + + for (int y = top; y < bottom; y++) + { + Unsafe.AsRef(operation).Invoke(y, span); + } + + return; + } + + int verticalStep = DivideCeil(height, numOfSteps); + var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = numOfSteps }; + var info = new IterationParameters(top, bottom, verticalStep, width); + var wrappingOperation = new RowOperationWrapper(in info, allocator, in operation); + + Parallel.For( + 0, + numOfSteps, + parallelOptions, + wrappingOperation.Invoke); + } + /// /// Iterate through the rows of a rectangle in optimized batches defined by -s. /// @@ -123,10 +254,9 @@ namespace SixLabors.ImageSharp.Advanced if (numOfSteps == 1) { var rows = new RowInterval(top, bottom); - using (IMemoryOwner buffer = allocator.Allocate(width)) - { - Unsafe.AsRef(operation).Invoke(in rows, buffer.Memory.Span); - } + using IMemoryOwner buffer = allocator.Allocate(width); + + Unsafe.AsRef(operation).Invoke(in rows, buffer.Memory.Span); return; }