为什么从F#调用我的C代码非常慢(与本机相比)?

问题描述:

所以我写了一些数字代码在C,但想从F#调用它。然而它运行得非常慢。为什么从F#调用我的C代码非常慢(与本机相比)?

时报:

  • GCC -O3:4秒
  • GCC -O0:30秒
  • fsharp代码调用优化GCC代码:2分30秒。

作为参考,C代码是

int main(int argc, char** argv) 
{ 
    setvals(100,100,15,20.0,0.0504); 
    float* dmats = malloc(sizeof(float) * factor*factor); 
    MakeDmat(1.4,-1.92,dmats); //dmat appears to be correct 
    float* arr1 = malloc(sizeof(float)*xsize*ysize); 
    float* arr2 = malloc(sizeof(float)*xsize*ysize); 
    randinit(arr1); 
    for (int i = 0;i < 10000;i++) 
    { 
      evolve(arr1,arr2,dmats); 
      evolve(arr2,arr1,dmats); 
      if (i==9999) {print(arr1,xsize,ysize);}; 
    } 
    return 0; 
} 

我离开了的功能的实现。我正在使用的F#代码是

open System.Runtime.InteropServices 
open Microsoft.FSharp.NativeInterop 

[<DllImport("a.dll")>] extern void main (int argc, char* argv) 
[<DllImport("a.dll")>] extern void setvals (int _xsize, int _ysize, int _distlimit,float _tau,float _Iex) 
[<DllImport("a.dll")>] extern void MakeDmat(float We,float Wi, float*arr) 
[<DllImport("a.dll")>] extern void randinit(float* arr) 
[<DllImport("a.dll")>] extern void print(float* arr) 
[<DllImport("a.dll")>] extern void evolve (float* input, float* output,float* connections) 

let dlimit,xsize,ysize = 15,100,100 
let factor = (2*dlimit)+1 
setvals(xsize,ysize,dlimit,20.0,0.0504) 
let dmat = Array.zeroCreate (factor*factor) 
MakeDmat(1.4,-1.92,&&dmat.[0]) 

let arr1 = Array.zeroCreate (xsize*ysize) 
let arr2 = Array.zeroCreate (xsize*ysize) 
let addr1 = &&arr1.[0] 
let addr2 = &&arr2.[0] 
let dmataddr = &&dmat.[0] 
randinit(&&dmat.[0]) 
[0..10000] |> List.iter (fun _ -> 
    evolve(addr1,addr2,dmataddr) 
    evolve(addr2,addr1,dmataddr) 
     ) 

print(&&arr1.[0]) 

F#代码是在优化上编译的。

调用C代码的单一接口真的很慢(每个函数调用的开销几乎为8ms)还是我只是在做一些愚蠢的事情?

+1

测试在Windows的代码?可能是很多事情。 – leppie 2012-03-14 05:18:33

+7

另外:在F#中,'float'的意思是'double',它是8个字节。在C中,通常'float'是4个字节。您可能会遇到一个严重的签名不匹配问题。 – JaredPar 2012-03-14 05:18:51

+1

@JaredPar - 这就是答案,我怀疑浮点数转换会导致参数被更改为导致执行速度更慢的参数。 F#的运行时间现在几乎与普通的C相同。是否有一些方法来检查这些签名不匹配? – 2012-03-14 05:29:31

看起来是问题的一部分是,你正在使用的F#和PInvoke的签名的C面都float。在F#float实际上是System.Double,因此是8个字节。在C a float通常是4个字节。

如果是这样的CLR下运行我希望你看到的PInvoke在调试过程中堆栈不平衡错误。我不确定莫诺是否有类似的检查。但这可能与您看到的问题有关。