2012-03-14 8 views
6

私はCでいくつかの数値コードを書いたが、F#からそれを呼びたいと思った。しかし、それは信じられないほどゆっくりと実行されます。私のCコードをF#から呼び出すのがなぜ(ネイティブと比べて)非常に遅いのですか?

時間:

  • GCC -03:4秒
  • GCC -O0:2分30秒:最適化されたGCCコードを呼び出し、30秒
  • fsharpコード。私は機能の実装を残し

    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; 
    } 
    

は参考のために、Cコードです。私が使用している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コードを呼び出すためのモノラルインターフェイスは本当に遅いです(関数呼び出しごとにオーバーヘッドがほぼ8ミリ秒)か、何かばかげているだけですか?

+1

Windowsでコードをテストしましたか?多くのことができます。 – leppie

+7

脇に:F#で 'float'は実際には8バイトの' double'を意味します。 Cでは、通常、 'float'は4バイトです。そこにピンボークのシグネチャの不一致があります。 – JaredPar

+1

@ JaredPar - それは答えでした。私は、浮動小数点数の変換によってパラメータが非常に遅い実行を引き起こしたものに変更されたと思われます。 F#ランタイムは現在、Cとほぼ同じです。これらのシグネチャのミスマッチをチェックする方法はありますか? –

答えて

11

問題の一部は、をPInvoke署名のF#とCの両方で使用しているようです。 F#floatでは、実際にはSystem.Doubleであり、したがって8バイトです。 Cでは、floatは一般に4バイトです。

これがCLRで実行されていた場合は、デバッグ中にPInvokeスタックの不平衡エラーが発生することが予想されます。 Monoに類似のチェックがあるかどうかはわかりません。しかし、これはあなたが見ている問題に関連している可能性があります。

関連する問題