From 18d6076f50cf455c6609caada022c93682202354 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 15 Oct 2020 21:32:37 +0100 Subject: [PATCH 01/17] Add FeatureTestRunner --- .../FeatureTesting/FeatureTestRunner.cs | 266 ++++++++++++++++++ .../Tests/FeatureTestRunnerTests.cs | 237 ++++++++++++++++ 2 files changed, 503 insertions(+) create mode 100644 tests/ImageSharp.Tests/TestUtilities/FeatureTesting/FeatureTestRunner.cs create mode 100644 tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs diff --git a/tests/ImageSharp.Tests/TestUtilities/FeatureTesting/FeatureTestRunner.cs b/tests/ImageSharp.Tests/TestUtilities/FeatureTesting/FeatureTestRunner.cs new file mode 100644 index 0000000000..57ed85a182 --- /dev/null +++ b/tests/ImageSharp.Tests/TestUtilities/FeatureTesting/FeatureTestRunner.cs @@ -0,0 +1,266 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using Microsoft.DotNet.RemoteExecutor; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.TestUtilities +{ + /// + /// Allows the testing against specific feature sets. + /// + public static class FeatureTestRunner + { + private static readonly char[] SplitChars = new[] { ',', ' ' }; + + /// + /// Allows the deserialization of parameters passed to the feature test. + /// + /// + /// This is required because does not allow + /// marshalling of fields so we cannot pass a wrapped + /// allowing automatic deserialization. + /// + /// + /// + /// The type to deserialize to. + /// The string value to deserialize. + /// The value. + public static T Deserialize(string value) + where T : IXunitSerializable + => BasicSerializer.Deserialize(value); + + /// + /// Runs the given test within an environment + /// where the given features. + /// + /// The test action to run. + /// The intrinsics features. + public static void RunWithHwIntrinsicsFeature( + Action action, + HwIntrinsics intrinsics) + { + if (!RemoteExecutor.IsSupported) + { + return; + } + + foreach (KeyValuePair intrinsic in intrinsics.ToFeatureKeyValueCollection()) + { + var processStartInfo = new ProcessStartInfo(); + if (intrinsic.Key != HwIntrinsics.AllowAll) + { + processStartInfo.Environment[$"COMPlus_Enable{intrinsic}"] = "0"; + + RemoteExecutor.Invoke( + action, + new RemoteInvokeOptions + { + StartInfo = processStartInfo + }) + .Dispose(); + } + else + { + // Since we are running using the default architecture there is no + // point creating the overhead of running the action in a separate process. + action(); + } + } + } + + /// + /// Runs the given test within an environment + /// where the given features. + /// + /// + /// The test action to run. + /// The parameter passed will be a string representing the currently testing . + /// The intrinsics features. + public static void RunWithHwIntrinsicsFeature( + Action action, + HwIntrinsics intrinsics) + { + if (!RemoteExecutor.IsSupported) + { + return; + } + + foreach (KeyValuePair intrinsic in intrinsics.ToFeatureKeyValueCollection()) + { + var processStartInfo = new ProcessStartInfo(); + if (intrinsic.Key != HwIntrinsics.AllowAll) + { + processStartInfo.Environment[$"COMPlus_Enable{intrinsic}"] = "0"; + + RemoteExecutor.Invoke( + action, + intrinsic.Key.ToString(), + new RemoteInvokeOptions + { + StartInfo = processStartInfo + }) + .Dispose(); + } + else + { + // Since we are running using the default architecture there is no + // point creating the overhead of running the action in a separate process. + action(intrinsic.Key.ToString()); + } + } + } + + /// + /// Runs the given test within an environment + /// where the given features. + /// + /// The test action to run. + /// The intrinsics features. + /// The value to pass as a parameter to the test action. + public static void RunWithHwIntrinsicsFeature( + Action action, + HwIntrinsics intrinsics, + T serializable) + where T : IXunitSerializable + { + if (!RemoteExecutor.IsSupported) + { + return; + } + + foreach (KeyValuePair intrinsic in intrinsics.ToFeatureKeyValueCollection()) + { + var processStartInfo = new ProcessStartInfo(); + if (intrinsic.Key != HwIntrinsics.AllowAll) + { + processStartInfo.Environment[$"COMPlus_Enable{intrinsic}"] = "0"; + + RemoteExecutor.Invoke( + action, + BasicSerializer.Serialize(serializable), + new RemoteInvokeOptions + { + StartInfo = processStartInfo + }) + .Dispose(); + } + else + { + // Since we are running using the default architecture there is no + // point creating the overhead of running the action in a separate process. + action(BasicSerializer.Serialize(serializable)); + } + } + } + + /// + /// Runs the given test within an environment + /// where the given features. + /// + /// The test action to run. + /// The intrinsics features. + /// The value to pass as a parameter to the test action. + public static void RunWithHwIntrinsicsFeature( + Action action, + HwIntrinsics intrinsics, + T serializable) + where T : IXunitSerializable + { + if (!RemoteExecutor.IsSupported) + { + return; + } + + foreach (KeyValuePair intrinsic in intrinsics.ToFeatureKeyValueCollection()) + { + var processStartInfo = new ProcessStartInfo(); + if (intrinsic.Key != HwIntrinsics.AllowAll) + { + processStartInfo.Environment[$"COMPlus_Enable{intrinsic}"] = "0"; + + RemoteExecutor.Invoke( + action, + BasicSerializer.Serialize(serializable), + intrinsic.Key.ToString(), + new RemoteInvokeOptions + { + StartInfo = processStartInfo + }) + .Dispose(); + } + else + { + // Since we are running using the default architecture there is no + // point creating the overhead of running the action in a separate process. + action(BasicSerializer.Serialize(serializable), intrinsic.Key.ToString()); + } + } + } + + internal static Dictionary ToFeatureKeyValueCollection(this HwIntrinsics intrinsics) + { + // Loop through and translate the given values into COMPlus equivaluents + var features = new Dictionary(); + foreach (string intrinsic in intrinsics.ToString("G").Split(SplitChars, StringSplitOptions.RemoveEmptyEntries)) + { + var key = (HwIntrinsics)Enum.Parse(typeof(HwIntrinsics), intrinsic); + switch (intrinsic) + { + case nameof(HwIntrinsics.DisableSIMD): + features.Add(key, "FeatureSIMD"); + break; + + case nameof(HwIntrinsics.AllowAll): + + // Not a COMPlus value. We filter in calling method. + features.Add(key, nameof(HwIntrinsics.AllowAll)); + break; + + default: + features.Add(key, intrinsic.Replace("Disable", "Enable")); + break; + } + } + + return features; + } + } + + /// + /// See + /// + /// ends up impacting all SIMD support(including System.Numerics) + /// but not things like , , and . + /// + /// + [Flags] +#pragma warning disable RCS1135 // Declare enum member with zero value (when enum has FlagsAttribute). + public enum HwIntrinsics +#pragma warning restore RCS1135 // Declare enum member with zero value (when enum has FlagsAttribute). + { + // Use flags so we can pass multiple values without using params. + // Don't base on 0 or use inverse for All as that doesn't translate to string values. + DisableSIMD = 1 << 0, + DisableHWIntrinsic = 1 << 1, + DisableSSE = 1 << 2, + DisableSSE2 = 1 << 3, + DisableAES = 1 << 4, + DisablePCLMULQDQ = 1 << 5, + DisableSSE3 = 1 << 6, + DisableSSSE3 = 1 << 7, + DisableSSE41 = 1 << 8, + DisableSSE42 = 1 << 9, + DisablePOPCNT = 1 << 10, + DisableAVX = 1 << 11, + DisableFMA = 1 << 12, + DisableAVX2 = 1 << 13, + DisableBMI1 = 1 << 14, + DisableBMI2 = 1 << 15, + DisableLZCNT = 1 << 16, + AllowAll = 1 << 17 + } +} diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs new file mode 100644 index 0000000000..9852ba3478 --- /dev/null +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs @@ -0,0 +1,237 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +#if SUPPORTS_RUNTIME_INTRINSICS +using System.Runtime.Intrinsics.X86; +#endif +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.TestUtilities.Tests +{ + public class FeatureTestRunnerTests + { + public static TheoryData Intrinsics => + new TheoryData + { + { HwIntrinsics.DisableAES | HwIntrinsics.AllowAll, new string[] { "EnableAES", "AllowAll" } }, + { HwIntrinsics.DisableSIMD | HwIntrinsics.DisableHWIntrinsic, new string[] { "FeatureSIMD", "EnableHWIntrinsic" } }, + { HwIntrinsics.DisableSSE42 | HwIntrinsics.DisableAVX, new string[] { "EnableSSE42", "EnableAVX" } } + }; + + [Theory] + [MemberData(nameof(Intrinsics))] + public void ToFeatureCollectionReturnsExpectedResult(HwIntrinsics expectedItrinsics, string[] expectedValues) + { + Dictionary features = expectedItrinsics.ToFeatureKeyValueCollection(); + HwIntrinsics[] keys = features.Keys.ToArray(); + + HwIntrinsics actualIntrinsics = keys[0]; + for (int i = 1; i < keys.Length; i++) + { + actualIntrinsics |= keys[i]; + } + + Assert.Equal(expectedItrinsics, actualIntrinsics); + + IEnumerable actualValues = features.Select(x => x.Value); + Assert.Equal(expectedValues, actualValues); + } + + [Fact] + public void AllowsAllHwIntrinsicFeatures() + { + FeatureTestRunner.RunWithHwIntrinsicsFeature( + () => Assert.True(Vector.IsHardwareAccelerated), + HwIntrinsics.AllowAll); + } + + [Fact] + public void CanLimitHwIntrinsicFeatures() + { + FeatureTestRunner.RunWithHwIntrinsicsFeature( + () => Assert.False(Vector.IsHardwareAccelerated), + HwIntrinsics.DisableSIMD); + } + + [Fact] + public void CanLimitHwIntrinsicFeaturesWithIntrinsicsParam() + { + static void AssertHwIntrinsicsFeatureDisabled(string intrinsic) + { + Assert.NotNull(intrinsic); + + switch ((HwIntrinsics)Enum.Parse(typeof(HwIntrinsics), intrinsic)) + { + case HwIntrinsics.DisableSIMD: + Assert.False(Vector.IsHardwareAccelerated); + break; +#if SUPPORTS_RUNTIME_INTRINSICS + case HwIntrinsics.DisableHWIntrinsic: + Assert.False(Vector.IsHardwareAccelerated); + break; + case HwIntrinsics.DisableSSE: + Assert.False(Sse.IsSupported); + break; + case HwIntrinsics.DisableSSE2: + Assert.False(Sse2.IsSupported); + break; + case HwIntrinsics.DisableAES: + Assert.False(Aes.IsSupported); + break; + case HwIntrinsics.DisablePCLMULQDQ: + Assert.False(Pclmulqdq.IsSupported); + break; + case HwIntrinsics.DisableSSE3: + Assert.False(Sse3.IsSupported); + break; + case HwIntrinsics.DisableSSSE3: + Assert.False(Ssse3.IsSupported); + break; + case HwIntrinsics.DisableSSE41: + Assert.False(Sse41.IsSupported); + break; + case HwIntrinsics.DisableSSE42: + Assert.False(Sse42.IsSupported); + break; + case HwIntrinsics.DisablePOPCNT: + Assert.False(Popcnt.IsSupported); + break; + case HwIntrinsics.DisableAVX: + Assert.False(Avx.IsSupported); + break; + case HwIntrinsics.DisableFMA: + Assert.False(Fma.IsSupported); + break; + case HwIntrinsics.DisableAVX2: + Assert.False(Avx2.IsSupported); + break; + case HwIntrinsics.DisableBMI1: + Assert.False(Bmi1.IsSupported); + break; + case HwIntrinsics.DisableBMI2: + Assert.False(Bmi2.IsSupported); + break; + case HwIntrinsics.DisableLZCNT: + Assert.False(Lzcnt.IsSupported); + break; +#endif + } + } + + foreach (HwIntrinsics intrinsic in (HwIntrinsics[])Enum.GetValues(typeof(HwIntrinsics))) + { + FeatureTestRunner.RunWithHwIntrinsicsFeature(AssertHwIntrinsicsFeatureDisabled, intrinsic); + } + } + + [Fact] + public void CanLimitHwIntrinsicFeaturesWithSerializableParam() + { + static void AssertHwIntrinsicsFeatureDisabled(string serializable) + { + Assert.NotNull(serializable); + Assert.NotNull(FeatureTestRunner.Deserialize(serializable)); + +#if SUPPORTS_RUNTIME_INTRINSICS + Assert.False(Sse.IsSupported); +#endif + } + + foreach (HwIntrinsics intrinsic in (HwIntrinsics[])Enum.GetValues(typeof(HwIntrinsics))) + { + FeatureTestRunner.RunWithHwIntrinsicsFeature( + AssertHwIntrinsicsFeatureDisabled, + HwIntrinsics.DisableSSE, + new FakeSerializable()); + } + } + + [Fact] + public void CanLimitHwIntrinsicFeaturesWithSerializableAndIntrinsicsParams() + { + static void AssertHwIntrinsicsFeatureDisabled(string serializable, string intrinsic) + { + Assert.NotNull(serializable); + Assert.NotNull(FeatureTestRunner.Deserialize(serializable)); + + switch ((HwIntrinsics)Enum.Parse(typeof(HwIntrinsics), intrinsic)) + { + case HwIntrinsics.DisableSIMD: + Assert.False(Vector.IsHardwareAccelerated); + break; +#if SUPPORTS_RUNTIME_INTRINSICS + case HwIntrinsics.DisableHWIntrinsic: + Assert.False(Vector.IsHardwareAccelerated); + break; + case HwIntrinsics.DisableSSE: + Assert.False(Sse.IsSupported); + break; + case HwIntrinsics.DisableSSE2: + Assert.False(Sse2.IsSupported); + break; + case HwIntrinsics.DisableAES: + Assert.False(Aes.IsSupported); + break; + case HwIntrinsics.DisablePCLMULQDQ: + Assert.False(Pclmulqdq.IsSupported); + break; + case HwIntrinsics.DisableSSE3: + Assert.False(Sse3.IsSupported); + break; + case HwIntrinsics.DisableSSSE3: + Assert.False(Ssse3.IsSupported); + break; + case HwIntrinsics.DisableSSE41: + Assert.False(Sse41.IsSupported); + break; + case HwIntrinsics.DisableSSE42: + Assert.False(Sse42.IsSupported); + break; + case HwIntrinsics.DisablePOPCNT: + Assert.False(Popcnt.IsSupported); + break; + case HwIntrinsics.DisableAVX: + Assert.False(Avx.IsSupported); + break; + case HwIntrinsics.DisableFMA: + Assert.False(Fma.IsSupported); + break; + case HwIntrinsics.DisableAVX2: + Assert.False(Avx2.IsSupported); + break; + case HwIntrinsics.DisableBMI1: + Assert.False(Bmi1.IsSupported); + break; + case HwIntrinsics.DisableBMI2: + Assert.False(Bmi2.IsSupported); + break; + case HwIntrinsics.DisableLZCNT: + Assert.False(Lzcnt.IsSupported); + break; +#endif + } + } + + foreach (HwIntrinsics intrinsic in (HwIntrinsics[])Enum.GetValues(typeof(HwIntrinsics))) + { + FeatureTestRunner.RunWithHwIntrinsicsFeature(AssertHwIntrinsicsFeatureDisabled, intrinsic, new FakeSerializable()); + } + } + + public class FakeSerializable : IXunitSerializable + { + public void Deserialize(IXunitSerializationInfo info) + { + } + + public void Serialize(IXunitSerializationInfo info) + { + } + } + } +} From 296d9f622009d51cf4187d06d00bfc7b2154a75d Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 15 Oct 2020 21:36:51 +0100 Subject: [PATCH 02/17] Use single Block8x8F.TransponseInto test --- .../Formats/Jpg/Block8x8FTests.cs | 48 +++++++------------ 1 file changed, 17 insertions(+), 31 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs index 73a68063c0..5482380885 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs @@ -5,10 +5,9 @@ // #define BENCHMARKING using System; using System.Diagnostics; - using SixLabors.ImageSharp.Formats.Jpeg.Components; using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils; - +using SixLabors.ImageSharp.Tests.TestUtilities; using Xunit; using Xunit.Abstractions; @@ -163,42 +162,29 @@ public void Load_Store_IntArray() } [Fact] - public void TransposeIntoFallback() + public void TransposeInto() { - float[] expected = Create8x8FloatData(); - ReferenceImplementations.Transpose8x8(expected); - - var source = default(Block8x8F); - source.LoadFrom(Create8x8FloatData()); - - var dest = default(Block8x8F); - source.TransposeIntoFallback(ref dest); - - float[] actual = new float[64]; - dest.ScaledCopyTo(actual); - - Assert.Equal(expected, actual); - } + static void RunTest() + { + float[] expected = Create8x8FloatData(); + ReferenceImplementations.Transpose8x8(expected); -#if SUPPORTS_RUNTIME_INTRINSICS - [Fact] - public void TransposeIntoAvx() - { - float[] expected = Create8x8FloatData(); - ReferenceImplementations.Transpose8x8(expected); + var source = default(Block8x8F); + source.LoadFrom(Create8x8FloatData()); - var source = default(Block8x8F); - source.LoadFrom(Create8x8FloatData()); + var dest = default(Block8x8F); + source.TransposeInto(ref dest); - var dest = default(Block8x8F); - source.TransposeIntoAvx(ref dest); + float[] actual = new float[64]; + dest.ScaledCopyTo(actual); - float[] actual = new float[64]; - dest.ScaledCopyTo(actual); + Assert.Equal(expected, actual); + } - Assert.Equal(expected, actual); + FeatureTestRunner.RunWithHwIntrinsicsFeature( + RunTest, + HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX); } -#endif private class BufferHolder { From ca06595d3e3ade4917a2c085ca0587a0d515ede3 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 15 Oct 2020 21:58:24 +0100 Subject: [PATCH 03/17] Ensure remoteexecutor tests run --- .github/workflows/build-and-test.yml | 32 +++++++++---------- .../Tests/FeatureTestRunnerTests.cs | 8 +++++ 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index c8f3997946..ecb5ceb0ef 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -17,23 +17,23 @@ jobs: - os: ubuntu-latest framework: netcoreapp3.1 runtime: -x64 - codecov: true - - os: windows-latest - framework: netcoreapp3.1 - runtime: -x64 - codecov: false - - os: windows-latest - framework: netcoreapp2.1 - runtime: -x64 - codecov: false - - os: windows-latest - framework: net472 - runtime: -x64 - codecov: false - - os: windows-latest - framework: net472 - runtime: -x86 codecov: false + # - os: windows-latest + # framework: netcoreapp3.1 + # runtime: -x64 + # codecov: false + # - os: windows-latest + # framework: netcoreapp2.1 + # runtime: -x64 + # codecov: false + # - os: windows-latest + # framework: net472 + # runtime: -x64 + # codecov: false + # - os: windows-latest + # framework: net472 + # runtime: -x86 + # codecov: false runs-on: ${{matrix.options.os}} if: "!contains(github.event.head_commit.message, '[skip ci]')" diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs index 9852ba3478..070f205748 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs @@ -23,6 +23,14 @@ public class FeatureTestRunnerTests { HwIntrinsics.DisableSSE42 | HwIntrinsics.DisableAVX, new string[] { "EnableSSE42", "EnableAVX" } } }; + [Fact] + public void TempAssertThrow() + { + FeatureTestRunner.RunWithHwIntrinsicsFeature( + () => Assert.True(false), + HwIntrinsics.DisableAVX); + } + [Theory] [MemberData(nameof(Intrinsics))] public void ToFeatureCollectionReturnsExpectedResult(HwIntrinsics expectedItrinsics, string[] expectedValues) From bef379392ebe80cf967e7340b3b38b681a68add8 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 15 Oct 2020 22:12:40 +0100 Subject: [PATCH 04/17] Increment tests --- .../Tests/FeatureTestRunnerTests.cs | 340 +++++++++--------- 1 file changed, 166 insertions(+), 174 deletions(-) diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs index 070f205748..023679b2e0 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs @@ -23,14 +23,6 @@ public class FeatureTestRunnerTests { HwIntrinsics.DisableSSE42 | HwIntrinsics.DisableAVX, new string[] { "EnableSSE42", "EnableAVX" } } }; - [Fact] - public void TempAssertThrow() - { - FeatureTestRunner.RunWithHwIntrinsicsFeature( - () => Assert.True(false), - HwIntrinsics.DisableAVX); - } - [Theory] [MemberData(nameof(Intrinsics))] public void ToFeatureCollectionReturnsExpectedResult(HwIntrinsics expectedItrinsics, string[] expectedValues) @@ -54,7 +46,7 @@ public void ToFeatureCollectionReturnsExpectedResult(HwIntrinsics expectedItrins public void AllowsAllHwIntrinsicFeatures() { FeatureTestRunner.RunWithHwIntrinsicsFeature( - () => Assert.True(Vector.IsHardwareAccelerated), + () => Assert.True(Vector.IsHardwareAccelerated, nameof(Vector.IsHardwareAccelerated)), HwIntrinsics.AllowAll); } @@ -62,174 +54,174 @@ public void AllowsAllHwIntrinsicFeatures() public void CanLimitHwIntrinsicFeatures() { FeatureTestRunner.RunWithHwIntrinsicsFeature( - () => Assert.False(Vector.IsHardwareAccelerated), + () => Assert.False(Vector.IsHardwareAccelerated, nameof(Vector.IsHardwareAccelerated)), HwIntrinsics.DisableSIMD); } - [Fact] - public void CanLimitHwIntrinsicFeaturesWithIntrinsicsParam() - { - static void AssertHwIntrinsicsFeatureDisabled(string intrinsic) - { - Assert.NotNull(intrinsic); - - switch ((HwIntrinsics)Enum.Parse(typeof(HwIntrinsics), intrinsic)) - { - case HwIntrinsics.DisableSIMD: - Assert.False(Vector.IsHardwareAccelerated); - break; -#if SUPPORTS_RUNTIME_INTRINSICS - case HwIntrinsics.DisableHWIntrinsic: - Assert.False(Vector.IsHardwareAccelerated); - break; - case HwIntrinsics.DisableSSE: - Assert.False(Sse.IsSupported); - break; - case HwIntrinsics.DisableSSE2: - Assert.False(Sse2.IsSupported); - break; - case HwIntrinsics.DisableAES: - Assert.False(Aes.IsSupported); - break; - case HwIntrinsics.DisablePCLMULQDQ: - Assert.False(Pclmulqdq.IsSupported); - break; - case HwIntrinsics.DisableSSE3: - Assert.False(Sse3.IsSupported); - break; - case HwIntrinsics.DisableSSSE3: - Assert.False(Ssse3.IsSupported); - break; - case HwIntrinsics.DisableSSE41: - Assert.False(Sse41.IsSupported); - break; - case HwIntrinsics.DisableSSE42: - Assert.False(Sse42.IsSupported); - break; - case HwIntrinsics.DisablePOPCNT: - Assert.False(Popcnt.IsSupported); - break; - case HwIntrinsics.DisableAVX: - Assert.False(Avx.IsSupported); - break; - case HwIntrinsics.DisableFMA: - Assert.False(Fma.IsSupported); - break; - case HwIntrinsics.DisableAVX2: - Assert.False(Avx2.IsSupported); - break; - case HwIntrinsics.DisableBMI1: - Assert.False(Bmi1.IsSupported); - break; - case HwIntrinsics.DisableBMI2: - Assert.False(Bmi2.IsSupported); - break; - case HwIntrinsics.DisableLZCNT: - Assert.False(Lzcnt.IsSupported); - break; -#endif - } - } - - foreach (HwIntrinsics intrinsic in (HwIntrinsics[])Enum.GetValues(typeof(HwIntrinsics))) - { - FeatureTestRunner.RunWithHwIntrinsicsFeature(AssertHwIntrinsicsFeatureDisabled, intrinsic); - } - } - - [Fact] - public void CanLimitHwIntrinsicFeaturesWithSerializableParam() - { - static void AssertHwIntrinsicsFeatureDisabled(string serializable) - { - Assert.NotNull(serializable); - Assert.NotNull(FeatureTestRunner.Deserialize(serializable)); - -#if SUPPORTS_RUNTIME_INTRINSICS - Assert.False(Sse.IsSupported); -#endif - } - - foreach (HwIntrinsics intrinsic in (HwIntrinsics[])Enum.GetValues(typeof(HwIntrinsics))) - { - FeatureTestRunner.RunWithHwIntrinsicsFeature( - AssertHwIntrinsicsFeatureDisabled, - HwIntrinsics.DisableSSE, - new FakeSerializable()); - } - } - - [Fact] - public void CanLimitHwIntrinsicFeaturesWithSerializableAndIntrinsicsParams() - { - static void AssertHwIntrinsicsFeatureDisabled(string serializable, string intrinsic) - { - Assert.NotNull(serializable); - Assert.NotNull(FeatureTestRunner.Deserialize(serializable)); - - switch ((HwIntrinsics)Enum.Parse(typeof(HwIntrinsics), intrinsic)) - { - case HwIntrinsics.DisableSIMD: - Assert.False(Vector.IsHardwareAccelerated); - break; -#if SUPPORTS_RUNTIME_INTRINSICS - case HwIntrinsics.DisableHWIntrinsic: - Assert.False(Vector.IsHardwareAccelerated); - break; - case HwIntrinsics.DisableSSE: - Assert.False(Sse.IsSupported); - break; - case HwIntrinsics.DisableSSE2: - Assert.False(Sse2.IsSupported); - break; - case HwIntrinsics.DisableAES: - Assert.False(Aes.IsSupported); - break; - case HwIntrinsics.DisablePCLMULQDQ: - Assert.False(Pclmulqdq.IsSupported); - break; - case HwIntrinsics.DisableSSE3: - Assert.False(Sse3.IsSupported); - break; - case HwIntrinsics.DisableSSSE3: - Assert.False(Ssse3.IsSupported); - break; - case HwIntrinsics.DisableSSE41: - Assert.False(Sse41.IsSupported); - break; - case HwIntrinsics.DisableSSE42: - Assert.False(Sse42.IsSupported); - break; - case HwIntrinsics.DisablePOPCNT: - Assert.False(Popcnt.IsSupported); - break; - case HwIntrinsics.DisableAVX: - Assert.False(Avx.IsSupported); - break; - case HwIntrinsics.DisableFMA: - Assert.False(Fma.IsSupported); - break; - case HwIntrinsics.DisableAVX2: - Assert.False(Avx2.IsSupported); - break; - case HwIntrinsics.DisableBMI1: - Assert.False(Bmi1.IsSupported); - break; - case HwIntrinsics.DisableBMI2: - Assert.False(Bmi2.IsSupported); - break; - case HwIntrinsics.DisableLZCNT: - Assert.False(Lzcnt.IsSupported); - break; -#endif - } - } - - foreach (HwIntrinsics intrinsic in (HwIntrinsics[])Enum.GetValues(typeof(HwIntrinsics))) - { - FeatureTestRunner.RunWithHwIntrinsicsFeature(AssertHwIntrinsicsFeatureDisabled, intrinsic, new FakeSerializable()); - } - } + // [Fact] + // public void CanLimitHwIntrinsicFeaturesWithIntrinsicsParam() + // { + // static void AssertHwIntrinsicsFeatureDisabled(string intrinsic) + // { + // Assert.NotNull(intrinsic); + + // switch ((HwIntrinsics)Enum.Parse(typeof(HwIntrinsics), intrinsic)) + // { + // case HwIntrinsics.DisableSIMD: + // Assert.False(Vector.IsHardwareAccelerated); + // break; + //#if SUPPORTS_RUNTIME_INTRINSICS + // case HwIntrinsics.DisableHWIntrinsic: + // Assert.False(Vector.IsHardwareAccelerated); + // break; + // case HwIntrinsics.DisableSSE: + // Assert.False(Sse.IsSupported); + // break; + // case HwIntrinsics.DisableSSE2: + // Assert.False(Sse2.IsSupported); + // break; + // case HwIntrinsics.DisableAES: + // Assert.False(Aes.IsSupported); + // break; + // case HwIntrinsics.DisablePCLMULQDQ: + // Assert.False(Pclmulqdq.IsSupported); + // break; + // case HwIntrinsics.DisableSSE3: + // Assert.False(Sse3.IsSupported); + // break; + // case HwIntrinsics.DisableSSSE3: + // Assert.False(Ssse3.IsSupported); + // break; + // case HwIntrinsics.DisableSSE41: + // Assert.False(Sse41.IsSupported); + // break; + // case HwIntrinsics.DisableSSE42: + // Assert.False(Sse42.IsSupported); + // break; + // case HwIntrinsics.DisablePOPCNT: + // Assert.False(Popcnt.IsSupported); + // break; + // case HwIntrinsics.DisableAVX: + // Assert.False(Avx.IsSupported); + // break; + // case HwIntrinsics.DisableFMA: + // Assert.False(Fma.IsSupported); + // break; + // case HwIntrinsics.DisableAVX2: + // Assert.False(Avx2.IsSupported); + // break; + // case HwIntrinsics.DisableBMI1: + // Assert.False(Bmi1.IsSupported); + // break; + // case HwIntrinsics.DisableBMI2: + // Assert.False(Bmi2.IsSupported); + // break; + // case HwIntrinsics.DisableLZCNT: + // Assert.False(Lzcnt.IsSupported); + // break; + //#endif + // } + // } + + // foreach (HwIntrinsics intrinsic in (HwIntrinsics[])Enum.GetValues(typeof(HwIntrinsics))) + // { + // FeatureTestRunner.RunWithHwIntrinsicsFeature(AssertHwIntrinsicsFeatureDisabled, intrinsic); + // } + // } + + // [Fact] + // public void CanLimitHwIntrinsicFeaturesWithSerializableParam() + // { + // static void AssertHwIntrinsicsFeatureDisabled(string serializable) + // { + // Assert.NotNull(serializable); + // Assert.NotNull(FeatureTestRunner.Deserialize(serializable)); + + //#if SUPPORTS_RUNTIME_INTRINSICS + // Assert.False(Sse.IsSupported); + //#endif + // } + + // foreach (HwIntrinsics intrinsic in (HwIntrinsics[])Enum.GetValues(typeof(HwIntrinsics))) + // { + // FeatureTestRunner.RunWithHwIntrinsicsFeature( + // AssertHwIntrinsicsFeatureDisabled, + // HwIntrinsics.DisableSSE, + // new FakeSerializable()); + // } + // } + + // [Fact] + // public void CanLimitHwIntrinsicFeaturesWithSerializableAndIntrinsicsParams() + // { + // static void AssertHwIntrinsicsFeatureDisabled(string serializable, string intrinsic) + // { + // Assert.NotNull(serializable); + // Assert.NotNull(FeatureTestRunner.Deserialize(serializable)); + + // switch ((HwIntrinsics)Enum.Parse(typeof(HwIntrinsics), intrinsic)) + // { + // case HwIntrinsics.DisableSIMD: + // Assert.False(Vector.IsHardwareAccelerated, nameof(Vector.IsHardwareAccelerated)); + // break; + //#if SUPPORTS_RUNTIME_INTRINSICS + // case HwIntrinsics.DisableHWIntrinsic: + // Assert.False(Vector.IsHardwareAccelerated, nameof(Vector.IsHardwareAccelerated)); + // break; + // case HwIntrinsics.DisableSSE: + // Assert.False(Sse.IsSupported); + // break; + // case HwIntrinsics.DisableSSE2: + // Assert.False(Sse2.IsSupported); + // break; + // case HwIntrinsics.DisableAES: + // Assert.False(Aes.IsSupported); + // break; + // case HwIntrinsics.DisablePCLMULQDQ: + // Assert.False(Pclmulqdq.IsSupported); + // break; + // case HwIntrinsics.DisableSSE3: + // Assert.False(Sse3.IsSupported); + // break; + // case HwIntrinsics.DisableSSSE3: + // Assert.False(Ssse3.IsSupported); + // break; + // case HwIntrinsics.DisableSSE41: + // Assert.False(Sse41.IsSupported); + // break; + // case HwIntrinsics.DisableSSE42: + // Assert.False(Sse42.IsSupported); + // break; + // case HwIntrinsics.DisablePOPCNT: + // Assert.False(Popcnt.IsSupported); + // break; + // case HwIntrinsics.DisableAVX: + // Assert.False(Avx.IsSupported); + // break; + // case HwIntrinsics.DisableFMA: + // Assert.False(Fma.IsSupported); + // break; + // case HwIntrinsics.DisableAVX2: + // Assert.False(Avx2.IsSupported); + // break; + // case HwIntrinsics.DisableBMI1: + // Assert.False(Bmi1.IsSupported); + // break; + // case HwIntrinsics.DisableBMI2: + // Assert.False(Bmi2.IsSupported); + // break; + // case HwIntrinsics.DisableLZCNT: + // Assert.False(Lzcnt.IsSupported); + // break; + //#endif + // } + // } + + // foreach (HwIntrinsics intrinsic in (HwIntrinsics[])Enum.GetValues(typeof(HwIntrinsics))) + // { + // FeatureTestRunner.RunWithHwIntrinsicsFeature(AssertHwIntrinsicsFeatureDisabled, intrinsic, new FakeSerializable()); + // } + // } public class FakeSerializable : IXunitSerializable { From 4c5a32e686171bae69cd78c67ae76335f1a425b7 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 15 Oct 2020 22:22:08 +0100 Subject: [PATCH 05/17] Fix COMPlus environmental parameters --- .../TestUtilities/FeatureTesting/FeatureTestRunner.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/ImageSharp.Tests/TestUtilities/FeatureTesting/FeatureTestRunner.cs b/tests/ImageSharp.Tests/TestUtilities/FeatureTesting/FeatureTestRunner.cs index 57ed85a182..a053471394 100644 --- a/tests/ImageSharp.Tests/TestUtilities/FeatureTesting/FeatureTestRunner.cs +++ b/tests/ImageSharp.Tests/TestUtilities/FeatureTesting/FeatureTestRunner.cs @@ -53,7 +53,7 @@ public static void RunWithHwIntrinsicsFeature( var processStartInfo = new ProcessStartInfo(); if (intrinsic.Key != HwIntrinsics.AllowAll) { - processStartInfo.Environment[$"COMPlus_Enable{intrinsic}"] = "0"; + processStartInfo.Environment[$"COMPlus_{intrinsic}"] = "0"; RemoteExecutor.Invoke( action, @@ -94,7 +94,7 @@ public static void RunWithHwIntrinsicsFeature( var processStartInfo = new ProcessStartInfo(); if (intrinsic.Key != HwIntrinsics.AllowAll) { - processStartInfo.Environment[$"COMPlus_Enable{intrinsic}"] = "0"; + processStartInfo.Environment[$"COMPlus_{intrinsic}"] = "0"; RemoteExecutor.Invoke( action, @@ -137,7 +137,7 @@ public static void RunWithHwIntrinsicsFeature( var processStartInfo = new ProcessStartInfo(); if (intrinsic.Key != HwIntrinsics.AllowAll) { - processStartInfo.Environment[$"COMPlus_Enable{intrinsic}"] = "0"; + processStartInfo.Environment[$"COMPlus_{intrinsic}"] = "0"; RemoteExecutor.Invoke( action, @@ -180,7 +180,7 @@ public static void RunWithHwIntrinsicsFeature( var processStartInfo = new ProcessStartInfo(); if (intrinsic.Key != HwIntrinsics.AllowAll) { - processStartInfo.Environment[$"COMPlus_Enable{intrinsic}"] = "0"; + processStartInfo.Environment[$"COMPlus_{intrinsic}"] = "0"; RemoteExecutor.Invoke( action, From d50439ee78166dac4aff43f2f32ca232b012e818 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 15 Oct 2020 22:30:11 +0100 Subject: [PATCH 06/17] Test another property to be sure --- .../TestUtilities/Tests/FeatureTestRunnerTests.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs index 023679b2e0..13a0806129 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs @@ -50,13 +50,15 @@ public void AllowsAllHwIntrinsicFeatures() HwIntrinsics.AllowAll); } +#if SUPPORTS_RUNTIME_INTRINSICS [Fact] public void CanLimitHwIntrinsicFeatures() { FeatureTestRunner.RunWithHwIntrinsicsFeature( - () => Assert.False(Vector.IsHardwareAccelerated, nameof(Vector.IsHardwareAccelerated)), - HwIntrinsics.DisableSIMD); + () => Assert.False(Sse.IsSupported, nameof(Sse.IsSupported)), + HwIntrinsics.DisableSSE); } +#endif // [Fact] // public void CanLimitHwIntrinsicFeaturesWithIntrinsicsParam() From 41eb364d7cedbf6cb510a80f394c3203dfc0f4f5 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 15 Oct 2020 22:44:35 +0100 Subject: [PATCH 07/17] Fix COMPlus value properly. --- .../TestUtilities/FeatureTesting/FeatureTestRunner.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/ImageSharp.Tests/TestUtilities/FeatureTesting/FeatureTestRunner.cs b/tests/ImageSharp.Tests/TestUtilities/FeatureTesting/FeatureTestRunner.cs index a053471394..eb1714baad 100644 --- a/tests/ImageSharp.Tests/TestUtilities/FeatureTesting/FeatureTestRunner.cs +++ b/tests/ImageSharp.Tests/TestUtilities/FeatureTesting/FeatureTestRunner.cs @@ -53,7 +53,7 @@ public static void RunWithHwIntrinsicsFeature( var processStartInfo = new ProcessStartInfo(); if (intrinsic.Key != HwIntrinsics.AllowAll) { - processStartInfo.Environment[$"COMPlus_{intrinsic}"] = "0"; + processStartInfo.Environment[$"COMPlus_{intrinsic.Value}"] = "0"; RemoteExecutor.Invoke( action, @@ -94,7 +94,7 @@ public static void RunWithHwIntrinsicsFeature( var processStartInfo = new ProcessStartInfo(); if (intrinsic.Key != HwIntrinsics.AllowAll) { - processStartInfo.Environment[$"COMPlus_{intrinsic}"] = "0"; + processStartInfo.Environment[$"COMPlus_{intrinsic.Value}"] = "0"; RemoteExecutor.Invoke( action, @@ -137,7 +137,7 @@ public static void RunWithHwIntrinsicsFeature( var processStartInfo = new ProcessStartInfo(); if (intrinsic.Key != HwIntrinsics.AllowAll) { - processStartInfo.Environment[$"COMPlus_{intrinsic}"] = "0"; + processStartInfo.Environment[$"COMPlus_{intrinsic.Value}"] = "0"; RemoteExecutor.Invoke( action, @@ -180,7 +180,7 @@ public static void RunWithHwIntrinsicsFeature( var processStartInfo = new ProcessStartInfo(); if (intrinsic.Key != HwIntrinsics.AllowAll) { - processStartInfo.Environment[$"COMPlus_{intrinsic}"] = "0"; + processStartInfo.Environment[$"COMPlus_{intrinsic.Value}"] = "0"; RemoteExecutor.Invoke( action, From 1a8f1c0261dae7e1edf995b58782b7cca2572ad6 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 15 Oct 2020 22:50:22 +0100 Subject: [PATCH 08/17] Test FeatureSIMD --- .../TestUtilities/Tests/FeatureTestRunnerTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs index 13a0806129..eb6f82885f 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs @@ -55,8 +55,8 @@ public void AllowsAllHwIntrinsicFeatures() public void CanLimitHwIntrinsicFeatures() { FeatureTestRunner.RunWithHwIntrinsicsFeature( - () => Assert.False(Sse.IsSupported, nameof(Sse.IsSupported)), - HwIntrinsics.DisableSSE); + () => Assert.False(Vector.IsHardwareAccelerated, nameof(Vector.IsHardwareAccelerated)), + HwIntrinsics.DisableSIMD); } #endif From 5600923751b05b88a2684342da1a3c5998e248c0 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 15 Oct 2020 22:55:46 +0100 Subject: [PATCH 09/17] Now test both disable values. --- .../TestUtilities/Tests/FeatureTestRunnerTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs index eb6f82885f..0f6cdc066a 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs @@ -56,7 +56,7 @@ public void CanLimitHwIntrinsicFeatures() { FeatureTestRunner.RunWithHwIntrinsicsFeature( () => Assert.False(Vector.IsHardwareAccelerated, nameof(Vector.IsHardwareAccelerated)), - HwIntrinsics.DisableSIMD); + HwIntrinsics.DisableSIMD | HwIntrinsics.DisableHWIntrinsic); } #endif From eed727930ec4adc1ca47a1cfad02ed59a6cabb3a Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 15 Oct 2020 23:08:27 +0100 Subject: [PATCH 10/17] Split base disabled checks --- .../Tests/FeatureTestRunnerTests.cs | 33 +++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs index 0f6cdc066a..8eb5c9fd62 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs @@ -50,13 +50,40 @@ public void AllowsAllHwIntrinsicFeatures() HwIntrinsics.AllowAll); } -#if SUPPORTS_RUNTIME_INTRINSICS [Fact] - public void CanLimitHwIntrinsicFeatures() + public void CanLimitHwIntrinsicSIMDFeatures() { FeatureTestRunner.RunWithHwIntrinsicsFeature( () => Assert.False(Vector.IsHardwareAccelerated, nameof(Vector.IsHardwareAccelerated)), - HwIntrinsics.DisableSIMD | HwIntrinsics.DisableHWIntrinsic); + HwIntrinsics.DisableSIMD); + } + +#if SUPPORTS_RUNTIME_INTRINSICS + [Fact] + public void CanLimitHwIntrinsicBaseFeatures() + { + static void AssertDisabled() + { + Assert.False(Sse.IsSupported); + Assert.False(Sse2.IsSupported); + Assert.False(Aes.IsSupported); + Assert.False(Pclmulqdq.IsSupported); + Assert.False(Sse3.IsSupported); + Assert.False(Ssse3.IsSupported); + Assert.False(Sse41.IsSupported); + Assert.False(Sse42.IsSupported); + Assert.False(Popcnt.IsSupported); + Assert.False(Avx.IsSupported); + Assert.False(Fma.IsSupported); + Assert.False(Avx2.IsSupported); + Assert.False(Bmi1.IsSupported); + Assert.False(Bmi2.IsSupported); + Assert.False(Lzcnt.IsSupported); + } + + FeatureTestRunner.RunWithHwIntrinsicsFeature( + AssertDisabled, + HwIntrinsics.DisableHWIntrinsic); } #endif From f0ecfd85de6b2f75d94e10c44898435417c75049 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 15 Oct 2020 23:16:00 +0100 Subject: [PATCH 11/17] Enable additional tests --- .../Tests/FeatureTestRunnerTests.cs | 341 ++++++++++-------- 1 file changed, 183 insertions(+), 158 deletions(-) diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs index 8eb5c9fd62..eea22592bc 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs @@ -46,7 +46,7 @@ public void ToFeatureCollectionReturnsExpectedResult(HwIntrinsics expectedItrins public void AllowsAllHwIntrinsicFeatures() { FeatureTestRunner.RunWithHwIntrinsicsFeature( - () => Assert.True(Vector.IsHardwareAccelerated, nameof(Vector.IsHardwareAccelerated)), + () => Assert.True(Vector.IsHardwareAccelerated), HwIntrinsics.AllowAll); } @@ -54,7 +54,7 @@ public void AllowsAllHwIntrinsicFeatures() public void CanLimitHwIntrinsicSIMDFeatures() { FeatureTestRunner.RunWithHwIntrinsicsFeature( - () => Assert.False(Vector.IsHardwareAccelerated, nameof(Vector.IsHardwareAccelerated)), + () => Assert.False(Vector.IsHardwareAccelerated), HwIntrinsics.DisableSIMD); } @@ -87,170 +87,195 @@ static void AssertDisabled() } #endif - // [Fact] - // public void CanLimitHwIntrinsicFeaturesWithIntrinsicsParam() - // { - // static void AssertHwIntrinsicsFeatureDisabled(string intrinsic) - // { - // Assert.NotNull(intrinsic); + [Fact] + public void CanLimitHwIntrinsicFeaturesWithIntrinsicsParam() + { + static void AssertHwIntrinsicsFeatureDisabled(string intrinsic) + { + Assert.NotNull(intrinsic); - // switch ((HwIntrinsics)Enum.Parse(typeof(HwIntrinsics), intrinsic)) - // { - // case HwIntrinsics.DisableSIMD: - // Assert.False(Vector.IsHardwareAccelerated); - // break; - //#if SUPPORTS_RUNTIME_INTRINSICS - // case HwIntrinsics.DisableHWIntrinsic: - // Assert.False(Vector.IsHardwareAccelerated); - // break; - // case HwIntrinsics.DisableSSE: - // Assert.False(Sse.IsSupported); - // break; - // case HwIntrinsics.DisableSSE2: - // Assert.False(Sse2.IsSupported); - // break; - // case HwIntrinsics.DisableAES: - // Assert.False(Aes.IsSupported); - // break; - // case HwIntrinsics.DisablePCLMULQDQ: - // Assert.False(Pclmulqdq.IsSupported); - // break; - // case HwIntrinsics.DisableSSE3: - // Assert.False(Sse3.IsSupported); - // break; - // case HwIntrinsics.DisableSSSE3: - // Assert.False(Ssse3.IsSupported); - // break; - // case HwIntrinsics.DisableSSE41: - // Assert.False(Sse41.IsSupported); - // break; - // case HwIntrinsics.DisableSSE42: - // Assert.False(Sse42.IsSupported); - // break; - // case HwIntrinsics.DisablePOPCNT: - // Assert.False(Popcnt.IsSupported); - // break; - // case HwIntrinsics.DisableAVX: - // Assert.False(Avx.IsSupported); - // break; - // case HwIntrinsics.DisableFMA: - // Assert.False(Fma.IsSupported); - // break; - // case HwIntrinsics.DisableAVX2: - // Assert.False(Avx2.IsSupported); - // break; - // case HwIntrinsics.DisableBMI1: - // Assert.False(Bmi1.IsSupported); - // break; - // case HwIntrinsics.DisableBMI2: - // Assert.False(Bmi2.IsSupported); - // break; - // case HwIntrinsics.DisableLZCNT: - // Assert.False(Lzcnt.IsSupported); - // break; - //#endif - // } - // } + switch ((HwIntrinsics)Enum.Parse(typeof(HwIntrinsics), intrinsic)) + { + case HwIntrinsics.DisableSIMD: + Assert.False(Vector.IsHardwareAccelerated); + break; +#if SUPPORTS_RUNTIME_INTRINSICS + case HwIntrinsics.DisableHWIntrinsic: + Assert.False(Sse.IsSupported); + Assert.False(Sse2.IsSupported); + Assert.False(Aes.IsSupported); + Assert.False(Pclmulqdq.IsSupported); + Assert.False(Sse3.IsSupported); + Assert.False(Ssse3.IsSupported); + Assert.False(Sse41.IsSupported); + Assert.False(Sse42.IsSupported); + Assert.False(Popcnt.IsSupported); + Assert.False(Avx.IsSupported); + Assert.False(Fma.IsSupported); + Assert.False(Avx2.IsSupported); + Assert.False(Bmi1.IsSupported); + Assert.False(Bmi2.IsSupported); + Assert.False(Lzcnt.IsSupported); + break; + case HwIntrinsics.DisableSSE: + Assert.False(Sse.IsSupported); + break; + case HwIntrinsics.DisableSSE2: + Assert.False(Sse2.IsSupported); + break; + case HwIntrinsics.DisableAES: + Assert.False(Aes.IsSupported); + break; + case HwIntrinsics.DisablePCLMULQDQ: + Assert.False(Pclmulqdq.IsSupported); + break; + case HwIntrinsics.DisableSSE3: + Assert.False(Sse3.IsSupported); + break; + case HwIntrinsics.DisableSSSE3: + Assert.False(Ssse3.IsSupported); + break; + case HwIntrinsics.DisableSSE41: + Assert.False(Sse41.IsSupported); + break; + case HwIntrinsics.DisableSSE42: + Assert.False(Sse42.IsSupported); + break; + case HwIntrinsics.DisablePOPCNT: + Assert.False(Popcnt.IsSupported); + break; + case HwIntrinsics.DisableAVX: + Assert.False(Avx.IsSupported); + break; + case HwIntrinsics.DisableFMA: + Assert.False(Fma.IsSupported); + break; + case HwIntrinsics.DisableAVX2: + Assert.False(Avx2.IsSupported); + break; + case HwIntrinsics.DisableBMI1: + Assert.False(Bmi1.IsSupported); + break; + case HwIntrinsics.DisableBMI2: + Assert.False(Bmi2.IsSupported); + break; + case HwIntrinsics.DisableLZCNT: + Assert.False(Lzcnt.IsSupported); + break; +#endif + } + } - // foreach (HwIntrinsics intrinsic in (HwIntrinsics[])Enum.GetValues(typeof(HwIntrinsics))) - // { - // FeatureTestRunner.RunWithHwIntrinsicsFeature(AssertHwIntrinsicsFeatureDisabled, intrinsic); - // } - // } + foreach (HwIntrinsics intrinsic in (HwIntrinsics[])Enum.GetValues(typeof(HwIntrinsics))) + { + FeatureTestRunner.RunWithHwIntrinsicsFeature(AssertHwIntrinsicsFeatureDisabled, intrinsic); + } + } - // [Fact] - // public void CanLimitHwIntrinsicFeaturesWithSerializableParam() - // { - // static void AssertHwIntrinsicsFeatureDisabled(string serializable) - // { - // Assert.NotNull(serializable); - // Assert.NotNull(FeatureTestRunner.Deserialize(serializable)); + [Fact] + public void CanLimitHwIntrinsicFeaturesWithSerializableParam() + { + static void AssertHwIntrinsicsFeatureDisabled(string serializable) + { + Assert.NotNull(serializable); + Assert.NotNull(FeatureTestRunner.Deserialize(serializable)); - //#if SUPPORTS_RUNTIME_INTRINSICS - // Assert.False(Sse.IsSupported); - //#endif - // } +#if SUPPORTS_RUNTIME_INTRINSICS + Assert.False(Sse.IsSupported); +#endif + } - // foreach (HwIntrinsics intrinsic in (HwIntrinsics[])Enum.GetValues(typeof(HwIntrinsics))) - // { - // FeatureTestRunner.RunWithHwIntrinsicsFeature( - // AssertHwIntrinsicsFeatureDisabled, - // HwIntrinsics.DisableSSE, - // new FakeSerializable()); - // } - // } + FeatureTestRunner.RunWithHwIntrinsicsFeature( + AssertHwIntrinsicsFeatureDisabled, + HwIntrinsics.DisableSSE, + new FakeSerializable()); + } - // [Fact] - // public void CanLimitHwIntrinsicFeaturesWithSerializableAndIntrinsicsParams() - // { - // static void AssertHwIntrinsicsFeatureDisabled(string serializable, string intrinsic) - // { - // Assert.NotNull(serializable); - // Assert.NotNull(FeatureTestRunner.Deserialize(serializable)); + [Fact] + public void CanLimitHwIntrinsicFeaturesWithSerializableAndIntrinsicsParams() + { + static void AssertHwIntrinsicsFeatureDisabled(string serializable, string intrinsic) + { + Assert.NotNull(serializable); + Assert.NotNull(FeatureTestRunner.Deserialize(serializable)); - // switch ((HwIntrinsics)Enum.Parse(typeof(HwIntrinsics), intrinsic)) - // { - // case HwIntrinsics.DisableSIMD: - // Assert.False(Vector.IsHardwareAccelerated, nameof(Vector.IsHardwareAccelerated)); - // break; - //#if SUPPORTS_RUNTIME_INTRINSICS - // case HwIntrinsics.DisableHWIntrinsic: - // Assert.False(Vector.IsHardwareAccelerated, nameof(Vector.IsHardwareAccelerated)); - // break; - // case HwIntrinsics.DisableSSE: - // Assert.False(Sse.IsSupported); - // break; - // case HwIntrinsics.DisableSSE2: - // Assert.False(Sse2.IsSupported); - // break; - // case HwIntrinsics.DisableAES: - // Assert.False(Aes.IsSupported); - // break; - // case HwIntrinsics.DisablePCLMULQDQ: - // Assert.False(Pclmulqdq.IsSupported); - // break; - // case HwIntrinsics.DisableSSE3: - // Assert.False(Sse3.IsSupported); - // break; - // case HwIntrinsics.DisableSSSE3: - // Assert.False(Ssse3.IsSupported); - // break; - // case HwIntrinsics.DisableSSE41: - // Assert.False(Sse41.IsSupported); - // break; - // case HwIntrinsics.DisableSSE42: - // Assert.False(Sse42.IsSupported); - // break; - // case HwIntrinsics.DisablePOPCNT: - // Assert.False(Popcnt.IsSupported); - // break; - // case HwIntrinsics.DisableAVX: - // Assert.False(Avx.IsSupported); - // break; - // case HwIntrinsics.DisableFMA: - // Assert.False(Fma.IsSupported); - // break; - // case HwIntrinsics.DisableAVX2: - // Assert.False(Avx2.IsSupported); - // break; - // case HwIntrinsics.DisableBMI1: - // Assert.False(Bmi1.IsSupported); - // break; - // case HwIntrinsics.DisableBMI2: - // Assert.False(Bmi2.IsSupported); - // break; - // case HwIntrinsics.DisableLZCNT: - // Assert.False(Lzcnt.IsSupported); - // break; - //#endif - // } - // } + switch ((HwIntrinsics)Enum.Parse(typeof(HwIntrinsics), intrinsic)) + { + case HwIntrinsics.DisableSIMD: + Assert.False(Vector.IsHardwareAccelerated, nameof(Vector.IsHardwareAccelerated)); + break; +#if SUPPORTS_RUNTIME_INTRINSICS + case HwIntrinsics.DisableHWIntrinsic: + Assert.False(Sse.IsSupported); + Assert.False(Sse2.IsSupported); + Assert.False(Aes.IsSupported); + Assert.False(Pclmulqdq.IsSupported); + Assert.False(Sse3.IsSupported); + Assert.False(Ssse3.IsSupported); + Assert.False(Sse41.IsSupported); + Assert.False(Sse42.IsSupported); + Assert.False(Popcnt.IsSupported); + Assert.False(Avx.IsSupported); + Assert.False(Fma.IsSupported); + Assert.False(Avx2.IsSupported); + Assert.False(Bmi1.IsSupported); + Assert.False(Bmi2.IsSupported); + Assert.False(Lzcnt.IsSupported); + break; + case HwIntrinsics.DisableSSE: + Assert.False(Sse.IsSupported); + break; + case HwIntrinsics.DisableSSE2: + Assert.False(Sse2.IsSupported); + break; + case HwIntrinsics.DisableAES: + Assert.False(Aes.IsSupported); + break; + case HwIntrinsics.DisablePCLMULQDQ: + Assert.False(Pclmulqdq.IsSupported); + break; + case HwIntrinsics.DisableSSE3: + Assert.False(Sse3.IsSupported); + break; + case HwIntrinsics.DisableSSSE3: + Assert.False(Ssse3.IsSupported); + break; + case HwIntrinsics.DisableSSE41: + Assert.False(Sse41.IsSupported); + break; + case HwIntrinsics.DisableSSE42: + Assert.False(Sse42.IsSupported); + break; + case HwIntrinsics.DisablePOPCNT: + Assert.False(Popcnt.IsSupported); + break; + case HwIntrinsics.DisableAVX: + Assert.False(Avx.IsSupported); + break; + case HwIntrinsics.DisableFMA: + Assert.False(Fma.IsSupported); + break; + case HwIntrinsics.DisableAVX2: + Assert.False(Avx2.IsSupported); + break; + case HwIntrinsics.DisableBMI1: + Assert.False(Bmi1.IsSupported); + break; + case HwIntrinsics.DisableBMI2: + Assert.False(Bmi2.IsSupported); + break; + case HwIntrinsics.DisableLZCNT: + Assert.False(Lzcnt.IsSupported); + break; +#endif + } + } - // foreach (HwIntrinsics intrinsic in (HwIntrinsics[])Enum.GetValues(typeof(HwIntrinsics))) - // { - // FeatureTestRunner.RunWithHwIntrinsicsFeature(AssertHwIntrinsicsFeatureDisabled, intrinsic, new FakeSerializable()); - // } - // } + foreach (HwIntrinsics intrinsic in (HwIntrinsics[])Enum.GetValues(typeof(HwIntrinsics))) + { + FeatureTestRunner.RunWithHwIntrinsicsFeature(AssertHwIntrinsicsFeatureDisabled, intrinsic, new FakeSerializable()); + } + } public class FakeSerializable : IXunitSerializable { From 60acc49f50818fc4da6a6654bb450dbf76cfbf16 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 15 Oct 2020 23:31:56 +0100 Subject: [PATCH 12/17] Update PngEncoderTests.cs --- .../Formats/Png/PngEncoderTests.cs | 28 ++++--------------- 1 file changed, 5 insertions(+), 23 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index b35e55887c..9ba956d722 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -2,13 +2,8 @@ // Licensed under the Apache License, Version 2.0. // ReSharper disable InconsistentNaming -using System.Diagnostics; using System.IO; using System.Linq; -#if SUPPORTS_RUNTIME_INTRINSICS -using System.Runtime.Intrinsics.X86; -#endif -using Microsoft.DotNet.RemoteExecutor; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Metadata; @@ -16,7 +11,6 @@ using SixLabors.ImageSharp.Processing.Processors.Quantization; using SixLabors.ImageSharp.Tests.TestUtilities; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; - using Xunit; namespace SixLabors.ImageSharp.Tests.Formats.Png @@ -538,13 +532,10 @@ public void Encode_WorksWithDiscontiguousBuffers(TestImageProvider provider) { - static void RunTest(string providerDump) + static void RunTest(string serialized) { TestImageProvider provider = - BasicSerializer.Deserialize>(providerDump); -#if SUPPORTS_RUNTIME_INTRINSICS - Assert.False(Ssse3.IsSupported); -#endif + FeatureTestRunner.Deserialize>(serialized); foreach (PngInterlaceMode interlaceMode in InterlaceMode) { @@ -559,19 +550,10 @@ static void RunTest(string providerDump) } } - string providerDump = BasicSerializer.Serialize(provider); - - var processStartInfo = new ProcessStartInfo(); - processStartInfo.Environment[TestEnvironment.Features.EnableSSE3] = TestEnvironment.Features.Off; - - RemoteExecutor.Invoke( + FeatureTestRunner.RunWithHwIntrinsicsFeature( RunTest, - providerDump, - new RemoteInvokeOptions - { - StartInfo = processStartInfo - }) - .Dispose(); + HwIntrinsics.DisableSSSE3, + provider); } private static void TestPngEncoderCore( From f2f16d8c67a31e040924ad6587653e404371bea4 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 16 Oct 2020 00:06:31 +0100 Subject: [PATCH 13/17] Use envonment aware benchmarking for intrinsics. --- .../BlockOperations/Block8x8F_Transpose.cs | 16 +--- .../Config.HwIntrinsics.cs | 81 +++++++++++++++++++ tests/ImageSharp.Benchmarks/Config.cs | 2 +- .../TestUtilities/TestEnvironment.Features.cs | 54 ------------- 4 files changed, 86 insertions(+), 67 deletions(-) create mode 100644 tests/ImageSharp.Benchmarks/Config.HwIntrinsics.cs delete mode 100644 tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Features.cs diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Transpose.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Transpose.cs index ae1b23df92..814c910383 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Transpose.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Transpose.cs @@ -6,26 +6,18 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations { + [Config(typeof(Config.HwIntrinsics_SSE_AVX))] public class Block8x8F_Transpose { private static readonly Block8x8F Source = Create8x8FloatData(); - [Benchmark(Baseline=true)] - public void TransposeIntoVector4() + [Benchmark(Baseline = true)] + public void TransposeInto() { var dest = default(Block8x8F); - Source.TransposeIntoFallback(ref dest); + Source.TransposeInto(ref dest); } -#if SUPPORTS_RUNTIME_INTRINSICS - [Benchmark] - public void TransposeIntoAvx() - { - var dest = default(Block8x8F); - Source.TransposeIntoAvx(ref dest); - } -#endif - private static Block8x8F Create8x8FloatData() { var result = new float[64]; diff --git a/tests/ImageSharp.Benchmarks/Config.HwIntrinsics.cs b/tests/ImageSharp.Benchmarks/Config.HwIntrinsics.cs new file mode 100644 index 0000000000..e860c5491f --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Config.HwIntrinsics.cs @@ -0,0 +1,81 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +#if SUPPORTS_RUNTIME_INTRINSICS +using System.Runtime.Intrinsics.X86; +#endif +using BenchmarkDotNet.Environments; +using BenchmarkDotNet.Jobs; + +namespace SixLabors.ImageSharp.Benchmarks +{ + public partial class Config + { + private const string On = "1"; + private const string Off = "0"; + + // See https://github.com/SixLabors/ImageSharp/pull/1229#discussion_r440477861 + // * EnableHWIntrinsic + // * EnableSSE + // * EnableSSE2 + // * EnableAES + // * EnablePCLMULQDQ + // * EnableSSE3 + // * EnableSSSE3 + // * EnableSSE41 + // * EnableSSE42 + // * EnablePOPCNT + // * EnableAVX + // * EnableFMA + // * EnableAVX2 + // * EnableBMI1 + // * EnableBMI2 + // * EnableLZCNT + // + // `FeatureSIMD` ends up impacting all SIMD support(including `System.Numerics`) but not things + // like `LZCNT`, `BMI1`, or `BMI2` + // `EnableSSE3_4` is a legacy switch that exists for compat and is basically the same as `EnableSSE3` + private const string EnableAES = "COMPlus_EnableAES"; + private const string EnableAVX = "COMPlus_EnableAVX"; + private const string EnableAVX2 = "COMPlus_EnableAVX2"; + private const string EnableBMI1 = "COMPlus_EnableBMI1"; + private const string EnableBMI2 = "COMPlus_EnableBMI2"; + private const string EnableFMA = "COMPlus_EnableFMA"; + private const string EnableHWIntrinsic = "COMPlus_EnableHWIntrinsic"; + private const string EnableLZCNT = "COMPlus_EnableLZCNT"; + private const string EnablePCLMULQDQ = "COMPlus_EnablePCLMULQDQ"; + private const string EnablePOPCNT = "COMPlus_EnablePOPCNT"; + private const string EnableSSE = "COMPlus_EnableSSE"; + private const string EnableSSE2 = "COMPlus_EnableSSE2"; + private const string EnableSSE3 = "COMPlus_EnableSSE3"; + private const string EnableSSE3_4 = "COMPlus_EnableSSE3_4"; + private const string EnableSSE41 = "COMPlus_EnableSSE41"; + private const string EnableSSE42 = "COMPlus_EnableSSE42"; + private const string EnableSSSE3 = "COMPlus_EnableSSSE3"; + private const string FeatureSIMD = "COMPlus_FeatureSIMD"; + + public class HwIntrinsics_SSE_AVX : Config + { + public HwIntrinsics_SSE_AVX() + { +#if SUPPORTS_RUNTIME_INTRINSICS + if (Avx.IsSupported) + { + this.AddJob(Job.Default.WithRuntime(CoreRuntime.Core31) + .WithId("AVX").AsBaseline()); + } + + if (Sse.IsSupported) + { + this.AddJob(Job.Default.WithRuntime(CoreRuntime.Core31) + .WithEnvironmentVariables(new EnvironmentVariable(EnableAVX, Off)) + .WithId("SSE")); + } +#endif + this.AddJob(Job.Default.WithRuntime(CoreRuntime.Core31) + .WithEnvironmentVariables(new EnvironmentVariable(EnableHWIntrinsic, Off)) + .WithId("No HwIntrinsics")); + } + } + } +} diff --git a/tests/ImageSharp.Benchmarks/Config.cs b/tests/ImageSharp.Benchmarks/Config.cs index f9240779b9..53271f522d 100644 --- a/tests/ImageSharp.Benchmarks/Config.cs +++ b/tests/ImageSharp.Benchmarks/Config.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Benchmarks { - public class Config : ManualConfig + public partial class Config : ManualConfig { public Config() { diff --git a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Features.cs b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Features.cs deleted file mode 100644 index 3568c1e5dc..0000000000 --- a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Features.cs +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Apache License, Version 2.0. - -namespace SixLabors.ImageSharp.Tests -{ - public static partial class TestEnvironment - { - internal static class Features - { - public const string On = "1"; - public const string Off = "0"; - - // See https://github.com/SixLabors/ImageSharp/pull/1229#discussion_r440477861 - // * EnableHWIntrinsic - // * EnableSSE - // * EnableSSE2 - // * EnableAES - // * EnablePCLMULQDQ - // * EnableSSE3 - // * EnableSSSE3 - // * EnableSSE41 - // * EnableSSE42 - // * EnablePOPCNT - // * EnableAVX - // * EnableFMA - // * EnableAVX2 - // * EnableBMI1 - // * EnableBMI2 - // * EnableLZCNT - // - // `FeatureSIMD` ends up impacting all SIMD support(including `System.Numerics`) but not things - // like `LZCNT`, `BMI1`, or `BMI2` - // `EnableSSE3_4` is a legacy switch that exists for compat and is basically the same as `EnableSSE3` - public const string EnableAES = "COMPlus_EnableAES"; - public const string EnableAVX = "COMPlus_EnableAVX"; - public const string EnableAVX2 = "COMPlus_EnableAVX2"; - public const string EnableBMI1 = "COMPlus_EnableBMI1"; - public const string EnableBMI2 = "COMPlus_EnableBMI2"; - public const string EnableFMA = "COMPlus_EnableFMA"; - public const string EnableHWIntrinsic = "COMPlus_EnableHWIntrinsic"; - public const string EnableLZCNT = "COMPlus_EnableLZCNT"; - public const string EnablePCLMULQDQ = "COMPlus_EnablePCLMULQDQ"; - public const string EnablePOPCNT = "COMPlus_EnablePOPCNT"; - public const string EnableSSE = "COMPlus_EnableSSE"; - public const string EnableSSE2 = "COMPlus_EnableSSE2"; - public const string EnableSSE3 = "COMPlus_EnableSSE3"; - public const string EnableSSE3_4 = "COMPlus_EnableSSE3_4"; - public const string EnableSSE41 = "COMPlus_EnableSSE41"; - public const string EnableSSE42 = "COMPlus_EnableSSE42"; - public const string EnableSSSE3 = "COMPlus_EnableSSSE3"; - public const string FeatureSIMD = "COMPlus_FeatureSIMD"; - } - } -} From d406ee8e5dacec8d1c2bca6aeabb1689e6cb2675 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 16 Oct 2020 00:14:47 +0100 Subject: [PATCH 14/17] Use a single method for Block8x8F.TransposeInto. --- .../Jpeg/Components/Block8x8F.Generated.cs | 80 ------- .../Jpeg/Components/Block8x8F.Generated.tt | 32 --- .../Formats/Jpeg/Components/Block8x8F.cs | 211 +++++++++++------- 3 files changed, 135 insertions(+), 188 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs index 10cbee5e6f..6a336ad2b4 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs @@ -10,86 +10,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components { internal partial struct Block8x8F { - /// - /// Fallback method to transpose a block into the destination block on non AVX supported CPUs. - /// - /// The destination block - [MethodImpl(InliningOptions.ShortMethod)] - public void TransposeIntoFallback(ref Block8x8F d) - { - d.V0L.X = V0L.X; - d.V1L.X = V0L.Y; - d.V2L.X = V0L.Z; - d.V3L.X = V0L.W; - d.V4L.X = V0R.X; - d.V5L.X = V0R.Y; - d.V6L.X = V0R.Z; - d.V7L.X = V0R.W; - - d.V0L.Y = V1L.X; - d.V1L.Y = V1L.Y; - d.V2L.Y = V1L.Z; - d.V3L.Y = V1L.W; - d.V4L.Y = V1R.X; - d.V5L.Y = V1R.Y; - d.V6L.Y = V1R.Z; - d.V7L.Y = V1R.W; - - d.V0L.Z = V2L.X; - d.V1L.Z = V2L.Y; - d.V2L.Z = V2L.Z; - d.V3L.Z = V2L.W; - d.V4L.Z = V2R.X; - d.V5L.Z = V2R.Y; - d.V6L.Z = V2R.Z; - d.V7L.Z = V2R.W; - - d.V0L.W = V3L.X; - d.V1L.W = V3L.Y; - d.V2L.W = V3L.Z; - d.V3L.W = V3L.W; - d.V4L.W = V3R.X; - d.V5L.W = V3R.Y; - d.V6L.W = V3R.Z; - d.V7L.W = V3R.W; - - d.V0R.X = V4L.X; - d.V1R.X = V4L.Y; - d.V2R.X = V4L.Z; - d.V3R.X = V4L.W; - d.V4R.X = V4R.X; - d.V5R.X = V4R.Y; - d.V6R.X = V4R.Z; - d.V7R.X = V4R.W; - - d.V0R.Y = V5L.X; - d.V1R.Y = V5L.Y; - d.V2R.Y = V5L.Z; - d.V3R.Y = V5L.W; - d.V4R.Y = V5R.X; - d.V5R.Y = V5R.Y; - d.V6R.Y = V5R.Z; - d.V7R.Y = V5R.W; - - d.V0R.Z = V6L.X; - d.V1R.Z = V6L.Y; - d.V2R.Z = V6L.Z; - d.V3R.Z = V6L.W; - d.V4R.Z = V6R.X; - d.V5R.Z = V6R.Y; - d.V6R.Z = V6R.Z; - d.V7R.Z = V6R.W; - - d.V0R.W = V7L.X; - d.V1R.W = V7L.Y; - d.V2R.W = V7L.Z; - d.V3R.W = V7L.W; - d.V4R.W = V7R.X; - d.V5R.W = V7R.Y; - d.V6R.W = V7R.Z; - d.V7R.W = V7R.W; - } - /// /// Level shift by +maximum/2, clip to [0, maximum] /// diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt index f47d9106ee..26cd5c2ac4 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt @@ -23,38 +23,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components { internal partial struct Block8x8F { - /// - /// Fallback method to transpose a block into the destination block on non AVX supported CPUs. - /// - /// The destination block - [MethodImpl(InliningOptions.ShortMethod)] - public void TransposeIntoFallback(ref Block8x8F d) - { - <# - PushIndent(" "); - - for (int i = 0; i < 8; i++) - { - char destCoord = coordz[i % 4]; - char destSide = (i / 4) % 2 == 0 ? 'L' : 'R'; - - for (int j = 0; j < 8; j++) - { - if(i > 0 && j == 0){ - WriteLine(""); - } - - char srcCoord = coordz[j % 4]; - char srcSide = (j / 4) % 2 == 0 ? 'L' : 'R'; - - var expression = $"d.V{j}{destSide}.{destCoord} = V{i}{srcSide}.{srcCoord};\r\n"; - Write(expression); - } - } - PopIndent(); - #> - } - /// /// Level shift by +maximum/2, clip to [0, maximum] /// diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs index 547e116230..ccdba48857 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs @@ -611,87 +611,146 @@ public void TransposeInto(ref Block8x8F d) #if SUPPORTS_RUNTIME_INTRINSICS if (Avx.IsSupported) { - this.TransposeIntoAvx(ref d); + // https://stackoverflow.com/questions/25622745/transpose-an-8x8-float-using-avx-avx2/25627536#25627536 + Vector256 r0 = Avx.InsertVector128( + Unsafe.As>(ref this.V0L).ToVector256(), + Unsafe.As>(ref this.V4L), + 1); + + Vector256 r1 = Avx.InsertVector128( + Unsafe.As>(ref this.V1L).ToVector256(), + Unsafe.As>(ref this.V5L), + 1); + + Vector256 r2 = Avx.InsertVector128( + Unsafe.As>(ref this.V2L).ToVector256(), + Unsafe.As>(ref this.V6L), + 1); + + Vector256 r3 = Avx.InsertVector128( + Unsafe.As>(ref this.V3L).ToVector256(), + Unsafe.As>(ref this.V7L), + 1); + + Vector256 r4 = Avx.InsertVector128( + Unsafe.As>(ref this.V0R).ToVector256(), + Unsafe.As>(ref this.V4R), + 1); + + Vector256 r5 = Avx.InsertVector128( + Unsafe.As>(ref this.V1R).ToVector256(), + Unsafe.As>(ref this.V5R), + 1); + + Vector256 r6 = Avx.InsertVector128( + Unsafe.As>(ref this.V2R).ToVector256(), + Unsafe.As>(ref this.V6R), + 1); + + Vector256 r7 = Avx.InsertVector128( + Unsafe.As>(ref this.V3R).ToVector256(), + Unsafe.As>(ref this.V7R), + 1); + + Vector256 t0 = Avx.UnpackLow(r0, r1); + Vector256 t2 = Avx.UnpackLow(r2, r3); + Vector256 v = Avx.Shuffle(t0, t2, 0x4E); + Unsafe.As>(ref d.V0L) = Avx.Blend(t0, v, 0xCC); + Unsafe.As>(ref d.V1L) = Avx.Blend(t2, v, 0x33); + + Vector256 t4 = Avx.UnpackLow(r4, r5); + Vector256 t6 = Avx.UnpackLow(r6, r7); + v = Avx.Shuffle(t4, t6, 0x4E); + Unsafe.As>(ref d.V4L) = Avx.Blend(t4, v, 0xCC); + Unsafe.As>(ref d.V5L) = Avx.Blend(t6, v, 0x33); + + Vector256 t1 = Avx.UnpackHigh(r0, r1); + Vector256 t3 = Avx.UnpackHigh(r2, r3); + v = Avx.Shuffle(t1, t3, 0x4E); + Unsafe.As>(ref d.V2L) = Avx.Blend(t1, v, 0xCC); + Unsafe.As>(ref d.V3L) = Avx.Blend(t3, v, 0x33); + + Vector256 t5 = Avx.UnpackHigh(r4, r5); + Vector256 t7 = Avx.UnpackHigh(r6, r7); + v = Avx.Shuffle(t5, t7, 0x4E); + Unsafe.As>(ref d.V6L) = Avx.Blend(t5, v, 0xCC); + Unsafe.As>(ref d.V7L) = Avx.Blend(t7, v, 0x33); } else #endif { - this.TransposeIntoFallback(ref d); + d.V0L.X = this.V0L.X; + d.V1L.X = this.V0L.Y; + d.V2L.X = this.V0L.Z; + d.V3L.X = this.V0L.W; + d.V4L.X = this.V0R.X; + d.V5L.X = this.V0R.Y; + d.V6L.X = this.V0R.Z; + d.V7L.X = this.V0R.W; + + d.V0L.Y = this.V1L.X; + d.V1L.Y = this.V1L.Y; + d.V2L.Y = this.V1L.Z; + d.V3L.Y = this.V1L.W; + d.V4L.Y = this.V1R.X; + d.V5L.Y = this.V1R.Y; + d.V6L.Y = this.V1R.Z; + d.V7L.Y = this.V1R.W; + + d.V0L.Z = this.V2L.X; + d.V1L.Z = this.V2L.Y; + d.V2L.Z = this.V2L.Z; + d.V3L.Z = this.V2L.W; + d.V4L.Z = this.V2R.X; + d.V5L.Z = this.V2R.Y; + d.V6L.Z = this.V2R.Z; + d.V7L.Z = this.V2R.W; + + d.V0L.W = this.V3L.X; + d.V1L.W = this.V3L.Y; + d.V2L.W = this.V3L.Z; + d.V3L.W = this.V3L.W; + d.V4L.W = this.V3R.X; + d.V5L.W = this.V3R.Y; + d.V6L.W = this.V3R.Z; + d.V7L.W = this.V3R.W; + + d.V0R.X = this.V4L.X; + d.V1R.X = this.V4L.Y; + d.V2R.X = this.V4L.Z; + d.V3R.X = this.V4L.W; + d.V4R.X = this.V4R.X; + d.V5R.X = this.V4R.Y; + d.V6R.X = this.V4R.Z; + d.V7R.X = this.V4R.W; + + d.V0R.Y = this.V5L.X; + d.V1R.Y = this.V5L.Y; + d.V2R.Y = this.V5L.Z; + d.V3R.Y = this.V5L.W; + d.V4R.Y = this.V5R.X; + d.V5R.Y = this.V5R.Y; + d.V6R.Y = this.V5R.Z; + d.V7R.Y = this.V5R.W; + + d.V0R.Z = this.V6L.X; + d.V1R.Z = this.V6L.Y; + d.V2R.Z = this.V6L.Z; + d.V3R.Z = this.V6L.W; + d.V4R.Z = this.V6R.X; + d.V5R.Z = this.V6R.Y; + d.V6R.Z = this.V6R.Z; + d.V7R.Z = this.V6R.W; + + d.V0R.W = this.V7L.X; + d.V1R.W = this.V7L.Y; + d.V2R.W = this.V7L.Z; + d.V3R.W = this.V7L.W; + d.V4R.W = this.V7R.X; + d.V5R.W = this.V7R.Y; + d.V6R.W = this.V7R.Z; + d.V7R.W = this.V7R.W; } } - -#if SUPPORTS_RUNTIME_INTRINSICS - /// - /// AVX-only variant for executing . - /// - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void TransposeIntoAvx(ref Block8x8F d) - { - Vector256 r0 = Avx.InsertVector128( - Unsafe.As>(ref this.V0L).ToVector256(), - Unsafe.As>(ref this.V4L), - 1); - - Vector256 r1 = Avx.InsertVector128( - Unsafe.As>(ref this.V1L).ToVector256(), - Unsafe.As>(ref this.V5L), - 1); - - Vector256 r2 = Avx.InsertVector128( - Unsafe.As>(ref this.V2L).ToVector256(), - Unsafe.As>(ref this.V6L), - 1); - - Vector256 r3 = Avx.InsertVector128( - Unsafe.As>(ref this.V3L).ToVector256(), - Unsafe.As>(ref this.V7L), - 1); - - Vector256 r4 = Avx.InsertVector128( - Unsafe.As>(ref this.V0R).ToVector256(), - Unsafe.As>(ref this.V4R), - 1); - - Vector256 r5 = Avx.InsertVector128( - Unsafe.As>(ref this.V1R).ToVector256(), - Unsafe.As>(ref this.V5R), - 1); - - Vector256 r6 = Avx.InsertVector128( - Unsafe.As>(ref this.V2R).ToVector256(), - Unsafe.As>(ref this.V6R), - 1); - - Vector256 r7 = Avx.InsertVector128( - Unsafe.As>(ref this.V3R).ToVector256(), - Unsafe.As>(ref this.V7R), - 1); - - Vector256 t0 = Avx.UnpackLow(r0, r1); - Vector256 t2 = Avx.UnpackLow(r2, r3); - Vector256 v = Avx.Shuffle(t0, t2, 0x4E); - Unsafe.As>(ref d.V0L) = Avx.Blend(t0, v, 0xCC); - Unsafe.As>(ref d.V1L) = Avx.Blend(t2, v, 0x33); - - Vector256 t4 = Avx.UnpackLow(r4, r5); - Vector256 t6 = Avx.UnpackLow(r6, r7); - v = Avx.Shuffle(t4, t6, 0x4E); - Unsafe.As>(ref d.V4L) = Avx.Blend(t4, v, 0xCC); - Unsafe.As>(ref d.V5L) = Avx.Blend(t6, v, 0x33); - - Vector256 t1 = Avx.UnpackHigh(r0, r1); - Vector256 t3 = Avx.UnpackHigh(r2, r3); - v = Avx.Shuffle(t1, t3, 0x4E); - Unsafe.As>(ref d.V2L) = Avx.Blend(t1, v, 0xCC); - Unsafe.As>(ref d.V3L) = Avx.Blend(t3, v, 0x33); - - Vector256 t5 = Avx.UnpackHigh(r4, r5); - Vector256 t7 = Avx.UnpackHigh(r6, r7); - v = Avx.Shuffle(t5, t7, 0x4E); - Unsafe.As>(ref d.V6L) = Avx.Blend(t5, v, 0xCC); - Unsafe.As>(ref d.V7L) = Avx.Blend(t7, v, 0x33); - } -#endif } } From ce61acc37f578dbd11fb8b793de339b7a9266171 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 16 Oct 2020 00:20:41 +0100 Subject: [PATCH 15/17] Enable all test platforms --- .github/workflows/build-and-test.yml | 32 ++++++++++++++-------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index ecb5ceb0ef..c8f3997946 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -17,23 +17,23 @@ jobs: - os: ubuntu-latest framework: netcoreapp3.1 runtime: -x64 + codecov: true + - os: windows-latest + framework: netcoreapp3.1 + runtime: -x64 + codecov: false + - os: windows-latest + framework: netcoreapp2.1 + runtime: -x64 + codecov: false + - os: windows-latest + framework: net472 + runtime: -x64 + codecov: false + - os: windows-latest + framework: net472 + runtime: -x86 codecov: false - # - os: windows-latest - # framework: netcoreapp3.1 - # runtime: -x64 - # codecov: false - # - os: windows-latest - # framework: netcoreapp2.1 - # runtime: -x64 - # codecov: false - # - os: windows-latest - # framework: net472 - # runtime: -x64 - # codecov: false - # - os: windows-latest - # framework: net472 - # runtime: -x86 - # codecov: false runs-on: ${{matrix.options.os}} if: "!contains(github.event.head_commit.message, '[skip ci]')" From dfd6aaab2160cf2556ea505f286bf7f99bff5f6b Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 16 Oct 2020 00:36:39 +0100 Subject: [PATCH 16/17] Remove method baseline property --- .../Codecs/Jpeg/BlockOperations/Block8x8F_Transpose.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Transpose.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Transpose.cs index 814c910383..1d103cd1a0 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Transpose.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Transpose.cs @@ -11,7 +11,7 @@ public class Block8x8F_Transpose { private static readonly Block8x8F Source = Create8x8FloatData(); - [Benchmark(Baseline = true)] + [Benchmark] public void TransposeInto() { var dest = default(Block8x8F); From b3ce02c419c14cf6e90d2889f6a9592926a08f11 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 16 Oct 2020 01:05:40 +0100 Subject: [PATCH 17/17] Fix incorrect test on NET 32bit --- .../TestUtilities/Tests/FeatureTestRunnerTests.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs index eea22592bc..646000120f 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs @@ -45,6 +45,11 @@ public void ToFeatureCollectionReturnsExpectedResult(HwIntrinsics expectedItrins [Fact] public void AllowsAllHwIntrinsicFeatures() { + if (!Vector.IsHardwareAccelerated) + { + return; + } + FeatureTestRunner.RunWithHwIntrinsicsFeature( () => Assert.True(Vector.IsHardwareAccelerated), HwIntrinsics.AllowAll);