Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Optimize managed to native calls

What can be done to speed up calling native methods from managed code?

I'm writing a program which needs to be able to manage arbitrarily-sized lists of objects and retrieve information from them at high speed, which it feeds into scripts. Scripts are bits of compiled C# code. I'm writing a basic interface layer from the C++ (native) DLL/SO/etc to the C# (.Net or Mono) management layer.

Now, I've been doing some testing, and I've found that on average, PInvoking a native method from managed code is something like 100 times slower than doing it all in managed (all native and all managed are identically fast, for reference).

The syntax I was using is:

[DllImport("test.dll")]
extern static public String test_method(String value);

String returnedValue = test_method("hello world");

Is there a way to cache a pointer to the function, some code of fast invoker, that would increase speed after loading the native library? That would solve the problem quite neatly, so I doubt it exists. :P

Edit: I didn't specify, but this needs to work on Windows, Linux (Ubuntu at least) and Mac OS X, all for both x86 and x64. Otherwise I would've gone with a C++/CLI interface and been done with it, but unless that works for all 3 platforms, I can't use it.

like image 581
ssube Avatar asked Jul 29 '10 01:07

ssube


2 Answers

Perhaps the string marshalling is what is causing a slowdown. For comparison sake, try to profile a function that takes and returns elementary C++ types like int.

You can also try to experiment with C++/CLI. That way you can take explicit control over the marshalling and maybe see an improvement.

In C++/CLI assembly:

System::String ^ test_method(System::String ^ args)
{
    pin_ptr<const wchar_t> pp = PtrToStringChars(args);
    //This might leak, probably needs a smart pointer to wrap it
    wchar_t* ret = native_method(pp);
    return gcnew String^(ret);
}
like image 44
Igor Zevaka Avatar answered Nov 15 '22 03:11

Igor Zevaka


Further to my question comment, we've established that it was a debug build with the debugger attached. This has a massive impact on runtime performance of .NET code. Easy mistake to make. :)

I'm guessing with a release build and no debugger attached, the performance difference is now much more reasonable.

If you have a very chatty API, and the native methods being called are cheap, then method call overhead can be a performance issue. Try and design a less chatty API. This is a typical technique used to increase the performance of boundary\systems communications.

If performance is acceptable after sorting the debugger issue, there is a simple technique that I have used to easily get a substantial performance increase in chatty APIs, by just adding a single attribute.

In the classes where you have your imported functions (i.e. the DllImport functions), place the SuppressUnmanagedCodeSecurity attribute on the classes. This will remove some expensive security checking from each P/Invoke call. Please see the documentation on SuppressUnmanagedCodeSecurity to understand the ramifications of this. I tend to keep my imported functions grouped together in internal classes (that only contain imported functions) with this attribute applied.

like image 82
Tim Lloyd Avatar answered Nov 15 '22 04:11

Tim Lloyd