【发布时间】:2010-09-29 17:53:40
【问题描述】:
我正在阅读一个关于 c# 代码优化的问题,一个解决方案是将 c++ 与 SSE 结合使用。是否可以直接从 c# 程序进行 SSE?
【问题讨论】:
-
您的编译器会为您执行此操作,例如,当您多次遍历数组时
我正在阅读一个关于 c# 代码优化的问题,一个解决方案是将 c++ 与 SSE 结合使用。是否可以直接从 c# 程序进行 SSE?
【问题讨论】:
【讨论】:
C# 可以显式调用 SSE 吗?
没有。 C# 不能生成内联 IL,更不用说内联 x86/amd64 程序集了。
如果 SSE 可用,CLR,更具体地说是 JIT,将使用 SSE,而无需在大多数情况下强制使用它。我说得最多是因为我不是 SSE 专家,而且我确信在某些情况下它可能是有益的,而 JIT 不会进行优化。
【讨论】:
phminposuw 或 psadbw 水平操作之类的东西,或者只有通用垂直操作,例如添加原始类型的向量。
SIMD for .NET will be available 在不久的将来。此功能 ATM 需要RyuJIT(.NET 的下一代 JIT 编译器)。
您应该使用Microsoft.Bcl.Simd package 中的Microsoft.Numerics.Vectors.Vector<T> 类来利用此功能。示例代码here。
【讨论】:
根据this 论坛发帖,如果 SSE 在目标机器上可用,MS JIT 编译器会自动使用 SSE。
【讨论】:
如果您有“大块”工作要做,最好的办法是使用 MMX/SSE 内在函数在 C++ 中编写它,然后创建一个非常简单的 /clr 托管 C++ 类来包装您的功能并公开它作为一个.net类。然后您的代码就可以像使用普通类一样使用该程序集。
有关 VC 内在函数的更多信息,您可以查看我多年前写的这个小曲子。
http://msdn.microsoft.com/en-us/library/0aws1s9k.aspx
哦 - 我假设您实际上想要使用并行函数来加快速度。正如其他人所指出的 - 如果您只是想以更大的块等移动数据,JIT 已经知道如何将 SSE 用于这些基础知识。
【讨论】:
菲利普是正确的。我有另一个较旧的帖子显示了类似但更详细的示例。我实际上已经运行了这段代码,并自己修改了它以向自己证明它有效。我正在考虑在我正在工作的项目中使用这种技术,这就是为什么我要出去看看可能有什么新东西,因为这有点旧了。正如作者暗示的那样,你可以用 C++ 编写任何你想要的函数,编译它,然后将字节复制到你的 C# 中。
http://blogs.msdn.com/b/devinj/archive/2005/07/12/438323.aspx
我要补充一点,Joe 的 CLI C++ 类也是一个好主意,但是,我认为 sse 编译器标志和 /clr 标志在同一个项目上不兼容。我刚刚验证过:必须在单独的项目中编写高性能代码才能使用 SSE(/arch:sse 或 /arch:sse2)编译器标志,因为 /clr 是不兼容的。做任何比对几个输入做简单算术更复杂的事情,我认为这是最好的方法。
【讨论】:
最近微软发布了一个用于 C# 的测试版 SIMD 矢量库 (Microsoft.Bcl.Simd),它需要安装 RyuJIT CTP,并且仅适用于 Windows 8。
您也可以只使用本机 SSE 库并从 C# 调用它。例如 Yeppp 库,请参阅this StackOverflow answer。
【讨论】:
现代 C# 很好地支持 SIMD/SSE 指令并使其使用起来相当简单。并非所有指令都受支持。
以下是 uint[] 数组的 SSE .Sum() 示例:
using System.Numerics;
private static ulong SumSseInner(this uint[] arrayToSum, int l, int r)
{
var sumVectorLower = new Vector<ulong>();
var sumVectorUpper = new Vector<ulong>();
var longLower = new Vector<ulong>();
var longUpper = new Vector<ulong>();
int sseIndexEnd = l + ((r - l + 1) / Vector<uint>.Count) * Vector<uint>.Count;
int i;
for (i = l; i < sseIndexEnd; i += Vector<int>.Count)
{
var inVector = new Vector<uint>(arrayToSum, i);
Vector.Widen(inVector, out longLower, out longUpper);
sumVectorLower += longLower;
sumVectorUpper += longUpper;
}
ulong overallSum = 0;
for (; i <= r; i++)
overallSum += arrayToSum[i];
sumVectorLower += sumVectorUpper;
for (i = 0; i < Vector<long>.Count; i++)
overallSum += sumVectorLower[i];
return overallSum;
}
此特定功能是开源和免费 nuget 包 HPCsharp 的一部分,可在我维护的 nuget.org 上获得。
【讨论】:
当然可以(更重要的问题是 - 你为什么要这样做?把它留给运行时;这是它的工作)。
C# 允许您将委托映射到内存地址。该内存地址可以包含原始汇编代码。您可以在Michael Giagnocavo's blog 上阅读更多内容。
虽然我自己没试过,但也可以用Marshal.GetDelegateForFunctionPointer。
【讨论】: