C# 我可以在Raspberry Pi 4上使用.NET SIMD吗?

C# 我可以在Raspberry Pi 4上使用.NET SIMD吗?,c#,raspberry-pi,arm,simd,neon,C#,Raspberry Pi,Arm,Simd,Neon,我正在编写代码,将两个数组中的相应字节相减,并计算超过给定阈值的结果字节数。另外,它确实可以从.NET SIMD中获益,但是当我在Raspberry Pi 4上编译C#时,System.Numerics.Vector.IsHardwareAccelerated返回false 我添加的dotnet版本是3.1.406 <PropertyGroup> <Optimize>true</Optimize> </PropertyGroup>

我正在编写代码,将两个数组中的相应字节相减,并计算超过给定阈值的结果字节数。另外,它确实可以从.NET SIMD中获益,但是当我在Raspberry Pi 4上编译C#时,
System.Numerics.Vector.IsHardwareAccelerated
返回false

我添加的
dotnet
版本是3.1.406

  <PropertyGroup>
    <Optimize>true</Optimize>
  </PropertyGroup>
我使用的是32位Raspbian(Debian派生),是否有可能需要64位版本才能工作

另外,为了澄清,在简单的C中,算法如下所示:

publicstaticintscalartest(字节[]lhs,字节[]rhs)
{
var结果=0;
对于(int index=0;indexa)
{
(b,a)=(a,b);
}
结果+=((a-b)>=16)?1:0;
}
返回结果;
}

尽管API已经完成,甚至有文档记录,但实现仍然缺失。8字节SIMD向量是NEON ISA几十年来的重要组成部分(于2005年推出),但.NET运行时仅在为ARM64(2013年发布)编译时实现它们

我不为微软工作,也不知道他们是如何编译二进制文件的,但源代码告诉我,在为ARM64目标构建时,他们至少对NEON有一些支持。如果您想在.NET中使用这些内部函数,可以尝试使用64位操作系统


有一个解决方案——在C++中实现你的性能关键部件,编译一个Linux共享库,然后使用<代码> [DLLimPurt] < /Cord>从.NET中消费这些函数。我以这种方式构建了非平凡的Linux软件(),使用以下gcc标志构建DLL:

-march=native-mfpu=neon-fp16-mfp16 format=ieee-ffast math-O3-fPIC
这种方式将适用于32位操作系统,并且不需要.NET运行时的任何特殊功能,我已经用.NET Core 2.1进行了测试。

下面是@Soonts的答案,在切换到64位Raspbian之后,下面是我在Net5中得到的。我正在寻找的大多数说明都是支持的

Console.WriteLine(System.Runtime.InteropServices.RuntimeInformation.OSDescription);
//Linux 5.4.51-v8+ #1333 SMP PREEMPT Mon Aug 10 16:58:35 BST 2020

Console.WriteLine(System.Runtime.InteropServices.RuntimeInformation.ProcessArchitecture);
//Arm64

Console.WriteLine(System.Environment.Is64BitOperatingSystem);           //true

Console.WriteLine(System.Numerics.Vector.IsHardwareAccelerated);        //true
Console.WriteLine(Vector<byte>.Count);                                  //16
Console.WriteLine(Vector<sbyte>.Count);                                 //16
Console.WriteLine(Vector<short>.Count);                                 //8
Console.WriteLine(Vector<ushort>.Count);                                //8
Console.WriteLine(Vector<int>.Count);                                   //4
Console.WriteLine(Vector<uint>.Count);                                  //4
Console.WriteLine(Vector<long>.Count);                                  //2
Console.WriteLine(Vector<ulong>.Count);                                 //2

Console.WriteLine(Vector<float>.Count);                                 //4
Console.WriteLine(Vector<double>.Count);                                //2

