Jump to content
  • Advertisement
Sign in to follow this  
TrashCondor

[.net] .NET & COM & DLL interop efficiency

This topic is 3749 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I was wondering after a discussion with a colleague, how efficient is .NET communication with normal C++ DLLs and COM DLLs? It is something that works but not smart. Is it viable for high performance code? Is there anything else to consider that I don't know to ask? :) thanks!

Share this post


Link to post
Share on other sites
Advertisement
Do you have any examples or specific topics you would like to talk about? You can't say much about such a broad topic. I will put in that, although there IS a performance hit when marshaling between managed and unmanaged code, Winforms relies heavily on it. Also, our SlimDX project, which interops with .NET and DirectX, doesn't seem to have any performance problems either.

Share this post


Link to post
Share on other sites
Ah :) thanks for the reply. I don't have a specific scenario in mind. Just the question at face value regarding how efficient interop is.

For example, how many interop operations can I reliably perform per second without noticeably affecting main program execution?

Is the interop affected by the actual objects themselves? (Objects that contain a lot of data might aversely effect interop time?)

Do I want to use interops to transfer data from and to .NET to and from DLL, or is some other mechanism more appropriate?

Thanks, again

Share this post


Link to post
Share on other sites
You can only get a solid answer for yourself by trying it out and comparing. It entirely depends on what you're doing, how smart you are about creating the bindings, how the library is structured, understanding the pitfalls that can kill the performance of a .net application, etc.

That said, my experience has always been that the overhead of interoping managed and unmanaged code is minimal.

A random example of something that adds overhead would be say, passing matrix info to OpenGl. If you use glLoadMatrixf, and pass it a managed array, the data contained in the array will get copied to it's unmanaged equivalent prior to being passed to OpenGL. I imagine something similar happens with SlimDX.

Due to issues like that, I don't think I've ever gotten a c# opengl app to run quite as fast as the c++ equivalent, but personally I'm willing to sacrifice a tiny bit of performance to work in a less headache-prone development environment.

And by tiny bit, I'm talking maybe 1-5%. Though I haven't come up with that number though exhaustive profiling or anything, so don't see that as carved in stone. It's just my general experience from using both languages.

Share this post


Link to post
Share on other sites
One example I will throw out there is that for SlimDX, we opted to reimplement much of the math library functionality in .NET instead of calling the native DirectX equivalents. For example, instead of calling D3DXVec3Add() to add two vectors, we would do the addition by hand in .NET.

This is because, while the overhead might be minimal, it IS still there, and for trivial operations the overhead outweighs any speed penalties incurred by doing the operation in managed code. There is a certain point where it becomes more efficient to do the work in the unmanaged DLL and eat the interop overhead (a great example is operations that work on arrays, such as transforming an array of matrices), but what that exact point is I don't know.

Share this post


Link to post
Share on other sites
The steps involved in an interop call, from this page:

* The function call arguments are marshaled from CLR to native types.
* A managed-to-unmanaged thunk is executed.
* The unmanaged function is called (using the native versions of the arguments).
* An unmanaged-to-managed thunk is executed.
* The return type and any "out" or "in,out" arguments are marshaled from native to CLR types.

There's also a security check before all of that to make sure that the code has native code privileges. There's a fixed cost for most of these steps, except that the type marshaling complexity depends on exactly what needs to be done.

Share this post


Link to post
Share on other sites
How you implement it will make a big difference.
For example you don't have to use COM, though that might be the easiest way to do it.
You can allocate an array in .NET, pin it, and pass a raw pointer to the DLL, so you can exchange large amounts of data with minimal penalty if you're writing all the code.

Here's the Tao code to send a Single[] to glLoadMatrixf


//Delegates
[System.Security.SuppressUnmanagedCodeSecurity()]
internal unsafe delegate void LoadMatrixf(Single* m);
internal unsafe static LoadMatrixf glLoadMatrixf;

[System.Security.SuppressUnmanagedCodeSecurity()]
[System.Runtime.InteropServices.DllImport(Gl.Library, EntryPoint = "glLoadMatrixf", ExactSpelling = true)]
internal extern static unsafe void LoadMatrixf(Single* m);

//Single[] overload
public static
void glLoadMatrixf(Single[] m)
{
unsafe
{
fixed (Single* m_ptr = m)
{
Delegates.glLoadMatrixf((Single*)m_ptr);
}
}
}


Pinning & unpinning the array (fixed) has some overhead locking down the memory but I don't believe a copy is made.

Share this post


Link to post
Share on other sites
...

Shouldn't the built in automatic marshalling be doing exactly that when passing an array to native code? It shouldn't be necessary to write a function to do it explicitly. SlimDX of course does the exact same thing, but in C++ and we can't use the automatic marshalling.

Share this post


Link to post
Share on other sites
Quote:
Original post by Promit
...

Shouldn't the built in automatic marshalling be doing exactly that when passing an array to native code? It shouldn't be necessary to write a function to do it explicitly. SlimDX of course does the exact same thing, but in C++ and we can't use the automatic marshalling.


There are two reasons to have a function:
a) it's faster to pass a fixed pointer instead of relying on the automatic marshaller, which may copy memory.
b) DllImports do not work with OpenGL extension methods (the function above wraps a delegate which holds the actual function pointers).

(b) could be worked around by hacking the generated IL - which is exactly what Tao was doing before Marshal.GetDelegateForFunctionPointer came along.

(a) AFAIK the automatic marshaller may either pin the array or copy it, depending on size (and possibly other parameters we don't have any control over). As long as the function is using server storage, it will *always* be faster to just pin the array, since OpenGL will copy it internally anyway.

By the way, are you using IJW for interop? If so, have you run any performance tests?

My testing on Mono indicates that C# interop adds about 6-7 ns of overhead on a DllImported function (tested on a 2.6GHz Core 2), on Linux. Windows/.Net add more overhead (about 15ns). Tao is a little slower than that, since it routes calls through delegates.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!