The Wavelength
The Wavelength

Reputation: 2914

Callback with PInvoke is very slow

I'm using a native/unmanaged C++ DLL in my C# application. I call a native function to register a callback method in C# using PInvoke:

[DllImport("MyHook.dll", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.U1)] // necessary due to http://dotnet.dzone.com/articles/pinvoke-c-bool-return-values
private static extern bool InstallHook(CallbackPrototype callback);

private delegate int CallbackPrototype(byte* bytes, int size, int max);

// ...

var callback = new CallbackPrototype(MyCallback);
_callbackHandle = GCHandle.Alloc(callback);
var result = InstallHook(callback);

// somewhere when I'm removing the hook, I call _callbackHandle.Free();

Then, when an event happens, the native C++ DLL calls my callback.

private int MyCallback(byte* bytes, int size, int max)
{
    //var buffer = new byte[size]; // A
    //Marshal.Copy(new IntPtr(bytes), buffer, 0, size); // B

    //WrapperInstance.ParseBytes(buffer, 0, size); // C
    var x = 1 + 1; // D

    return size;
}

When everything is commented out, it works well. If I start uncommenting line A in the callback, it gets veeery slow. I notice it because the callback is called in a critical moment. It isn't acceptable that the callback runtime duration is so long that I notice it as a human being.

How could this happen? The size parameter is only from one to 100. Thats only 100 bytes at maximum that need to be allocated - very few for todays computers. I need improvements to make the runtime of the callback much faster. Any ideas?

To go further in testing, I've added line D. This does not have any impact.

Edit: For more detailed testing I've allocated a big buffer when the class is created. So line A is not in the callback anymore. If line B is then commented out, it suddenly starts taking a huge amount of time again. This must have something to do with the managed code / virtual machine. I hope there are possibilities to make it faster.

Upvotes: 1

Views: 1196

Answers (1)

aevitas
aevitas

Reputation: 3833

What you're basically doing is copying the bytes over into your buffer, and then parsing them afterwards. You could do that in one go, like so:

        var bytes = ReadBytes(address, Marshal.SizeOf(typeof(T)), isRelative);

        fixed (byte* b = bytes)
            return (T) Marshal.PtrToStructure(new IntPtr(b), typeof (T));

I've taken this example from my memory library, and I reckon it'll be quite a bit faster than the code you're using right now, assuming you're attempting to retrieve value types only.

Upvotes: 2

Related Questions