Console.WriteLine(System.Runtime.Intrinsics.Arm.AdvSimd.IsSupported);   //true
Console.WriteLine(System.Runtime.Intrinsics.Arm.Aes.IsSupported);       //false
Console.WriteLine(System.Runtime.Intrinsics.Arm.ArmBase.IsSupported);   //true
Console.WriteLine(System.Runtime.Intrinsics.Arm.Crc32.IsSupported);     //true
Console.WriteLine(System.Runtime.Intrinsics.Arm.Dp.IsSupported);        //false
Console.WriteLine(System.Runtime.Intrinsics.Arm.Rdm.IsSupported);       //false
Console.WriteLine(System.Runtime.Intrinsics.Arm.Sha1.IsSupported);      //false
Console.WriteLine(System.Runtime.Intrinsics.Arm.Sha256.IsSupported);    //false
Console.WriteLine(System.Runtime.InteropServices.RuntimeInformation.OSDescription);
//Linux 5.4.51-v8+#1333 SMP抢占周一8月10日16:58:35英国夏令时2020
WriteLine(System.Runtime.InteropServices.RuntimeInformation.ProcessArchitecture);
//Arm64
Console.WriteLine(System.Environment.IS64位操作系统)//真的
Console.WriteLine(System.Numerics.Vector.IsHardwareAccelerated)//真的
控制台写入线(向量计数)//16
控制台写入线(向量计数)//16
控制台写入线(向量计数)//8.
控制台写入线(向量计数)//8.
控制台写入线(向量计数)//4.
控制台写入线(向量计数)//4.
控制台写入线(向量计数)//2.
控制台写入线(向量计数)//2.
控制台写入线(向量计数)//4.
控制台写入线(向量计数)//2.
WriteLine(System.Runtime.Intrinsics.Arm.advismd.IsSupported)//真的
WriteLine(System.Runtime.Intrinsics.Arm.Aes.IsSupported)//假的
WriteLine(System.Runtime.Intrinsics.Arm.ArmBase.IsSupported)//真的
Console.WriteLine(System.Runtime.Intrinsics.Arm.Crc32.IsSupported)//真的
WriteLine(System.Runtime.Intrinsics.Arm.Dp.IsSupported)//假的
WriteLine(System.Runtime.Intrinsics.Arm.Rdm.IsSupported)//假的
Console.WriteLine(System.Runtime.Intrinsics.Arm.Sha1.IsSupported)//假的
Console.WriteLine(System.Runtime.Intrinsics.Arm.Sha256.IsSupported)//假的
在实现了将两个字节数组中的元素与abs进行比较的算法之后。差异超过某个阈值,在我的Pi 4上,我得到了以下基准测量值(预热后平均运行3次):

C#回路:

59毫秒

System.Numerics.Vector

21毫秒

System.Runtime.Intrinsics.Arm.AdvSimd

17毫秒

System.Runtime.Intrinsics.Arm.AdvSimd
使用优化的矢量创建从


2ms

“.减去相应的字节…”两个相应字节的减法将始终为零,对吗@JHBonarius我不知道这个词的最佳术语,我的意思是
arr1[I]-arr2[I]
。我将添加C#loop实现来解释我的意思。我希望NEON的性能提高3倍以上,字节很小,向量寄存器有16个字节。尝试将下面的C++移植到.NET中:(未经测试但想法相当简单)@从我所看到的,我几乎有完全相同的代码:我猜想字节数组中的向量创建可能更有效,并且会尝试重新解释阈值后结果而不是应用一个掩码。我改变了加载向量的方式,得到了2毫秒的平坦!您也可以尝试这个版本:它需要/unsafe编译器开关,但我认为它可能会稍微快一点。
Console.WriteLine(System.Runtime.InteropServices.RuntimeInformation.OSDescription);
//Linux 5.4.51-v8+ #1333 SMP PREEMPT Mon Aug 10 16:58:35 BST 2020

Console.WriteLine(System.Runtime.InteropServices.RuntimeInformation.ProcessArchitecture);
//Arm64

Console.WriteLine(System.Environment.Is64BitOperatingSystem);           //true

Console.WriteLine(System.Numerics.Vector.IsHardwareAccelerated);        //true
Console.WriteLine(Vector<byte>.Count);                                  //16
Console.WriteLine(Vector<sbyte>.Count);                                 //16
Console.WriteLine(Vector<short>.Count);                                 //8
Console.WriteLine(Vector<ushort>.Count);                                //8
Console.WriteLine(Vector<int>.Count);                                   //4
Console.WriteLine(Vector<uint>.Count);                                  //4
Console.WriteLine(Vector<long>.Count);                                  //2
Console.WriteLine(Vector<ulong>.Count);                                 //2

Console.WriteLine(Vector<float>.Count);                                 //4
Console.WriteLine(Vector<double>.Count);                                //2

Console.WriteLine(System.Runtime.Intrinsics.Arm.AdvSimd.IsSupported);   //true
Console.WriteLine(System.Runtime.Intrinsics.Arm.Aes.IsSupported);       //false
Console.WriteLine(System.Runtime.Intrinsics.Arm.ArmBase.IsSupported);   //true
Console.WriteLine(System.Runtime.Intrinsics.Arm.Crc32.IsSupported);     //true
Console.WriteLine(System.Runtime.Intrinsics.Arm.Dp.IsSupported);        //false
Console.WriteLine(System.Runtime.Intrinsics.Arm.Rdm.IsSupported);       //false
Console.WriteLine(System.Runtime.Intrinsics.Arm.Sha1.IsSupported);      //false
Console.WriteLine(System.Runtime.Intrinsics.Arm.Sha256.IsSupported);    //false