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.

Comments (8)

  1. Thomas says:

    I knew they were faster, but THAT much faster, holy crap.

    Nice article 🙂

  2. Shaun Bedingfield says:

    Big increase.. It makes me wonder if CultureComp might not need some work.

    I wonder based on a certain locale how fast it would be to use a precomputed (global) hash to translate the character into an integer corresponding to its sort position and then compare the list of integers. The smaller the integer the better as it might be possible to compare multiple characters at the same time. If you changed the order to big endian, you could do a straight integer compare. Little endian wouldn’t work though as the last character would have the highest weight.

    It would be great if you could get the performance difference down to 2 or 3 times.

  3. Shaun Bedingfield says:

    Anyone have some ideas on things to try to speed up CultureComp? I am sure mine isn’t the best and it may not even be as fast as the builtin method.

  4. Yeah, I was pretty suprised at how much faster it was. I’m not ruling out the possiblity that something was wrong with my test case, as I’m not a trained performance engineer like Rico. But nothing about my program seems fishy to me, it just might be that big a difference.

  5. Tim says:

    While your test program might not be optimal for determining the perf of the comparators, I’d totally buy the major difference that you found. Just look at the call tree of CultureComp vs. OrdinalComp.

    Hello .NET 2.0 =]

    BTW: I’m glad to see that you’re funky enough to handle the black IDE background, I’ve always been a fan. From what I can tell not many people can handle it =]

  6. Julia Jia says:

    A question about "inclusive/exclusive samples" in the Function View (grouped by module). CultureComp had 5 times number of samples to the OrdinalComp. What does this mean? How does the profile decide what to sample? Thanks!

  7. The profiler team has been crazy busy with getting Visual Studio Team System shipped and out the door,…

Skip to main content