Friday, August 31, 2012

Run time costs of common operations in C#

Disclaimers:
1) The benchmarking methodology below should not be used for very small things like i++. For measuring small things see this.
2) Since writing the below I've modified measure it  for integration with linqpad - use that instead.
3) If you still want to read this, be my guest :)


Today we debated if Enum.ToString() is too slow to be used. To my surprise it takes 1-5 micro seconds on my core-i7 laptop. If 5 micro seconds is too slow for you, the internet has you covered.

Naturally, I was curious about  cost of other operations so I measured those as well. You can reproduce and extend  my experiment by putting the below code into linqpad. The output from the current code on my laptop is:

Milliseconds to perform 100000 iterations
Enum.ToString() took 411 ms
NewGuid() took 31 ms
InterlockedIncrement() took 3 ms
Lock() took 3 ms
i++ took 2 ms


static TimeSpan TimeIt(int iterations, string title, Action action)
{
    var watch = Stopwatch.StartNew();
    for (int i = 0; i < iterations; i++) 
    {
        action();
    }
    return watch.Elapsed;
}

struct timeable
{
    public string title;
    public Action code;
}

internal enum AnEnum
{
    Fast,
    Slow
}

void Main()
{
    int interlocked=0;
    object lockable = new Object();
    var timeables  = new timeable []
    {
        new timeable {title="Enum.ToString()", code = ()=>AnEnum.Fast.ToString()},
        new timeable {title="NewGuid()", code = ()=>Guid.NewGuid()},
        new timeable {title="Lock()", code = ()=>Monitor.Enter(lockable)},
        new timeable {title="InterlockedIncrement()", code = ()=>Interlocked.Add(ref interlocked,interlocked)},
        new timeable {title="i++", code = ()=>interlocked++},
    };

    int iterations=100*1000;
    Console.WriteLine("Milliseconds to perform {0} iterations", iterations);
    var timings = timeables.Select(x=>new {x.title, elapsed = TimeIt(iterations,x.title,x.code)}).OrderByDescending(x=>x.elapsed).ToList();
    timings.ForEach(t=>Console.WriteLine("{0} took {1} ms",t.title,t.elapsed.TotalMilliseconds));
}

No comments: