Reputation: 2889
In order to maximize performance of a critical method, in another question it was suggested that I allocate and use the memory of the array natively instead of fixing it.
I'm working in C# and have no experience with unsafe code and using P/invoke. I haven't found any relevant examples on Google and the MSDN article about VirtualAlloc didn't help either.
This is a method which is called Billion of times and every bit of performance is desirable.
public static readonly int[] HR = new int[32487834];
public unsafe int eval(int c1, int c2, int c3, int c4, int c5, int c6, int c7)
{
fixed (int* HR = Evaluator.HR)
{
int p = HR[53 + c1];
p = HR[p + c2];
p = HR[p + c3];
p = HR[p + c4];
p = HR[p + c5];
p = HR[p + c6];
return (HR[p + c7]);
}
}
If you're interested, it's a C# port of the TwoPlusTwo-Evaluator which uses a 123mb lookup-table to return the rank of a random 7-card-pokerhand for comparison. I average about 80M evaluations/s in random order and 500M evaluations/s in consecutive order (c1=0, c2=1, loops incrementing every variable up to 52) on my machine.
Upvotes: 1
Views: 895
Reputation: 3350
The main problem with your example is that you must use the fixed
directive from outside the looping code. Using it inside this nested function won't really help and could possibly make things worse since it will make C# internally invoke its GC memory pinning API. So a much better solution would have code like this:
public unsafe int eval(int* HR, int c1, int c2, int c3, int c4, int c5, int c6, int c7)
{
int p = HR[53 + c1];
p = HR[p + c2];
p = HR[p + c3];
p = HR[p + c4];
p = HR[p + c5];
p = HR[p + c6];
return (HR[p + c7]);
}
fixed
is essentially a language construct synonym for GCHandle.AddrOfPinnedObject. In your case omitting the bounds checking on eight array fetches out-weighed the cost of pinning and unpinning the memory via the GC every time you entered that function... but probably not by much.
Using P/Invoke is generally not trivial, and I would recommend against it unless you want to spend a few days familiarizing yourself with the territory. It is even more challenging if you aren't already familiar with Win32/WinAPI programming via C++. Better to rework your code so that you can pin memory as high up the chain as possible. For this specific purpose you could even just as well create a GCHandle for that array as part of your object constructor.
Upvotes: 1
Reputation: 16981
Try to use C++/Cli:
ref class Evaluator
{
public:
static Int32* HR;
static Evaluator()
{
int size = 32487834;
HR = (INT*)malloc(size * 4);
}
static Int32 Eval(Int32 c1, Int32 c2, Int32 c3, Int32 c4, Int32 c5, Int32 c6, Int32 c7)
{
Int32 p = HR[53 + c1];
p = HR[p + c2];
p = HR[p + c3];
p = HR[p + c4];
p = HR[p + c5];
p = HR[p + c6];
return (HR[p + c7]);
}
};
Upvotes: 0