2009-01-19 50 views
2

我有一个C++方法签名,看起来像这样:.NET编组速度

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

我包裹功能定时的方法,包括内部和外部。在内部,该功能运行在0.24s。从外部来看,该功能运行时间为2.8s,约慢12倍。这是怎么回事?编组是否放慢了我的速度?如果是这样,我该如何解决这个问题?我应该去不安全的代码和使用指针或什么?对于额外的时间成本来自哪里,我有些fl ed不安。

回答

0

可悲的是,答案远比这些建议更普通,尽管它们确实有帮助。基本上,我搞乱了我的时间表。

,我用定时码是这样的:

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秒的成本。删除时间码删除了时间限制。

尽管运行时似乎还有延迟 - 代码会在该时间码上报0.24秒,现在报告的时间约为0.35秒,这意味着速度成本大约为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倍的速度提高肯定在我老板的可接受范围内。

3

看看this article。虽然它的重点是Compact Framework,但一般原则也适用于桌面。分析部分的相关报价如下:

托管调用不直接调用本地方法。相反,它会调用JITted存根方法,该方法必须执行一些开销例程,例如调用以确定GC抢占状态(以确定GC是否正在等待并且需要等待)。也有可能某些编组代码也会被打入存根中。这一切都需要时间。

编辑:也值得一读的是this blog article on perf of JITted code - 再次,CF具体,但仍然具有现实意义。也有an article covering call stack depth and its impact on perf,虽然这可能是特定于CF(未在桌面上测试过)。

+0

我从这收集的是我需要使用不安全的代码。我很酷,我会做转换并运行测试,并让你知道我的结果。 – mmr 2009-01-19 22:07:37

2

您是否尝试将两个数组参数切换到IntPtr?当编组签名中的所有类型都是blittable时,PInvoke是绝对最快的。这意味着Pinvoke只是简单的memcpy来获取数据。

在我的球队,我们发现来管理我们的PInvoke层最高效的办法就是

  1. 保证,一切为Marshall'd是blittable
  2. 付出代价手动元帅类型,比如数组通过根据需要操作IntPtr类。这是非常微不足道的,因为我们有很多包装方法/类。

与任何“这将是更快”的答案,你需要配置这是你自己的代码库。我们只是在考虑并分析了几种方法后才得出这个解决方案。

+0

我会测试一下。 – mmr 2009-01-19 22:08:45