ForNext, For, Delegate, Lamba Performance for x86 and x64

I have often changed fornext statements to lambda notation when prompted by code analysis tools. Every time that I did the change, I asked myself “I need to verify that this is the correct choice in terms of performance”. I assumed that it is because Microsoft had been trying to improve performance (which it did with XDocument being twice as fast as XmlDocument, which I documented in an earlier blog). I created a simple collection of different ways of walking an enumeration, with some very interesting results.

 

Compiled for x86 explicitly

Method Best Time x86 DATA  
No Op   1.95 0 0 0 0
Ienumerate: foreach/var 16.6 16.6 17.58 19.53 18.55 16.6
Ienumerate: foreach/typed 16.6 17.6 18.55 18.55 16.6 16.6
Array: for i 7.81 7.81 8.79 7.81 8.79 7.81
Array: foreach/var 7.81 7.81 8.79 7.81 7.81 7.81
Array: Array.ForEach (delegate) 6.84 7.81 7.81 6.84 8.79 7.81
Array: Array.ForEach (lamda) 6.84 7.81 11.72 6.84 7.81 7.81

 

I then compiled for x64 explicitly and had a shock…

 

Method Best Time x64 DATA  
No Op   1.95 0 0 0 0
Ienumerate: foreach/var 19.53 45.9 22.46 19.53 20.51 20.51
Ienumerate: foreach/typed 18.55 21.5 19.53 18.55 20.51 21.48
Array: for i 10.74 12.7 10.74 12.7 12.7 13.67
Array: foreach/var 9.77 11.7 9.77 10.74 11.72 14.64
Array: Array.ForEach (delegate) 8.79 9.77 8.79 8.79 8.79 11.72
Array: Array.ForEach (lamda) 7.81 9.77 7.81 8.79 9.77 9.77

x64 was not faster, but slower than x86. This is different then with C++ and suggests that the CLR 64 bit implementation has some significant short coming still.

 

So what is the bottom line:

  • if practical use arrays and not iEnumerable (collections, lists etc)
  • use Array.ForEach, lamda notation appears to match the best performance.

I confirmed my assumption that using Lambda notation was the right choice; but blew the assumption that x64 performed better than x86 out of the water. In short, compiling for x64 seems to be a political promise that is a political promise……

 

The code for folks that wish to replicate my experiment. I loaded a large Xml file to provide a big enumeration.

 

if (xmlFile.Exists)
{
    XDocument doc = XDocument.Load(xmlFile.FullName);
    IEnumerable<XElement> enumerable = doc.Descendants();
    XElement[] asList = enumerable.ToArray();
    for (int repeat = 0; repeat < 5; repeat++)
    for (int pattern = 0; pattern < 7; pattern++)
    {
        int cnt = 0;
        DateTime start = DateTime.Now;
        switch (pattern)
        {

            case 1:
                foreach (var item in enumerable)
                {
                    if (item.Name.LocalName.Length > 0)
                        cnt++;
                }
                break;
            case 2:
                foreach (XElement item in enumerable)
                {
                    if (item.Name.LocalName.Length > 0)
                        cnt++;
                }
                break;
            case 3:
                for (int i = 0; i < asList.Length; i++)
                {
                    if (asList[i].Name.LocalName.Length > 0)
                        cnt++;
                }
                break;
            case 4:
                foreach (XElement item in asList)
                {
                    if (item.Name.LocalName.Length > 0)
                        cnt++;
                }
                break;
            case 5:
                Array.ForEach(asList,
             delegate(XElement item)
             {
                 if (item.Name.LocalName.Length > 0)
                     cnt++;
             });
                break;
            case 6:
                Array.ForEach(asList, item =>
                {
                    if (item.Name.LocalName.Length > 0)
                        cnt++;
                });
                break;
            default:
                break;
        }
        DateTime end = DateTime.Now;
        TimeSpan elapse = end - start;
        Console.WriteLine(String.Format("{0} msec for {1} elements. Pattern:{2}", elapse.TotalMilliseconds, cnt, pattern));
    }
}

Comments

Popular posts from this blog

Simple WP7 Mango App for Background Tasks, Toast, and Tiles: Code Explanation

Yet once more into the breech (of altered programming logic)

How to convert SVG data to a Png Image file Using InkScape