Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is calling my C code from F# very slow (compared to native)?

Tags:

mono

f#

So I wrote some numerical code in C but wanted to call it from F#. However it runs incredibly slowly.

Times:

  • gcc -O3 : 4 seconds
  • gcc -O0 : 30 seconds
  • fsharp code which calls the optimised gcc code: 2 minutes 30 seconds.

For reference, the c code is

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

I left out the implementation of the functions. The F# code I am using is

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

The F# code is compiled with optimisations on.

Is the mono interface for calling C code really that slow (almost 8ms of overhead per function call) or am I just doing something stupid?

like image 592
John Palmer Avatar asked Mar 14 '12 05:03

John Palmer


People also ask

What is the meaning of F in C?

f = float. In c a value of 1 is an integer and 1.0 is a double, you use f after a decimal number to indicate that the compiler should treat it as a single precision floating point number.

How do I run C code on my phone?

To Install and Use C/C++ compiler in Termux (in Termux clang is the C/C++ compiler) , Download & Install Termux from : Play Store. After Installing execute this command pkg install clang. After Successfully installing clang you can compile C/C++ scripts.

How do you call C in C++?

Just declare the C++ function extern "C" (in your C++ code) and call it (from your C or C++ code). For example: // C++ code: extern "C" void f(int);


1 Answers

It looks like part of the problem is that you are using float on both the F# and C side of the PInvoke signature. In F# float is really System.Double and hence is 8 bytes. In C a float is generally 4 bytes.

If this were running under the CLR I would expect you to see a PInvoke stack unbalanced error during debugging. I'm not sure if Mono has similar checks or not. But it's possible this is related to the problem you're seeing.

like image 122
JaredPar Avatar answered Sep 20 '22 20:09

JaredPar