【问题标题】:Using SSE in c# is it possible?可以在 c# 中使用 SSE 吗?
【发布时间】:2010-09-29 17:53:40
【问题描述】:

我正在阅读一个关于 c# 代码优化的问题,一个解决方案是将 c++ 与 SSE 结合使用。是否可以直接从 c# 程序进行 SSE?

【问题讨论】:

  • 您的编译器会为您执行此操作,例如,当您多次遍历数组时

标签: c# sse


【解决方案1】:

即将发布的Mono 2.2 版本将支持 SIMD。 Miguel de Icaza 在博客中介绍了即将推出的功能 here,API 为 here

虽然将有一个库支持在 Microsoft 的 .NET Windows 运行时下进行开发,但除非您在 Mono 运行时下运行代码,否则它不会具有您正在寻找的性能优势。根据您的情况,这可能是可行的。

更新:Mono 2.2 是 released

【讨论】:

  • 啊,这在 .NET 中真是太好了。对 Mono 表示敬意,因为它甚至为 .NET 制作了软件实现,但对 MS 感到羞耻。
  • 如果我为我的 c# 项目链接 c++ .dll 怎么办?我可以在里面使用内在函数吗?
  • 更新:官方的 MS .NET 运行时也获得了 SIMD 支持(目前处于 CTP 阶段)。 blogs.msdn.com/b/dotnet/archive/2014/04/07/…
  • FYI,下一个 Runtime 的最新版本是 CTP4(如果我没记错的话),你可以在这里下载:blogs.msdn.com/b/clrcodegeneration/archive/2014/05/12/… -- 并且代码向后兼容非 CTP运行时,所以它仍然可以工作,只是不会利用 SIMD 指令。
【解决方案2】:

C# 可以显式调用 SSE 吗?

没有。 C# 不能生成内联 IL,更不用说内联 x86/amd64 程序集了。

如果 SSE 可用,CLR,更具体地说是 JIT,将使用 SSE,而无需在大多数情况下强制使用它。我说得最多是因为我不是 SSE 专家,而且我确信在某些情况下它可能是有益的,而 JIT 不会进行优化。

【讨论】:

  • 您能否提供 JIT 将在何处使用 SSE 的参考和/或示例?有没有办法以对 SSE 友好的方式编写代码?
  • @Konrad,查看 David Notario 的博客。他有一些关于 CLR 在何处使用 SSE2 的详细信息。 blogs.msdn.com/davidnotario/archive/2005/08/15/451845.aspx
  • 我知道这是一个旧响应,但实际上可以在 C# 中执行任意程序集。您不需要不安全,也不需要后编译器。您确实需要代码权限才能调用 Win32 VirtualAlloc。见stackoverflow.com/a/7964376/344638
  • 我认为这个答案现在已经过时了; C# 确实有 SSE/AVX 或至少通用 SIMD。不确定它是否真的暴露了 SSE shuffle 和诸如 phminposuwpsadbw 水平操作之类的东西,或者只有通用垂直操作,例如添加原始类型的向量。
【解决方案3】:

SIMD for .NET will be available 在不久的将来。此功能 ATM 需要RyuJIT(.NET 的下一代 JIT 编译器)。

您应该使用Microsoft.Bcl.Simd package 中的Microsoft.Numerics.Vectors.Vector<T> 类来利用此功能。示例代码here

【讨论】:

    【解决方案4】:

    根据this 论坛发帖,如果 SSE 在目标机器上可用,MS JIT 编译器会自动使用 SSE。

    【讨论】:

    • 有点。它检查 SSE 的 rev 以了解它是否可以访问一些不错的通用指令,如 LZCNT、POPCNT 和一些将使用扩展寄存器移动更大内存块的指令。它不会自动并行化任何东西。
    【解决方案5】:

    如果您有“大块”工作要做,最好的办法是使用 MMX/SSE 内在函数在 C++ 中编写它,然后创建一个非常简单的 /clr 托管 C++ 类来包装您的功能并公开它作为一个.net类。然后您的代码就可以像使用普通类一样使用该程序集。

    有关 VC 内在函数的更多信息,您可以查看我多年前写的这个小曲子。

    http://msdn.microsoft.com/en-us/library/0aws1s9k.aspx

    哦 - 我假设您实际上想要使用并行函数来加快速度。正如其他人所指出的 - 如果您只是想以更大的块等移动数据,JIT 已经知道如何将 SSE 用于这些基础知识。

    【讨论】:

      【解决方案6】:

      菲利普是正确的。我有另一个较旧的帖子显示了类似但更详细的示例。我实际上已经运行了这段代码,并自己修改了它以向自己证明它有效。我正在考虑在我正在工作的项目中使用这种技术,这就是为什么我要出去看看可能有什么新东西,因为这有点旧了。正如作者暗示的那样,你可以用 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 是不兼容的。做任何比对几个输入做简单算术更复杂的事情,我认为这是最好的方法。

      【讨论】:

        【解决方案7】:

        最近微软发布了一个用于 C# 的测试版 SIMD 矢量库 (Microsoft.Bcl.Simd),它需要安装 RyuJIT CTP,并且仅适用于 Windows 8。

        您也可以只使用本机 SSE 库并从 C# 调用它。例如 Yeppp 库,请参阅this StackOverflow answer

        【讨论】:

          【解决方案8】:
          【解决方案9】:

          现代 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 上获得。

          【讨论】:

            【解决方案10】:

            当然可以(更重要的问题是 - 你为什么要这样做?把它留给运行时;这是它的工作)。

            C# 允许您将委托映射到内存地址。该内存地址可以包含原始汇编代码。您可以在Michael Giagnocavo's blog 上阅读更多内容。

            虽然我自己没试过,但也可以用Marshal.GetDelegateForFunctionPointer

            【讨论】:

            • 运行时可能会也可能不会使用一些 SSE 指令,但它不会向量化您的代码。这意味着您错过了可能对您很重要的显着性能加速。
            • 每个人,包括 MS 都不同意这里的“你为什么要”——编译器/运行时无法检测到 SIMD 指令对你有意义的大多数情况——因此,MS 的下一代版本运行时 (RyuJIT) 支持开发人员直接从 C# 指定的 SIMD 优化。 -- 我知道你在 2009 年发布了这个答案,但这是一个非常封闭的答案,这种心态应该被整个社区所阻止。
            猜你喜欢
            • 1970-01-01
            • 2013-05-22
            • 1970-01-01
            • 2015-07-21
            • 2019-06-14
            • 2012-07-09
            • 2018-05-31
            • 2012-07-02
            • 1970-01-01
            相关资源
            最近更新 更多