从C ++ / CLI获得最佳性能

时间:2016-08-10 10:07:29

标签: c# .net performance c++-cli

对我的应用程序进行概要分析表明,50%的运行时用在packArrays()函数中,该函数执行数组转换,其中C ++强大地优于C#。

为了提高性能,我在unsafe中使用packArrays在运行时仅获得了较低的单位数百分比改进。为了消除缓存作为瓶颈,为了估计性能提升的上限,我在C ++中编写了packArrays并计算了两种语言的差异。 C ++版本的运行速度比C#快约5倍。我决定试试C ++ / CLI。

因此,我有三个实现:

  1. C ++ - 一个简单的packArrays()函数
  2. C# - packArrays()被包装到一个类中,但函数内部的代码与C ++版本相同
  3. C ++ / CLI - 如下所示,但packArrays()的实现与前两个相同(字面意思)
  4. C ++ / CLI实现如下

    QCppCliPackArrays.cpp

    public ref class QCppCliPackArrays
    {
         void pack(array<bool> ^ xBoolArray, int xLen, array<int> ^% yBoolArray, int % yLen)
            {
                // prepare variables
                pin_ptr<bool> xBoolArrayPinned = &xBoolArray[0];
                bool * xBoolArray_ = xBarsAreTruePinned;
    
                pin_ptr<bool> yBoolArrayPinned = &yBoolArray[0];
                bool * yBoolArray_ = yBarsAreTruePinned;
    
                // go
                packArrays(xBoolArray_, xBarCount, yBoolArray_ , yLen);
            }
    };
    

    packArraysWorker.cpp

    #pragma managed(push, off)
        void packArrays(bool * xArray, int xLen, bool * yArray, int & yLen)
        {
            ... actual code that is identical across languages code ...
        }
    #pragma managed(pop)
    

    QCppCliPackArrays.cpp使用\clr选项进行编译,packArraysWorker.cpp使用No Common Language RunTime Support选项进行编译。

    问题:当使用C#应用程序同时运行C#和C ++ / CLI实现时,C ++ / CLI实现仍然只比C#快一点。

    问题:

    1. 我可以使用其他选项/设置/关键字来提高C ++ / CLI的性能吗?
    2. 与C ++相比,C ++ / CLI的性能损失是否完全归功于互操作?目前,对于10K重复,C#比C ++运行慢4.5秒,每次重复互操作0.45毫秒。由于所有传递的类型都是blittable,我希望interop能够......只是传递一些指针。
    3. 使用P / Invoke可以获得任何收益吗?从我不读的内容来看,但总是要问问。
    4. 我还能使用其他方法吗?桌子上的性能提升了五倍太多了。
    5. 所有时间都在Release / x64中从命令行(而不是VS)在单个线程上进行。

      修改

      为了确定因互操作而造成的性能损失,我在Stopwatch电话周围放置了QCppCliPackArrays::packArrays()以及在chrono::high_resolution_clock本身内放置packArrays()。结果表明C# - &lt; - &gt; C ++ / CLI开关的成本约为。每10K呼叫5毫秒。根据结果​​,从托管C ++ / CLI切换到非托管C ++ / CLI,没有任何成本。

      因此,可以排除互操作作为性能退化的原因。

      另一方面,显而易见的是packArrays()不是作为非托管运行的!但为什么呢?

      编辑2: 我试图将packArrays()链接为从单独的非托管C ++库导出的.lib文件。结果仍然相同。

      编辑3: 实际的packArrays就是这个

      public void packArrays(bool[] xConditions, int[] xValues, int xLen, ref int[] yValuesPacked, ref int yPackedLen)
      {
          // alloc
          yPackedLen = xConditions.trueCount();
          yValuesPacked = new int [yPackedLen];
      
          // fill
          int xPackedIdx  = 0;
          for (int xIdx = 0; xIdx < xLen; xIdx++)
              if (xConditions[xIdx] == true)
                  yValuesPacked[xPackedIdx++] = xValues[xIdx];
      }
      

      进入yValuesPacked会将xValues中的所有值放在相应的xConditions[i]为真的位置。

      现在,我正面临一个新问题 - 我有几个旨在解决这个问题的实现,所有这些实现都正常(测试)。当我运行一个基准测试时,会在数组86K项上长时间调用这些不同的实现50K次,我会在几秒钟内获得以下timinigs:

      benchmark timings

      原始实现originalArray是上面列出的代码。显然,QCsCpp *版本在基准测试中占主导地位 - 这些是使用C ++ / CLI的实现。但是,当我在原始应用程序中替换originalArray时,多次调用packArrays,使用QCsCpp *实现,整个应用程序运行SLOWER。有了这个结果,我真的很无能,我必须承认它真诚地粉碎了我。这怎么可能是真的?一如既往,非常感谢任何见解。

0 个答案:

没有答案