mirror of https://github.com/SixLabors/ImageSharp
committed by
GitHub
11 changed files with 804 additions and 308 deletions
@ -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")); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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 |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Allows the testing against specific feature sets.
|
||||
|
/// </summary>
|
||||
|
public static class FeatureTestRunner |
||||
|
{ |
||||
|
private static readonly char[] SplitChars = new[] { ',', ' ' }; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Allows the deserialization of parameters passed to the feature test.
|
||||
|
/// <remark>
|
||||
|
/// <para>
|
||||
|
/// This is required because <see cref="RemoteExecutor"/> does not allow
|
||||
|
/// marshalling of fields so we cannot pass a wrapped <see cref="Action{T}"/>
|
||||
|
/// allowing automatic deserialization.
|
||||
|
/// </para>
|
||||
|
/// </remark>
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="T">The type to deserialize to.</typeparam>
|
||||
|
/// <param name="value">The string value to deserialize.</param>
|
||||
|
/// <returns>The <see cref="T"/> value.</returns>
|
||||
|
public static T Deserialize<T>(string value) |
||||
|
where T : IXunitSerializable |
||||
|
=> BasicSerializer.Deserialize<T>(value); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Runs the given test <paramref name="action"/> within an environment
|
||||
|
/// where the given <paramref name="intrinsics"/> features.
|
||||
|
/// </summary>
|
||||
|
/// <param name="action">The test action to run.</param>
|
||||
|
/// <param name="intrinsics">The intrinsics features.</param>
|
||||
|
public static void RunWithHwIntrinsicsFeature( |
||||
|
Action action, |
||||
|
HwIntrinsics intrinsics) |
||||
|
{ |
||||
|
if (!RemoteExecutor.IsSupported) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
foreach (KeyValuePair<HwIntrinsics, string> intrinsic in intrinsics.ToFeatureKeyValueCollection()) |
||||
|
{ |
||||
|
var processStartInfo = new ProcessStartInfo(); |
||||
|
if (intrinsic.Key != HwIntrinsics.AllowAll) |
||||
|
{ |
||||
|
processStartInfo.Environment[$"COMPlus_{intrinsic.Value}"] = "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(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Runs the given test <paramref name="action"/> within an environment
|
||||
|
/// where the given <paramref name="intrinsics"/> features.
|
||||
|
/// </summary>
|
||||
|
/// <param name="action">
|
||||
|
/// The test action to run.
|
||||
|
/// The parameter passed will be a string representing the currently testing <see cref="HwIntrinsics"/>.</param>
|
||||
|
/// <param name="intrinsics">The intrinsics features.</param>
|
||||
|
public static void RunWithHwIntrinsicsFeature( |
||||
|
Action<string> action, |
||||
|
HwIntrinsics intrinsics) |
||||
|
{ |
||||
|
if (!RemoteExecutor.IsSupported) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
foreach (KeyValuePair<HwIntrinsics, string> intrinsic in intrinsics.ToFeatureKeyValueCollection()) |
||||
|
{ |
||||
|
var processStartInfo = new ProcessStartInfo(); |
||||
|
if (intrinsic.Key != HwIntrinsics.AllowAll) |
||||
|
{ |
||||
|
processStartInfo.Environment[$"COMPlus_{intrinsic.Value}"] = "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()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Runs the given test <paramref name="action"/> within an environment
|
||||
|
/// where the given <paramref name="intrinsics"/> features.
|
||||
|
/// </summary>
|
||||
|
/// <param name="action">The test action to run.</param>
|
||||
|
/// <param name="intrinsics">The intrinsics features.</param>
|
||||
|
/// <param name="serializable">The value to pass as a parameter to the test action.</param>
|
||||
|
public static void RunWithHwIntrinsicsFeature<T>( |
||||
|
Action<string> action, |
||||
|
HwIntrinsics intrinsics, |
||||
|
T serializable) |
||||
|
where T : IXunitSerializable |
||||
|
{ |
||||
|
if (!RemoteExecutor.IsSupported) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
foreach (KeyValuePair<HwIntrinsics, string> intrinsic in intrinsics.ToFeatureKeyValueCollection()) |
||||
|
{ |
||||
|
var processStartInfo = new ProcessStartInfo(); |
||||
|
if (intrinsic.Key != HwIntrinsics.AllowAll) |
||||
|
{ |
||||
|
processStartInfo.Environment[$"COMPlus_{intrinsic.Value}"] = "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)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Runs the given test <paramref name="action"/> within an environment
|
||||
|
/// where the given <paramref name="intrinsics"/> features.
|
||||
|
/// </summary>
|
||||
|
/// <param name="action">The test action to run.</param>
|
||||
|
/// <param name="intrinsics">The intrinsics features.</param>
|
||||
|
/// <param name="serializable">The value to pass as a parameter to the test action.</param>
|
||||
|
public static void RunWithHwIntrinsicsFeature<T>( |
||||
|
Action<string, string> action, |
||||
|
HwIntrinsics intrinsics, |
||||
|
T serializable) |
||||
|
where T : IXunitSerializable |
||||
|
{ |
||||
|
if (!RemoteExecutor.IsSupported) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
foreach (KeyValuePair<HwIntrinsics, string> intrinsic in intrinsics.ToFeatureKeyValueCollection()) |
||||
|
{ |
||||
|
var processStartInfo = new ProcessStartInfo(); |
||||
|
if (intrinsic.Key != HwIntrinsics.AllowAll) |
||||
|
{ |
||||
|
processStartInfo.Environment[$"COMPlus_{intrinsic.Value}"] = "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<HwIntrinsics, string> ToFeatureKeyValueCollection(this HwIntrinsics intrinsics) |
||||
|
{ |
||||
|
// Loop through and translate the given values into COMPlus equivaluents
|
||||
|
var features = new Dictionary<HwIntrinsics, string>(); |
||||
|
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; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// See <see href="https://github.com/dotnet/runtime/blob/50ac454d8d8a1915188b2a4bb3fff3b81bf6c0cf/src/coreclr/src/jit/jitconfigvalues.h#L224"/>
|
||||
|
/// <remarks>
|
||||
|
/// <see cref="DisableSIMD"/> ends up impacting all SIMD support(including System.Numerics)
|
||||
|
/// but not things like <see cref="DisableBMI1"/>, <see cref="DisableBMI2"/>, and <see cref="DisableLZCNT"/>.
|
||||
|
/// </remarks>
|
||||
|
/// </summary>
|
||||
|
[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 |
||||
|
} |
||||
|
} |
||||
@ -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"; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,296 @@ |
|||||
|
// 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<HwIntrinsics, string[]> Intrinsics => |
||||
|
new TheoryData<HwIntrinsics, string[]> |
||||
|
{ |
||||
|
{ 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<HwIntrinsics, string> 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<string> actualValues = features.Select(x => x.Value); |
||||
|
Assert.Equal(expectedValues, actualValues); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void AllowsAllHwIntrinsicFeatures() |
||||
|
{ |
||||
|
if (!Vector.IsHardwareAccelerated) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
FeatureTestRunner.RunWithHwIntrinsicsFeature( |
||||
|
() => Assert.True(Vector.IsHardwareAccelerated), |
||||
|
HwIntrinsics.AllowAll); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void CanLimitHwIntrinsicSIMDFeatures() |
||||
|
{ |
||||
|
FeatureTestRunner.RunWithHwIntrinsicsFeature( |
||||
|
() => Assert.False(Vector.IsHardwareAccelerated), |
||||
|
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
|
||||
|
|
||||
|
[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(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); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void CanLimitHwIntrinsicFeaturesWithSerializableParam() |
||||
|
{ |
||||
|
static void AssertHwIntrinsicsFeatureDisabled(string serializable) |
||||
|
{ |
||||
|
Assert.NotNull(serializable); |
||||
|
Assert.NotNull(FeatureTestRunner.Deserialize<FakeSerializable>(serializable)); |
||||
|
|
||||
|
#if SUPPORTS_RUNTIME_INTRINSICS
|
||||
|
Assert.False(Sse.IsSupported); |
||||
|
#endif
|
||||
|
} |
||||
|
|
||||
|
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<FakeSerializable>(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(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()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public class FakeSerializable : IXunitSerializable |
||||
|
{ |
||||
|
public void Deserialize(IXunitSerializationInfo info) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public void Serialize(IXunitSerializationInfo info) |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue