Recently I had one strange performance problem.
I need to compare time intervals in cycle with large amount of iterations.
I used DateTime.TimeOfDay property to compare these intervals. However, I found that these comparisons are very slow versus DateTime comparisons. So, I had to create DateTime’s with 1 year 1 month and 1 day to speed up time’ intervals comparison’s.
I prepared a small example to show what I mean.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DatesBenchmark
{
class Program
{
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
sw.Start();
DateTime firstDate = DateTime.Now;
DateTime secondDate = DateTime.Now.AddSeconds(5);
for (int i = 0; i < 2000000; i++)
{
var a = firstDate.TimeOfDay > secondDate.TimeOfDay;
//var a = firstDate > secondDate;
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
Console.ReadKey();
}
}
}
I got 15ms (if first row in for cycle is commented) versus 176 ms (if second row in for cycle is commented) on my laptop.
My question is short. Why?
Calling foo.TimeOfDay is doing this:
By accessing the
TimeOfDayproperty on 2DateTimeinstances over 2 million iterations you are creating 4 millionTimespaninstances. However, that’s not the biggest expense.Digging further, you have:
So you have 4 million instantiations, remainder calculations, casts, and
&operations. These are all cheap operations (“cheap” of course being a relative term) but done in quantity they add up.The actual comparison is trivial:
Compiling the OPs code in Debug mode, I see:
var a = firstDate > secondDate;6ms (suggesting it is not optimized away)var a = firstDate.TimeOfDay;40msvar a = firstDate.TimeOfDay > secondDate.TimeOfDay;80msTimeSpan a = new TimeSpan( ticks ), b = new TimeSpan( ticks );7msRunning a performance analysis in VS 2012 against the program, 81% of samples are coming from
DateTime.get_TimeOfDay().Running x64, Release mode, all optimizations enabled:
var a = firstDate > secondDate;6msvar a = firstDate.TimeOfDay;20msvar a = firstDate.TimeOfDay > secondDate.TimeOfDay;40msTimeSpan a = new TimeSpan( ticks ), b = new TimeSpan( ticks );6msSo: