From 1968d3724fa81ac381145d4acc1dd1d36e89154f Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 5 Feb 2021 18:18:15 +0100 Subject: [PATCH 1/5] better JpegEncoder profiling/benchmarks --- .../Formats/Jpeg/Components/Block8x8F.cs | 4 ++-- src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs | 6 +++--- .../Codecs/Jpeg/EncodeJpeg.cs | 13 ++++++++----- .../ImageSharp.Tests.ProfilingSandbox/Program.cs | 9 ++++++++- .../JpegProfilingBenchmarks.cs | 15 +++++++++++++++ 5 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs index ddbac2d072..56afae68c7 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs @@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// The float value at the specified index public float this[int idx] { - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] get { GuardBlockIndex(idx); @@ -67,7 +67,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components return Unsafe.Add(ref selfRef, idx); } - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] set { GuardBlockIndex(idx); diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index 422c7bd7ec..d26fbb936d 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -315,7 +315,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// The packed bits. /// The number of bits /// The reference to the emitBuffer. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private void Emit(uint bits, uint count, ref byte emitBufferBase) { count += this.bitCount; @@ -356,7 +356,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// The index of the Huffman encoder /// The value to encode. /// The reference to the emit buffer. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private void EmitHuff(HuffIndex index, int value, ref byte emitBufferBase) { uint x = HuffmanLut.TheHuffmanLut[(int)index].Values[value]; @@ -370,7 +370,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// The number of copies to encode. /// The value to encode. /// The reference to the emit buffer. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private void EmitHuffRLE(HuffIndex index, int runLength, int value, ref byte emitBufferBase) { int a = value; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpeg.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpeg.cs index 81a5604f1e..5a9ceea946 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpeg.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpeg.cs @@ -16,17 +16,20 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg private Stream bmpStream; private SDImage bmpDrawing; private Image bmpCore; + private MemoryStream destinationStream; [GlobalSetup] public void ReadImages() { if (this.bmpStream == null) { - const string TestImage = TestImages.Bmp.NegHeight; + const string TestImage = TestImages.Jpeg.BenchmarkSuite.Jpeg420Exif_MidSizeYCbCr; this.bmpStream = File.OpenRead(Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, TestImage)); this.bmpCore = Image.Load(this.bmpStream); + this.bmpCore.Metadata.ExifProfile = null; this.bmpStream.Position = 0; this.bmpDrawing = SDImage.FromStream(this.bmpStream); + this.destinationStream = new MemoryStream(); } } @@ -42,15 +45,15 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg [Benchmark(Baseline = true, Description = "System.Drawing Jpeg")] public void JpegSystemDrawing() { - using var stream = new MemoryStream(); - this.bmpDrawing.Save(stream, ImageFormat.Jpeg); + this.bmpDrawing.Save(this.destinationStream, ImageFormat.Jpeg); + this.destinationStream.Seek(0, SeekOrigin.Begin); } [Benchmark(Description = "ImageSharp Jpeg")] public void JpegCore() { - using var stream = new MemoryStream(); - this.bmpCore.SaveAsJpeg(stream); + this.bmpCore.SaveAsJpeg(this.destinationStream); + this.destinationStream.Seek(0, SeekOrigin.Begin); } } } diff --git a/tests/ImageSharp.Tests.ProfilingSandbox/Program.cs b/tests/ImageSharp.Tests.ProfilingSandbox/Program.cs index 5504a99784..50a930b6f1 100644 --- a/tests/ImageSharp.Tests.ProfilingSandbox/Program.cs +++ b/tests/ImageSharp.Tests.ProfilingSandbox/Program.cs @@ -31,14 +31,21 @@ namespace SixLabors.ImageSharp.Tests.ProfilingSandbox /// public static void Main(string[] args) { + RunJpegEncoderProfilingTests(); // RunJpegColorProfilingTests(); - RunDecodeJpegProfilingTests(); + // RunDecodeJpegProfilingTests(); // RunToVector4ProfilingTest(); // RunResizeProfilingTest(); Console.ReadLine(); } + private static void RunJpegEncoderProfilingTests() + { + var benchmarks = new JpegProfilingBenchmarks(new ConsoleOutput()); + benchmarks.EncodeJpeg_SingleMidSize(); + } + private static void RunJpegColorProfilingTests() { new JpegColorConverterTests(new ConsoleOutput()).BenchmarkYCbCr(false); diff --git a/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegProfilingBenchmarks.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegProfilingBenchmarks.cs index 78fb99802e..9de3fc8dfe 100644 --- a/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegProfilingBenchmarks.cs +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegProfilingBenchmarks.cs @@ -75,6 +75,21 @@ namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks #pragma warning restore SA1515 // Single-line comment should be preceded by blank line } + [Fact(Skip = ProfilingSetup.SkipProfilingTests)] + public void EncodeJpeg_SingleMidSize() + { + string path = TestFile.GetInputFileFullPath(TestImages.Jpeg.BenchmarkSuite.Jpeg420Exif_MidSizeYCbCr); + using var image = Image.Load(path); + image.Metadata.ExifProfile = null; + + using var ms = new MemoryStream(); + for (int i = 0; i < 30; i++) + { + image.SaveAsJpeg(ms); + ms.Seek(0, SeekOrigin.Begin); + } + } + // Benchmark, enable manually! [Theory(Skip = ProfilingSetup.SkipProfilingTests)] [InlineData(1, 75, JpegSubsample.Ratio420)] From 7e0a43bcdb3d1f81b90f50e50d33f158f8771838 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 5 Feb 2021 18:35:10 +0100 Subject: [PATCH 2/5] change inlining options for RowOctet.Update() --- src/ImageSharp/Formats/Jpeg/Components/RowOctet.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/RowOctet.cs b/src/ImageSharp/Formats/Jpeg/Components/RowOctet.cs index f35bb44682..16d24cf814 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/RowOctet.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/RowOctet.cs @@ -75,7 +75,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components } } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void Update(Buffer2D buffer, int startY) { // We don't actually have to assign values outside of the From ae5657f9a9ca048ce41937313a59aeca12556c53 Mon Sep 17 00:00:00 2001 From: Ken Dale Date: Fri, 5 Feb 2021 15:54:44 -0500 Subject: [PATCH 3/5] Small edit --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6b2fa5d0f5..14352bd80e 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ To clone ImageSharp locally, click the "Clone in [YOUR_OS]" button above or run git clone https://github.com/SixLabors/ImageSharp ``` -If working with Windows please ensure that you have enabled log file paths in git (run as Administrator). +If working with Windows please ensure that you have enabled long file paths in git (run as Administrator). ```bash git config --system core.longpaths true @@ -130,4 +130,4 @@ Become a bronze sponsor with a monthly donation of $100 and get your logo (small - \ No newline at end of file + From de191995e128d435a8c1ef6f11c91f27666403fc Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sat, 13 Feb 2021 06:23:55 +0100 Subject: [PATCH 4/5] Add check for Avx2 in ResizeKernel, fix #1546 --- .../Processing/Processors/Transforms/Resize/ResizeKernel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs index 979206ad5c..66f885f23a 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs @@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms public Vector4 ConvolveCore(ref Vector4 rowStartRef) { #if SUPPORTS_RUNTIME_INTRINSICS - if (Fma.IsSupported) + if (Avx2.IsSupported && Fma.IsSupported) { float* bufferStart = this.bufferPtr; float* bufferEnd = bufferStart + (this.Length & ~3); From ce6f067935ca88818439f54f5694ca219a0691ec Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sat, 13 Feb 2021 06:49:32 +0100 Subject: [PATCH 5/5] Add resize test for HwIntrinsics --- .../Processing/Transforms/ResizeTests.cs | 21 +++++++++++++++++++ .../Tests/FeatureTestRunnerTests.cs | 6 +++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ResizeTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/ResizeTests.cs index bf412739d9..5f426083c2 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/ResizeTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/ResizeTests.cs @@ -1,8 +1,10 @@ // Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. +using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Transforms; +using SixLabors.ImageSharp.Tests.TestUtilities; using Xunit; namespace SixLabors.ImageSharp.Tests.Processing.Transforms @@ -85,5 +87,24 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms Assert.Equal(compand, resizeOptions.Compand); Assert.Equal(mode, resizeOptions.Mode); } + +#if SUPPORTS_RUNTIME_INTRINSICS + [Fact] + public void HwIntrinsics_Resize() + { + static void RunTest() + { + using var image = new Image(50, 50); + image.Mutate(img => img.Resize(25, 25)); + + Assert.Equal(25, image.Width); + Assert.Equal(25, image.Height); + } + + FeatureTestRunner.RunWithHwIntrinsicsFeature( + RunTest, + HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX2 | HwIntrinsics.DisableFMA); + } +#endif } } diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs index 4cbbefe686..a2f36c85a8 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs @@ -25,9 +25,9 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.Tests [Theory] [MemberData(nameof(Intrinsics))] - public void ToFeatureCollectionReturnsExpectedResult(HwIntrinsics expectedItrinsics, string[] expectedValues) + public void ToFeatureCollectionReturnsExpectedResult(HwIntrinsics expectedIntrinsics, string[] expectedValues) { - Dictionary features = expectedItrinsics.ToFeatureKeyValueCollection(); + Dictionary features = expectedIntrinsics.ToFeatureKeyValueCollection(); HwIntrinsics[] keys = features.Keys.ToArray(); HwIntrinsics actualIntrinsics = keys[0]; @@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.Tests actualIntrinsics |= keys[i]; } - Assert.Equal(expectedItrinsics, actualIntrinsics); + Assert.Equal(expectedIntrinsics, actualIntrinsics); IEnumerable actualValues = features.Select(x => x.Value); Assert.Equal(expectedValues, actualValues);