While rereading a blog entry about Mono Security Manager, I realised that I had never thought about the speed implications related to securit when calling into native code. Yes, I was disappointed by the time it took for the CLR to do a simple platform invoke round-trip (calling from the managed world into a native DLL and then returning back to managed), but I (incorrectly) presumed that this slowness was only caused by the function argument conversions. As I have just discovered, security also plays an important role here.
When calling into native code through a function declared with the [DllImport] attribute, the CLR security manager checks to see if the caller has the right to execute UnmanagedCode by doing a stack walk. If this is done lots of times, then the overhead of the security check gets noticeable.
To remove the redundant checks, I have now decorated the assembly which manages graphics operations through native code (AGG) with the SecurityPermission attribute. This marks the whole assembly as being a potential user of unmanaged code. When the JIT sees calls into this assembly, it won't generate a stack walk to ensure the callers have the UnmanagedCode right at every call. The JIT will do the check only once.
Here is the line I added to the AssemblyInfo.cs file:
I have not seen any significant speed increase, however. Calling into a no-op function using P/Invoke takes about 1100 CPU cycles without the above attribute and 1000 with it. The speedup is almost lost in the measurement noise.
Painting 100 glyphs in one P/invoke call takes about 2,750,000 cycles. So if I painted glyphs one after the other, I'd pay about 3% of the time for the P/Invoke overhead, with or without security walk.