我有一个 C++ 方法签名,如下所示:

    static extern void ImageProcessing(
        [MarshalAs(UnmanagedType.LPArray)]ushort[] inImage,
        [MarshalAs(UnmanagedType.LPArray)]ushort[] outImage,
        int inYSize, int inXSize);

我已将函数包装在内部和外部计时方法中。在内部,该函数的运行时间为 0.24 秒。从外部来看,该函数的运行时间为 2.8 秒,大约慢了 12 倍。这是怎么回事?编组会让我的速度减慢那么多吗?如果是的话,我该如何解决这个问题?我应该使用不安全的代码并使用指针或其他东西吗?我有点困惑,额外的时间成本从何而来。

有帮助吗?

解决方案 3

答案是,可悲的是,比这些建议更世俗,虽然他们的帮助。基本上,我弄乱了与I如何在做定时。

,我用定时码是这样的:

Ipp32s timer;
ippGetCpuFreqMhz(&timer);
Ipp64u globalStart = ippGetCpuClocks();
globalStart = ippGetCpuClocks() *2 - globalStart; //use this method to get rid of the overhead of getting clock ticks

      //do some stuff

Ipp64u globalEnd = ippGetCpuClocks(); 
globalEnd = ippGetCpuClocks() *2 - globalEnd;
std::cout << "total runtime: " << ((Ipp64f)globalEnd - (Ipp64f)globalStart)/((Ipp64f)timer *1000000.0f) << " seconds" << std::endl;

此代码是特定于英特尔编译器,并且被设计为给极其精确的时间测量。不幸的是,极高的精度意味着每次运行大约2.5秒成本。除去定时代码移除时间约束。

有似乎仍然是运行时的延迟,though--代码将与该定时代码报告0.24秒,现在报告的大致0.35S定时,这意味着有大约50%的速度成本。

的代码变更为这样:

  static extern void ImageProcessing(
     IntPtr inImage, //[MarshalAs(UnmanagedType.LPArray)]ushort[] inImage,
     IntPtr outImage, //[MarshalAs(UnmanagedType.LPArray)]ushort[] outImage,
     int inYSize, int inXSize);

和称为如下:

        unsafe {
            fixed (ushort* inImagePtr = theInputImage.DataArray){
                fixed (ushort* outImagePtr = theResult){
                    ImageProcessing((IntPtr)inImagePtr,//theInputImage.DataArray,
                        (IntPtr)outImagePtr,//theResult,
                        ysize,
                        xsize);
                }
            }
        }

滴可执行时间0.3秒(平均三次运行的)。还是太慢了我的口味,但10倍的速度提升无疑是可接受的。让我老板的境界中。

其他提示

看一眼 本文. 。虽然它的重点是 Compact Framework,但一般原则也适用于桌面。分析部分的相关引用如下:

托管调用不直接调用本机方法。相反,它调用 JITted 存根方法,该方法必须执行一些开销例程,例如调用以确定 GC 抢占状态(以确定 GC 是否处于挂起状态并且我们需要等待)。一些编组代码也可能会被 JIT 到存根中。这一切都需要时间。

编辑:另外值得一读的是 这篇关于 JIT 代码性能的博客文章 - 再次强调,CF 特定,但仍然相关。还有 一篇介绍调用堆栈深度及其对性能影响的文章, ,尽管这可能是 CF 特定的(未在桌面上测试)。

你有没有尝试过交换的两个阵列参数,因此?PInvoke是在它是绝对最快的时的所有类型的调集的签名是可直接复制到本机结构中。这意味着Pinvoke归结为仅仅是memcpy获得的数据来回。

在我的团队我们已经找到了最高性能的方式管理我们的PInvoke层是

  1. 保证一切都是马歇尔就是直接复制到本机结构中的
  2. 支付的价格以手工元帅的类型,如数组通过操纵的一个因此在班上的作为需要的基础。这是非常微不足道,因为我们有很多的包装方法/课程。

作为与任何"这将以更快的速度"的答案中,你只需要简这是你自己的代码。我们只能达成这种解决方案之后的几个方法被认为是和行分析。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top