The F1 Profiler vs. .NET string comparisons
Recently I was working through some of our codebase working on converting some existing string comparison functions to use new .NET framework 2.0 comparison functionality. Common practice was to use InvarientCulture for most string comparisons. The .NET framework has added a new StringComparison enumeration that contains new comparison types Ordinal and OrdinalIgnoreCase. I’ve linked to an article that talks about situations where you should use the new Ordinal comparisons versus situations where you should use the old culture comparisons. One of the reasons listed for using the new Ordinal comparisons was performance gains, so I figured that I would run the F1 profiler (the Enterprise Performance Tool included with Visual Studio Team System 2005) on some string comparison scenarios and see what kind of performance change I could see.
To test string performance I’m using the following program (in my own funky black background of choice):
I included the different strings so that I would have greater then comparisons, less then comparisons, equal comparisons and unequal comparisons that had to run down the length of the string. Also, I added the two “warm-up” string comparisons outside of the functions that I’m actually comparing to make sure that I don’t unfairly peg any startup cost on the first function to execute.
I’m going to start out this exploration using sampling mode; sampling mode has the least overhead and I believe that it will get the best data for a small, tightly looping program like this one. Pictured below is the Function view (grouped by module) with the ConsoleApplication4.exe module opened (yeah, really original name there).
To see how much time was spent in OrdinalComp vs CultureComp just look at the inclusive percent number. Inclusive Percent will tell us the percent of samples taken that were inside that function or inside one of that function’s children. For this run about 82 percent of the time was spent in CultureComp while 15 percent of the time was spent in OrdinalComp. So at a basic level we know that using the Ordinal comparison is around five times faster then using a Culture comparison. You can see why if you need to do a large number of comparisons you should use the Ordinal comparison if at all possible. At a core level, Ordinal is just doing a strcmp, while Culture comparisons have sensitivity to culture specific string comparison issues.
If we jump over to call tree view we can see the comparison between the call trees for OrdinalComp and CultureComp (note: You can right-click on any node in the call tree to set it as the root node. I set Program.Main as the root to hide several extra layers of .NET overhead above Program.Main). I added in a red dot on the lines for OrdinalComp and CultureComp to make them easier to pick out of the mix.
In the call tree above you can see how clean the execution of OrdinalComp is compared to CultureComp, with only two functions in one single execution path. Although you may have already guessed that Ordinal would be simple (after all it is mostly a safe .NET strcmp) you might be surprised at how much is going on in CultureComp.
Anyways, these were my quick and dirty results of running the F1 profiler to compare Ordinal versus Culture comparisons. The key takeaway for this lesson is that if you are using the 2.0 .NET framework you should use Ordinal comparisons as they are about five times faster then culture comparisons. Just one of the many great things we’re adding to .NET 2.0.