Reputation: 4125
When I analyzed my old posts exact solution, I found a contradiction so I try to code this in Form1 constructor (after InitializeComponent();
)
Stopwatch timer = Stopwatch.StartNew();
var timeStartGetStatistic = DateTime.Now.ToString("HH:mm:ss:fff");
var timeEndGetStatistic = DateTime.Now.ToString("HH:mm:ss:fff");
timer.Stop();
Console.WriteLine("Convert take time {0}", timer.Elapsed);
Console.WriteLine("First StopWatch\nStart:\t{0}\nStop:\t{1}",
timeStartGetStatistic, timeEndGetStatistic);
Stopwatch timer2 = Stopwatch.StartNew();
var timeStartGetStatistic2 = DateTime.Now.ToString("HH:mm:ss:fff");
var timeEndGetStatistic2 = DateTime.Now.ToString("HH:mm:ss:fff");
timer2.Stop();
Console.WriteLine("Convert take time {0}", timer2.Elapsed);
Console.WriteLine("Second StopWatch\nStart:\t{0}\nStop:\t{1}",
timeStartGetStatistic2, timeEndGetStatistic2);
Convert take time 00:00:00.0102284
First StopWatch
Start: 02:42:29:929
Stop: 02:42:29:939
Convert take time 00:00:00.0000069
Second StopWatch
Start: 02:42:29:940
Stop: 02:42:29:940
I found that only FIRST DateTime.Now.ToString("HH:mm:ss:fff");
consumes 10ms but 3 others consume less than 10us in same scope, may I know the exact reason?
Is it because the FIRST one make the code on the memory so the following 3 get the advantage of it to consume more less time to do the same things? thanks.
Upvotes: 1
Views: 224
Reputation: 1700
At first, I thought it was indeed the JIT.. but it doesn't make sense because the framework itself is compiled AOT, when installed.
I think it is loading the current culture (ToString
does that, and indeed it is the function that takes time)
================ EDIT =============
I did some tests, and there are two things which take time the first time they are called.
DateTime.Now
make a call to the internal method TimeZoneInfo.GetDateTimeNowUtcOffsetFromUtc
which take about half of the consumed time...
the rest is consumed by to string..
if instead of calling DateTime.Now
you had called DateTime.UtcNow
, you wouldn't notice that first-time impact of getting the local time offset.
and about ToString
- what's consuming most of it's running time, was generating the DateTimeFormat for the current culture.
I think this answered your question pretty well :)
Upvotes: 4
Reputation: 100620
First call to any individual method from a class requires JIT so first call is always slow (unless assembly pre-JITed with NGen).
There also additional cost to load necessary resources/data depending on method associated with first call. I.e. likely DateTime.Now
and DateTime.ToString
require some locale data to be loaded/preprocessed.
Standard way to measure performance with Stopwatch is to call function/code that you want to measure once to kick all JIT related to the code and than do measurement. Usually you'd run code many times and average results.
// --- Warm up --- ignore time here unless meauring startup perf.
var timeStartGetStatistic = DateTime.Now.ToString("HH:mm:ss:fff");
var timeEndGetStatistic = DateTime.Now.ToString("HH:mm:ss:fff");
// Actual timing after JIT and all startup cost is payed.
Stopwatch timer2 = Stopwatch.StartNew();
// Consider multiple iterations i.e. to run code for about a second.
var timeStartGetStatistic2 = DateTime.Now.ToString("HH:mm:ss:fff");
var timeEndGetStatistic2 = DateTime.Now.ToString("HH:mm:ss:fff");
timer2.Stop();
Console.WriteLine("Convert take time {0}", timer2.Elapsed);
Console.WriteLine("Second StopWatch\nStart:\t{0}\nStop:\t{1}",
timeStartGetStatistic2, timeEndGetStatistic2);
Upvotes: 2
Reputation: 73502
As already noted you're measuring wrong. You should not include first call to any code as it needs to be jited, that time will be included.
Also it is not good to rely on result just ran only once; You need to run the code number of times and you should be calculating the average time taken.
Be sure that you do it in release mode without debugger attached.
Upvotes: 0