Jump to navigation

Poupou's Corner of the Web

Looking for perfect security? Try a wireless brick.
Otherwise you may find some unperfect stuff here...


A bit of trivia

How many assemblies, let say from Mono's 2.0 profile, are using the C# lock statement (on anything) ?

Before answering let's talk about what else is going on with Gendarme ?

Ok, back to the question, why is this important ?

Simply because Gendarme has a rule, DoubleCheckLockingRule (actually this is one of the oldest rules, contributed by Aaron Tomb back in 2005), that checks them. Such rule needs to scan the IL of every method and this takes time. The newer API allows rules to short-circuit the every method (or type ...) if we can determine (or plant logic), at initialization time, that this is not worth it.

Trivia Answer:
Out of 72 (2.0) assemblies I have 42 (58%) of them don't refer to System.Threading.Monitor, which is used to implement C# lock statement. This number is not correct since mscorlib.dll does not refer, but define, the type. So 31 (2.0) assemblies (43%) actually uses lock.

Practically this answer can be translated in C# like this:

public override void Initialize (IRunner runner) { base.Initialize (runner); // is this module using Monitor.Enter ? (lock in c#) // if not then this rule does not need to be executed for the module // note: mscorlib.dll is an exception since it defines, not refer, System.Threading.Monitor Runner.AnalyzeModule += delegate (object o, RunnerEventArgs e) { Active = (e.CurrentAssembly.Name.Name == Constants.Corlib) || e.CurrentModule.TypeReferences.ContainsType ("System.Threading.Monitor"); }; }

Similar events exists for assemblies, types and methods. They can even be chained when necessary.

How much time do we gain ? The original rule executed on all 2.0 (72) assemblies took 12.225839 seconds. Adding this method reduce the execution time to 9.122709 seconds (25% less time). That's a lot considering that all 72 assemblies are still loaded by the runner (thru Cecil).

The original reason I looked back to this rule was that it called OpCode.Equals(object) which required casting and boxing while the == operator was much better suited (a little fact found by Gendarme itself). Also since this is an old rule some of the stuff, like using non-generic collections, were easy to update. Others things like avoiding, as much as possible, memory allocations were also possible.

The refresh of the rule brings down the execution time to 8.455765 seconds (30% less time than the original, but a very small gain, around 7%, wrt the previous optimization). In fact removing the Initialize from this version shows 11.34947 seconds (again 7%), less than one second under the original time.

Using Initialize is much easier, safer (unlikely to break anything) and give much better result than refactoring rules source code to be more optimal. Other rules needs to be reviewed to see if the same hack can be applied to them. It's a low hanging fruit for anyone who wants to optimize Gendarme.

4/7/2008 20:58:54 | Comments

The views expressed on this website/weblog are mine alone and do not necessarily reflect the views of my employer.