2012-03-14 9 views
6

Così ho scritto un codice numerico in C ma volevo chiamarlo da F #. Tuttavia funziona incredibilmente lentamente.Perché il mio codice C viene chiamato da F # molto lento (rispetto al nativo)?

tempi:

  • gcc -O3: 4 secondi
  • gcc -O0: 30 secondi
  • codice FSharp che chiama il codice gcc ottimizzato: 2 minuti e 30 secondi.

Per riferimento, il codice 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; 
} 

ho lasciato l'implementazione delle funzioni. La F # codice che sto usando è

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]) 

Il codice F # è compilato con ottimizzazioni su.

L'interfaccia mono per chiamare il codice C è davvero lenta (quasi 8 ms di overhead per chiamata di funzione) o sto facendo qualcosa di stupido?

+1

Testato il codice su Windows? Potrebbe essere molte cose. – leppie

+7

A parte: in F # 'float' significa veramente' double' che è 8 byte. In C generalmente 'float' è 4 byte. È possibile che vi sia una mancata corrispondenza della firma di pinvoke. – JaredPar

+1

@JaredPar - questa era la risposta, sospetto che la conversione float abbia causato la modifica dei parametri in quelli che hanno causato un'esecuzione molto più lenta. Il tempo di esecuzione di F # ora è praticamente identico al semplice C. Esiste un modo per controllare queste discrepanze tra le firme? –

risposta

11

Sembra che parte del problema è che si sta usando float sia sul lato F # che sul lato C della firma PInvoke. In F # float è in realtà System.Double e quindi 8 byte. In C a float è generalmente 4 byte.

Se questo era in esecuzione sotto CLR, mi aspetto che durante il debug si verifichi un errore di sbilanciamento di StackPInvoke. Non sono sicuro che Mono abbia assegni simili o no. Ma è possibile che questo sia correlato al problema che stai vedendo.

Problemi correlati