【发布时间】:2015-12-17 12:46:43
【问题描述】:
我正在尝试使用 System.Numerics.Vector(T) 对算法进行矢量化并利用 CPU 的 SIMD 操作。但是,我的向量实现比我的原始实现慢得多。使用可能没有记录的向量有什么技巧吗?这里的具体用途是尝试加速 kb 数据的异或运算。
不幸的是,我能找到的几乎所有文档都是基于 RyuJIT 的预发布版本,我不知道有多少材料可以移植到 .NET Native。
当我在 Vector xor 操作期间检查反汇编时,它显示:
00007FFB040A9C10 xor eax,eax
00007FFB040A9C12 mov qword ptr [rcx],rax
00007FFB040A9C15 mov qword ptr [rcx+8],rax
00007FFB040A9C19 mov rax,qword ptr [r8]
00007FFB040A9C1C xor rax,qword ptr [rdx]
00007FFB040A9C1F mov qword ptr [rcx],rax
00007FFB040A9C22 mov rax,qword ptr [r8+8]
00007FFB040A9C26 xor rax,qword ptr [rdx+8]
00007FFB040A9C2A mov qword ptr [rcx+8],rax
00007FFB040A9C2E mov rax,rcx
为什么它不为此使用 xmm 寄存器和 SIMD 指令?同样奇怪的是,SIMD 指令是为我没有明确矢量化的代码版本生成的,但它们从未被执行,有利于常规寄存器和指令。
我确保我运行时启用了 Release、x64、Optimize code。我在 x86 编译中看到了类似的行为。我对机器级的东西有点新手,所以可能只是这里发生了一些我没有正确理解的事情。
Framework 版本为 4.6,Vector.IsHardwareAccelerated 在运行时为 false。
更新:“使用 .NET Native 工具链编译”是罪魁祸首。启用它会导致 Vector.IsHardwareAccelerated == false;禁用它会导致 Vector.IsHardwareAccelerated == true。我已经确认,当禁用 .NET Native 时,编译器正在使用 ymm 寄存器生成 AVX 指令。这就引出了一个问题……为什么在 .NET Native 中未启用 SIMD?有什么办法可以改变吗?
更新切线:我发现未执行自动 SSE 向量化数组代码的原因是编译器插入了一条指令,该指令查看数组的开头是否为在比数组的最后一个元素低的地址处,如果是,则仅使用普通寄存器。我认为这一定是编译器中的一个错误,因为按照惯例,数组的开头应始终位于比其最后一个元素低的地址。它是测试每个操作数数组的内存地址的一组指令的一部分,我认为是为了确保它们不重叠。我为此提交了 Microsoft Connect 错误报告:https://connect.microsoft.com/VisualStudio/feedback/details/1831117
【问题讨论】:
-
这是什么框架版本?硬件加速是否报告为
true? -
框架版本 4.6,IsHardwareAccelerated 返回 false。
-
why is SIMD not enabled in .NET Native?我只能大胆猜测:SIMD 由 JIT(即时编译器,在运行时将 IL 代码转换为本机代码的东西)处理。 .NET 本机通过创建纯本机程序集(无需翻译)完全绕过 JIT。我猜他们根本没有在.NET 本机工具链中实现 SIMD 支持。要么是因为他们还没有时间,要么是因为 .NET 本机可用于创建在没有 SIMD 寄存器的 CPU 上运行的程序 -
KooKiz,这有点道理,但 .NET Native 确实在一定程度上使用了 SSE 寄存器和指令,而且我知道有一种方法可以评估 CPU 是否具有指示与否。所以我只能假设这是由于前者。但是,有一篇博文同时吹捧通用 Windows 应用程序中的 .NET Native 和 SIMD,建议现在两者都应该是可能的:blogs.msdn.com/b/dotnet/archive/2015/07/30/…
-
System.Numerics.Vector.dll 版本 4.1.0.0 中的 Vector 需要支持 AVX 指令集的处理器。至少英特尔 Sandy Bridge 或 AMD Bulldozer。这是像 .NET Native 这样的提前编译器的问题,不能保证目标机器有这样的处理器。
标签: .net assembly simd uwp .net-native