Environment.TickCount VS StopWatch [duplicate] - c#

Is it ever OK to use Environment.TickCountto calculate time spans?
int start = Environment.TickCount;
// Do stuff
int duration = Environment.TickCount - start;
Console.WriteLine("That took " + duration " ms");
Because TickCount is signed and will rollover after 25 days (it takes 50 days to hit all 32 bits, but you have to scrap the signed bit if you want to make any sense of the math), it seems like it's too risky to be useful.
I'm using DateTime.Now instead. Is this the best way to do this?
DateTime start = DateTime.Now;
// Do stuff
TimeSpan duration = DateTime.Now - start;
Console.WriteLine("That took " + duration.TotalMilliseconds + " ms");

Environment.TickCount is based on GetTickCount() WinAPI function. It's in milliseconds
But the actual precision of it is about 15.6 ms. So you can't measure shorter time intervals (or you'll get 0)
Note: The returned value is Int32, so this counter rolls over each ~49.7 days. You shouldn't use it to measure such long intervals.
DateTime.Ticks is based on GetSystemTimeAsFileTime() WinAPI function. It's in 100s nanoseconds (tenths of microsoconds).
The actual precision of DateTime.Ticks depends on the system. On XP, the increment of system clock is about 15.6 ms, the same as in Environment.TickCount.
On Windows 7 its precision is 1 ms (while Environemnt.TickCount's is still 15.6 ms), however if a power saving scheme is used (usually on laptops) it can go down to 15.6 ms as well.
Stopwatch is based on QueryPerformanceCounter() WinAPI function (but if high-resolution performance counter is not supported by your system, DateTime.Ticks is used)
Before using StopWatch notice two problems:
it can be unreliable on multiprocessor systems (see MS kb895980, kb896256)
it can be unreliable if CPU frequency varies (read this article)
You can evaluate the precision on your system with simple test:
static void Main(string[] args)
{
int xcnt = 0;
long xdelta, xstart;
xstart = DateTime.UtcNow.Ticks;
do {
xdelta = DateTime.UtcNow.Ticks - xstart;
xcnt++;
} while (xdelta == 0);
Console.WriteLine("DateTime:\t{0} ms, in {1} cycles", xdelta / (10000.0), xcnt);
int ycnt = 0, ystart;
long ydelta;
ystart = Environment.TickCount;
do {
ydelta = Environment.TickCount - ystart;
ycnt++;
} while (ydelta == 0);
Console.WriteLine("Environment:\t{0} ms, in {1} cycles ", ydelta, ycnt);
Stopwatch sw = new Stopwatch();
int zcnt = 0;
long zstart, zdelta;
sw.Start();
zstart = sw.ElapsedTicks; // This minimizes the difference (opposed to just using 0)
do {
zdelta = sw.ElapsedTicks - zstart;
zcnt++;
} while (zdelta == 0);
sw.Stop();
Console.WriteLine("StopWatch:\t{0} ms, in {1} cycles", (zdelta * 1000.0) / Stopwatch.Frequency, zcnt);
Console.ReadKey();
}

Use Stopwatch class. There is a decent example on msdn: http://msdn.microsoft.com/en-us/library/system.diagnostics.stopwatch.aspx
Stopwatch stopWatch = Stopwatch.StartNew();
Thread.Sleep(10000);
stopWatch.Stop();
// Get the elapsed time as a TimeSpan value.
TimeSpan ts = stopWatch.Elapsed;

Why are you worried about rollover? As long as the duration you are measuring is under 24.9 days and you calculate the relative duration, you're fine. It doesn't matter how long the system has been running, as long as you only concern yourself with your portion of that running time (as opposed to directly performing less-than or greater-than comparisons on the begin and end points). I.e. this:
int before_rollover = Int32.MaxValue - 5;
int after_rollover = Int32.MinValue + 7;
int duration = after_rollover - before_rollover;
Console.WriteLine("before_rollover: " + before_rollover.ToString());
Console.WriteLine("after_rollover: " + after_rollover.ToString());
Console.WriteLine("duration: " + duration.ToString());
correctly prints:
before_rollover: 2147483642
after_rollover: -2147483641
duration: 13
You don't have to worry about the sign bit. C#, like C, lets the CPU handle this.
This is a common situation I've run into before with time counts in embedded systems. I would never compare beforerollover < afterrollover directly, for instance. I would always perform the subtraction to find the duration that takes rollover into account, and then base any other calculations on the duration.

Environment.TickCount seems to be much faster then the other solutions:
Environment.TickCount 71
DateTime.UtcNow.Ticks 213
sw.ElapsedMilliseconds 1273
The measurements were generated by the following code:
static void Main( string[] args ) {
const int max = 10000000;
//
//
for ( int j = 0; j < 3; j++ ) {
var sw = new Stopwatch();
sw.Start();
for ( int i = 0; i < max; i++ ) {
var a = Environment.TickCount;
}
sw.Stop();
Console.WriteLine( $"Environment.TickCount {sw.ElapsedMilliseconds}" );
//
//
sw = new Stopwatch();
sw.Start();
for ( int i = 0; i < max; i++ ) {
var a = DateTime.UtcNow.Ticks;
}
sw.Stop();
Console.WriteLine( $"DateTime.UtcNow.Ticks {sw.ElapsedMilliseconds}" );
//
//
sw = new Stopwatch();
sw.Start();
for ( int i = 0; i < max; i++ ) {
var a = sw.ElapsedMilliseconds;
}
sw.Stop();
Console.WriteLine( $"sw.ElapsedMilliseconds {sw.ElapsedMilliseconds}" );
}
Console.WriteLine( "Done" );
Console.ReadKey();
}

Here is kind of an updated&refreshed summary of what may be the most useful answers & comments in this thread + extra benchmarks and variants:
First thing first: As others have pointed out in comments, things have changed the last years and with "modern" Windows (Win XP ++) and .NET, and modern hardware there are no or little reasons not to use Stopwatch().
See MSDN for details. Quotations:
"Is QPC accuracy affected by processor frequency changes caused by power management or Turbo Boost technology?
No. If the processor has an invariant TSC, the QPC is not affected by these sort of changes. If the processor doesn't have an invariant TSC, QPC will revert to a platform hardware timer that won't be affected by processor frequency changes or Turbo Boost technology.
Does QPC reliably work on multi-processor systems, multi-core system, and systems with hyper-threading?
Yes
How do I determine and validate that QPC works on my machine?
You don't need to perform such checks.
Which processors have non-invariant TSCs?
[..Read further..]
"
But if you don't need the precision of Stopwatch() or at least want to know exactly about the performance of Stopwatch (static vs. instance-based) and other possible variants, continue reading:
I took over the benchmark above from cskwg, and extended the code for more variants. I have measured with a some years old i7 4700 MQ and C# 7 with VS 2017 (to be more precise, compiled with .NET 4.5.2, despite binary literals, it is C# 6 (used of this: string literals and 'using static'). Especially the Stopwatch() performance seems to be improved compared to the mentioned benchmark.
This is an example of results of 10 million repetitions in a loop, as always, absolute values are not important, but even the relative values may differ on other hardware:
32 bit, Release mode without optimization:
Measured: GetTickCount64() [ms]: 275
Measured: Environment.TickCount [ms]: 45
Measured: DateTime.UtcNow.Ticks [ms]: 167
Measured: Stopwatch: .ElapsedTicks [ms]: 277
Measured: Stopwatch: .ElapsedMilliseconds [ms]: 548
Measured: static Stopwatch.GetTimestamp [ms]: 193
Measured: Stopwatch+conversion to DateTime [ms]: 551
Compare that with DateTime.Now.Ticks [ms]: 9010
32 bit, Release mode, optimized:
Measured: GetTickCount64() [ms]: 198
Measured: Environment.TickCount [ms]: 39
Measured: DateTime.UtcNow.Ticks [ms]: 66 (!)
Measured: Stopwatch: .ElapsedTicks [ms]: 175
Measured: Stopwatch: .ElapsedMilliseconds [ms]: 491
Measured: static Stopwatch.GetTimestamp [ms]: 175
Measured: Stopwatch+conversion to DateTime [ms]: 510
Compare that with DateTime.Now.Ticks [ms]: 8460
64 bit, Release mode without optimization:
Measured: GetTickCount64() [ms]: 205
Measured: Environment.TickCount [ms]: 39
Measured: DateTime.UtcNow.Ticks [ms]: 127
Measured: Stopwatch: .ElapsedTicks [ms]: 209
Measured: Stopwatch: .ElapsedMilliseconds [ms]: 285
Measured: static Stopwatch.GetTimestamp [ms]: 187
Measured: Stopwatch+conversion to DateTime [ms]: 319
Compare that with DateTime.Now.Ticks [ms]: 3040
64 bit, Release mode, optimized:
Measured: GetTickCount64() [ms]: 148
Measured: Environment.TickCount [ms]: 31 (is it still worth it?)
Measured: DateTime.UtcNow.Ticks [ms]: 76 (!)
Measured: Stopwatch: .ElapsedTicks [ms]: 178
Measured: Stopwatch: .ElapsedMilliseconds [ms]: 226
Measured: static Stopwatch.GetTimestamp [ms]: 175
Measured: Stopwatch+conversion to DateTime [ms]: 246
Compare that with DateTime.Now.Ticks [ms]: 3020
It may be very interesting, that creating a DateTime value to print out the Stopwatch time seems to have nearly no costs. Interesting in a more academic than practical way is that static Stopwatch is slightly faster (as expected). Some optimization points are quite interesting.
For example, I cannot explain why Stopwatch.ElapsedMilliseconds only with 32 bit is so slow compared to it's other variants, for example the static one. This and DateTime.Now more than double their speed with 64 bit.
You can see: Only for millions of executions, the time of Stopwatch begins to matter. If this is really the case (but beware micro-optimizing too early), it may be interesting that with GetTickCount64(), but especially with DateTime.UtcNow, you have a 64 bit (long) timer with less precision than Stopwatch, but faster, so that you don't have to mess around with the 32 bit "ugly" Environment.TickCount.
As expected, DateTime.Now is by far the slowest of all.
If you run it, the code retrieves also your current Stopwatch accuracy and more.
Here is the full benchmark code:
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using static System.Environment;
[...]
[DllImport("kernel32.dll") ]
public static extern UInt64 GetTickCount64(); // Retrieves a 64bit value containing ticks since system start
static void Main(string[] args)
{
const int max = 10_000_000;
const int n = 3;
Stopwatch sw;
// Following Process&Thread lines according to tips by Thomas Maierhofer: https://codeproject.com/KB/testing/stopwatch-measure-precise.aspx
// But this somewhat contradicts to assertions by MS in: https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396#Does_QPC_reliably_work_on_multi-processor_systems__multi-core_system__and_________systems_with_hyper-threading
Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(1); // Use only the first core
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
Thread.CurrentThread.Priority = ThreadPriority.Highest;
Thread.Sleep(2); // warmup
Console.WriteLine($"Repeating measurement {n} times in loop of {max:N0}:{NewLine}");
for (int j = 0; j < n; j++)
{
sw = new Stopwatch();
sw.Start();
for (int i = 0; i < max; i++)
{
var tickCount = GetTickCount64();
}
sw.Stop();
Console.WriteLine($"Measured: GetTickCount64() [ms]: {sw.ElapsedMilliseconds}");
//
//
sw = new Stopwatch();
sw.Start();
for (int i = 0; i < max; i++)
{
var tickCount = Environment.TickCount; // only int capacity, enough for a bit more than 24 days
}
sw.Stop();
Console.WriteLine($"Measured: Environment.TickCount [ms]: {sw.ElapsedMilliseconds}");
//
//
sw = new Stopwatch();
sw.Start();
for (int i = 0; i < max; i++)
{
var a = DateTime.UtcNow.Ticks;
}
sw.Stop();
Console.WriteLine($"Measured: DateTime.UtcNow.Ticks [ms]: {sw.ElapsedMilliseconds}");
//
//
sw = new Stopwatch();
sw.Start();
for (int i = 0; i < max; i++)
{
var a = sw.ElapsedMilliseconds;
}
sw.Stop();
Console.WriteLine($"Measured: Stopwatch: .ElapsedMilliseconds [ms]: {sw.ElapsedMilliseconds}");
//
//
sw = new Stopwatch();
sw.Start();
for (int i = 0; i < max; i++)
{
var a = Stopwatch.GetTimestamp();
}
sw.Stop();
Console.WriteLine($"Measured: static Stopwatch.GetTimestamp [ms]: {sw.ElapsedMilliseconds}");
//
//
DateTime dt=DateTime.MinValue; // just init
sw = new Stopwatch();
sw.Start();
for (int i = 0; i < max; i++)
{
var a = new DateTime(sw.Elapsed.Ticks); // using variable dt here seems to make nearly no difference
}
sw.Stop();
//Console.WriteLine($"Measured: Stopwatch+conversion to DateTime [s] with millisecs: {dt:s.fff}");
Console.WriteLine($"Measured: Stopwatch+conversion to DateTime [ms]: {sw.ElapsedMilliseconds}");
Console.WriteLine();
}
//
//
sw = new Stopwatch();
var tickCounterStart = Environment.TickCount;
sw.Start();
for (int i = 0; i < max/10; i++)
{
var a = DateTime.Now.Ticks;
}
sw.Stop();
var tickCounter = Environment.TickCount - tickCounterStart;
Console.WriteLine($"Compare that with DateTime.Now.Ticks [ms]: {sw.ElapsedMilliseconds*10}");
Console.WriteLine($"{NewLine}General Stopwatch information:");
if (Stopwatch.IsHighResolution)
Console.WriteLine("- Using high-resolution performance counter for Stopwatch class.");
else
Console.WriteLine("- Using high-resolution performance counter for Stopwatch class.");
double freq = (double)Stopwatch.Frequency;
double ticksPerMicroSec = freq / (1000d*1000d) ; // microsecond resolution: 1 million ticks per sec
Console.WriteLine($"- Stopwatch accuracy- ticks per microsecond (1000 ms): {ticksPerMicroSec:N1}");
Console.WriteLine(" (Max. tick resolution normally is 100 nanoseconds, this is 10 ticks/microsecond.)");
DateTime maxTimeForTickCountInteger= new DateTime(Int32.MaxValue*10_000L); // tickCount means millisec -> there are 10.000 milliseconds in 100 nanoseconds, which is the tick resolution in .NET, e.g. used for TimeSpan
Console.WriteLine($"- Approximated capacity (maxtime) of TickCount [dd:hh:mm:ss] {maxTimeForTickCountInteger:dd:HH:mm:ss}");
// this conversion from seems not really accurate, it will be between 24-25 days.
Console.WriteLine($"{NewLine}Done.");
while (Console.KeyAvailable)
Console.ReadKey(false);
Console.ReadKey();
}

You probably want System.Diagnostics.StopWatch.

If you're looking for the functionality of Environment.TickCount but without the overhead of creating new Stopwatch objects, you can use the static Stopwatch.GetTimestamp() method (along with Stopwatch.Frequency) to calculate long time spans. Because GetTimestamp() returns a long, it won't overflow for a very, very long time (over 100,000 years, on the machine I'm using to write this). It's also much more accurate than Environment.TickCount which has a maximum resolution of 10 to 16 milliseconds.

Use
System.Diagnostics.Stopwatch
It has a property called
EllapsedMilliseconds

TickCount64
Doing some quick measurements on this new function, I found (optimized, release 64-bit, 1000mio loops):
Environment.TickCount: 2265
Environment.TickCount64: 2531
DateTime.UtcNow.Ticks: 69016
The measurements for not-optimized code were similar.
Test code:
static void Main( string[] args ) {
long start, end, length = 1000 * 1000 * 1000;
start = Environment.TickCount64;
for ( int i = 0; i < length; i++ ) {
var a = Environment.TickCount;
}
end = Environment.TickCount64;
Console.WriteLine( "Environment.TickCount: {0}", end - start );
start = Environment.TickCount64;
for ( int i = 0; i < length; i++ ) {
var a = Environment.TickCount64;
}
end = Environment.TickCount64;
Console.WriteLine( "Environment.TickCount64: {0}", end - start );
start = Environment.TickCount64;
for ( int i = 0; i < length; i++ ) {
var a = DateTime.UtcNow.Ticks;
}
end = Environment.TickCount64;
Console.WriteLine( "DateTime.UtcNow.Ticks: {0}", end - start );
}

You should use the Stopwatch class instead.

I use Environment.TickCount because:
The Stopwatch class is not in the Compact Framework.
Stopwatch uses the same underlying timing mechanism as TickCount, so the results won't be any more or less accurate.
The wrap-around problem with TickCount is cosmically unlikely to be hit (you'd have to leave your computer running for 27 days and then try to measure a time that just happens to span the wrap-around moment), and even if you did hit it the result would be a huge negative time span (so it would kind of stand out).
That being said, I would also recommend using Stopwatch, if it's available to you. Or you could take about 1 minute and write a Stopwatch-like class that wraps Environment.TickCount.
BTW, I see nothing in the Stopwatch documentation that mentions the wrap-around problem with the underlying timer mechanism, so I wouldn't be surprised at all to find that Stopwatch suffers from the same problem. But again, I wouldn't spend any time worrying about it.

I was going to say wrap it into a stopwatch class, but Grzenio already said the right thing, so I will give him an uptick. Such encapsulation factors out the decision as to which way is better, and this can change in time. I remember being shocked at how expensive it can be getting the time on some systems, so having one place that can implement the best technique can be very important.

For one-shot timing, it's even simpler to write
Stopwatch stopWatch = Stopwatch.StartNew();
...dostuff...
Debug.WriteLine(String.Format("It took {0} milliseconds",
stopWatch.EllapsedMilliseconds)));
I'd guess the cosmically unlikely wraparound in TickCount is even less of a concern for StopWatch, given that the ElapsedTicks field is a long. On my machine, StopWatch is high resolution, at 2.4e9 ticks per second. Even at that rate, it would take over 121 years to overflow the ticks field. Of course, I don't know what's going on under the covers, so take that with a grain of salt. However, I notice that the documentation for StopWatch doesn't even mention the wraparound issue, while the doc for TickCount does.

Overflow compensation
As said before, rollover may happen after 24.9 days, or, if you use an uint cast, after 49.8 days.
Because I did not want to pInvoke GetTickCount64, I wrote this overflow compensation. The sample code is using 'byte' to keep the numbers handy. Please have a look at it, it still might contain errors:
using System;
namespace ConsoleApp1 {
class Program {
//
static byte Lower = byte.MaxValue / 3;
static byte Upper = 2 * byte.MaxValue / 3;
//
///<summary>Compute delta between two TickCount values reliably, because TickCount might wrap after 49.8 days.</summary>
static short Delta( byte next, byte ticks ) {
if ( next < Lower ) {
if ( ticks > Upper ) {
return (short) ( ticks - ( byte.MaxValue + 1 + next ) );
}
}
if ( next > Upper ) {
if ( ticks < Lower ) {
return (short) ( ( ticks + byte.MaxValue + 1 ) - next );
}
}
return (short) ( ticks - next );
}
//
static void Main( string[] args ) {
// Init
Random rnd = new Random();
int max = 0;
byte last = 0;
byte wait = 3;
byte next = (byte) ( last + wait );
byte step = 0;
// Loop tick
for ( byte tick = 0; true; ) {
//
short delta = Delta( next, tick );
if ( delta >= 0 ) {
Console.WriteLine( "RUN: last: {0} next: {1} tick: {2} delta: {3}", last, next, tick, delta );
last = tick;
next = (byte) ( last + wait );
}
// Will overflow to 0 automatically
step = (byte) rnd.Next( 0, 11 );
tick += step;
max++; if ( max > 99999 ) break;
}
}
}
}

Related

Parallel.For performance

This code is from Microsoft article http://msdn.microsoft.com/en-us/library/dd460703.aspx, with small changes:
const int size = 10000000;
int[] nums = new int[size];
Parallel.For(0, size, i => {nums[i] = 1;});
long total = 0;
Parallel.For<long>(
0, size, () => 0,
(j, loop, subtotal) =>
{
return subtotal + nums[j];
},
(x) => Interlocked.Add(ref total, x)
);
if (total != size)
{
Console.WriteLine("Error");
}
Non-parallel loop version is:
for (int i = 0; i < size; ++i)
{
total += nums[i];
}
When I measure loop execution time using StopWatch class, I see that parallel version is slower by 10-20%. Testing is done on Windows 7 64 bit, Intel i5-2400 CPU, 4 cores, 4 GB RAM. Of course, in Release configuration.
In my real program I am trying to compute an image histogram, and parallel version runs 10 times slower. Can such kind of computation tasks, when every loop invocation is very fast, be successfully parallelized with TPL?
Edit.
Finally I managed to shave more that 50% of histogram calculation execution time with Parallel.For, when divided the whole image to some number of chunks. Every loop body invocation now handles the whole chunk, and not one pixel.
Because Parallel.For should be used for things that are a little heacy, not to sum simple numbers! Just the use of the delegate (j, loop, subtotal) => is probably more than enough to give 10-20% more time. And we aren't even speaking of the threading overhead. It would be interesting to see some benchmark against a delegate summer in the for cycle and to see not only the "real world" time, but the CPU time.
I have even added a comparison to a "simple" delegate that does the same thing as the Parallel.For<> delegate.
Mmmh... Now I have some numbers at 32 bits, on my PC (an AMD six core)
32 bits
Parallel: Ticks: 74581, Total ProcessTime: 2496016
Base : Ticks: 90395, Total ProcessTime: 312002
Func : Ticks: 147037, Total ProcessTime: 468003
The Parallel is a little faster at wall time, but 8x slower at processor time :-)
But at 64 bits:
64 bits
Parallel: Ticks: 104326, Total ProcessTime: 2652017
Base : Ticks: 51664, Total ProcessTime: 156001
Func : Ticks: 77861, Total ProcessTime: 312002
Modified code:
Console.WriteLine("{0} bits", IntPtr.Size == 4 ? 32 : 64);
var cp = Process.GetCurrentProcess();
cp.PriorityClass = ProcessPriorityClass.High;
const int size = 10000000;
int[] nums = new int[size];
Parallel.For(0, size, i => { nums[i] = 1; });
GC.Collect();
GC.WaitForPendingFinalizers();
long total = 0;
{
TimeSpan start = cp.TotalProcessorTime;
Stopwatch sw = Stopwatch.StartNew();
Parallel.For<long>(
0, size, () => 0,
(j, loop, subtotal) =>
{
return subtotal + nums[j];
},
(x) => Interlocked.Add(ref total, x)
);
sw.Stop();
TimeSpan end = cp.TotalProcessorTime;
Console.WriteLine("Parallel: Ticks: {0,10}, Total ProcessTime: {1,10}", sw.ElapsedTicks, (end - start).Ticks);
}
if (total != size)
{
Console.WriteLine("Error");
}
GC.Collect();
GC.WaitForPendingFinalizers();
total = 0;
{
TimeSpan start = cp.TotalProcessorTime;
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < size; ++i)
{
total += nums[i];
}
sw.Stop();
TimeSpan end = cp.TotalProcessorTime;
Console.WriteLine("Base : Ticks: {0,10}, Total ProcessTime: {1,10}", sw.ElapsedTicks, (end - start).Ticks);
}
if (total != size)
{
Console.WriteLine("Error");
}
GC.Collect();
GC.WaitForPendingFinalizers();
total = 0;
Func<int, int, long, long> adder = (j, loop, subtotal) =>
{
return subtotal + nums[j];
};
{
TimeSpan start = cp.TotalProcessorTime;
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < size; ++i)
{
total = adder(i, 0, total);
}
sw.Stop();
TimeSpan end = cp.TotalProcessorTime;
Console.WriteLine("Func : Ticks: {0,10}, Total ProcessTime: {1,10}", sw.ElapsedTicks, (end - start).Ticks);
}
if (total != size)
{
Console.WriteLine("Error");
}

Exit the loop after specific time in C#

I have a requirement in my project (C#, VS2010, .NET 4.0) that a particular for loop must finish within 200 milliseconds. If it doesn't then it has to terminate after this duration without executing the remaining iterations. The loop generally goes for i = 0 to about 500,000 to 700,000 so the total loop time varies.
I have read following questions which are similar but they didn't help in my case:
What is the best way to exit out of a loop after an elapsed time of 30ms in C++
How to execute the loop for specific time
So far I have tried using a Stopwatch object to track the elapsed time but it's not working for me. Here are 2 different methods I have tried so far:
Method 1. Comparing the elapsed time within for loop:
Stopwatch sw = new Stopwatch();
sw.Start();
for (i = 0; i < nEntries; i++) // nEntries is typically more than 500,000
{
// Do some stuff
...
...
...
if (sw.Elapsed > TimeSpan.FromMilliseconds(200))
break;
}
sw.Stop();
This doesn't work because if (sw.Elapsed > TimeSpan.FromMilliseconds(200)) takes more than 200 milliseconds to complete. Hence useless in my case. I am not sure whether TimeSpan.FromMilliseconds() generally takes this long or it's just in my case for some reason.
Method 2. Creating a separate thread to compare time:
Stopwatch sw = new Stopwatch();
sw.Start();
bool bDoExit = false;
int msLimit = 200;
System.Threading.ThreadPool.QueueUserWorkItem((x) =>
{
while (bDoExit == false)
{
if (sw.Elapsed.Milliseconds > msLimit)
{
bDoExit = true;
sw.Stop();
}
System.Threading.Thread.Sleep(10);
}
});
for (i = 0; i < nEntries; i++) // nEntries is typically more than 500,000
{
// Do some stuff
...
...
...
if (bDoExit == true)
break;
}
sw.Stop();
I have some other code in the for loop that prints some statistics. It tells me that in case of Method 2, the for loop definitely breaks before completing all the iterations but the loop timing is still 280-300 milliseconds.
Any suggestions to break a for loop strictly with-in 200 milliseconds or less?
Thanks.
For a faster comparison try comparing
if(sw.ElapsedMilliseconds > 200)
break;
You should do that check in the beggining of your loop and also during the processing, ("// Do some stuff" part of the code) because it is possible, for example, that processing starts at 190 (beginning of the loop), lasts 20 and ends at 210.
You could also measure average execution time of your processing (this is approximate because it relies on average time), this way loop should last 200 milliseconds or less, here is a demo that you can put in a Main method of a Console application and easily modify it for your application:
Stopwatch sw = new Stopwatch();
sw.Start();
string a = String.Empty;
int i;
decimal sum = 0, avg = 0, beginning = 0, end = 0;
for (i = 0; i < 700000; i++) // nEntries is typically more than 500,000
{
beginning = sw.ElapsedMilliseconds;
if (sw.ElapsedMilliseconds + avg > 200)
break;
// Some processing
a += "x";
int s = a.Length * 100;
Thread.Sleep(19);
/////////////
end = sw.ElapsedMilliseconds;
sum += end - beginning;
avg = sum / (i + 1);
}
sw.Stop();
Console.WriteLine(
"avg:{0}, count:{1}, milliseconds elapsed:{2}", avg, i + 1,
sw.ElapsedMilliseconds);
Console.ReadKey();
Another option would be to use CancellationTokenSource:
CancellationTokenSource source = new CancellationTokenSource(100);
while(!source.IsCancellationRequested)
{
// Do stuff
}
Use the first one - simple and have better chances to be precise than second one.
Both cases have the same kind of termination condition, so both should behave are more-or-less the same. Second is much more complicated due to usage of threads and Sleep, so I'd use first one. Also second one is much less precise due to sleeps.
There are abolutely no reasons for TimeSpan.FromMilliseconds(200) to take any significant amount of time (as well as calling it in every iteration).
Using cancellation token:
var cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(15)).Token;
while (!cancellationToken.IsCancellationRequested)
{
//Do stuff...
}
I don't know if this is that exactly, but I think it's worth a try using a System.Timers.Timer:
int msLimit = 200;
int nEntries = 500000;
bool cancel = false;
System.Timers.Timer t = new System.Timers.Timer();
t.Interval = msLimit;
t.Elapsed += (s, e) => cancel = true;
t.Start();
for (int i = 0; i < nEntries; i++)
{
// do sth
if (cancel) {
break;
}
}

C# Performance Penalty from Adding Stop Watch?

What is the performance penalty incurred by adding the C# Stop Watch to an object?
Should not be that significant in the context of C# programming. If it proves to be significant, reconsider your need/use of Stopwatch and C#.
You can always try to benchmark it yourself by implementing it 1000 times, timing it, and then dividing the results by 1000. It's difficult to say precisely how performance demanding this feature is, but you could compare it to some other simple operations and see how it relates to.
Since I desired to use some timing statistics in an object creation pool to optimize its performance on-the-fly, I needed to know if adding a Stopwatch to monitor the timing would adversely affect the performance of the object creation. I wanted to time a typical object creation (appr. 20-30 ms) to optimize the timeout for the Task creating them, but only if adding the Stopwatch did not noticeably slow down the loop.
So I wrote this test program to separately time the overhead of creation, Start(), Stop() and elapsed time retrieval of the Stopwatch.
using System;
using System.Diagnostics;
namespace SO9925598_Stopwatch_overhead
{
class Program
{
private const int nLoops = 10000;
private const double nLoopsDouble = nLoops;
private const int waitTime = 2; //ms
static void Main(string[] args)
{
Stopwatch stopwatchTimingTheTest = new Stopwatch();
double frequencyConversionFactor = 1000.0 / Convert.ToDouble(Stopwatch.Frequency); // ms per click
Stopwatch stopwatchUnderTest;
// Instantiation
for (int i = 0; i < nLoops; i++)
{
stopwatchTimingTheTest.Start();
stopwatchUnderTest = new Stopwatch();
stopwatchTimingTheTest.Stop();
stopwatchUnderTest = null;
}
long elapsed = stopwatchTimingTheTest.ElapsedTicks;
double overhead = frequencyConversionFactor * (Convert.ToDouble(elapsed) / nLoopsDouble);
Console.WriteLine($"Creation overhead {overhead} ms per Stopwatch instantiation. (Based on {nLoops} trials).");
// Further tests can all use the same object
stopwatchUnderTest = new Stopwatch();
// Start
stopwatchTimingTheTest.Reset();
for (int i = 0; i < nLoops; i++)
{
stopwatchTimingTheTest.Start();
stopwatchUnderTest.Start();
stopwatchTimingTheTest.Stop();
stopwatchUnderTest.Stop();
elapsed = stopwatchUnderTest.ElapsedTicks;
}
elapsed = stopwatchTimingTheTest.ElapsedTicks;
overhead = frequencyConversionFactor * (Convert.ToDouble(elapsed) / nLoopsDouble);
Console.WriteLine($"Stopwatch.Start() overhead {overhead} ms.");
// Stop
stopwatchTimingTheTest.Reset();
for (int i = 0; i < nLoops; i++)
{
stopwatchUnderTest.Start();
stopwatchTimingTheTest.Start();
stopwatchUnderTest.Stop();
stopwatchTimingTheTest.Stop();
elapsed = stopwatchUnderTest.ElapsedTicks;
}
elapsed = stopwatchTimingTheTest.ElapsedTicks;
overhead = frequencyConversionFactor * (Convert.ToDouble(elapsed) / nLoopsDouble);
Console.WriteLine($"Stopwatch.Stop() overhead {overhead} ms.");
// Elapsed ticks
stopwatchTimingTheTest.Reset();
for (int i = 0; i < nLoops; i++)
{
stopwatchUnderTest.Start();
stopwatchUnderTest.Stop();
stopwatchTimingTheTest.Start();
elapsed = stopwatchUnderTest.ElapsedTicks;
stopwatchTimingTheTest.Stop();
}
elapsed = stopwatchTimingTheTest.ElapsedTicks;
overhead = frequencyConversionFactor * (Convert.ToDouble(elapsed) / nLoopsDouble);
Console.WriteLine($"Stopwatch.ElapsedTicks overhead {overhead} ms.");
// Elapsed ticks
stopwatchTimingTheTest.Reset();
for (int i = 0; i < nLoops; i++)
{
stopwatchUnderTest.Start();
stopwatchUnderTest.Stop();
stopwatchTimingTheTest.Start();
elapsed = stopwatchUnderTest.ElapsedMilliseconds;
stopwatchTimingTheTest.Stop();
}
elapsed = stopwatchTimingTheTest.ElapsedTicks;
overhead = frequencyConversionFactor * (Convert.ToDouble(elapsed) / nLoopsDouble);
Console.WriteLine($"Stopwatch.ElapsedMilliseconds overhead {overhead} ms.");
Console.WriteLine("Press any key to continue...");
Console.ReadKey();
}
}
}
These were the results:
Creation overhead 0,00011756 ms per Stopwatch instantiation. (Based on 10000 trials).
Stopwatch.Start() overhead 0,000256 ms.
Stopwatch.Stop() overhead 0,00023665 ms.
Stopwatch.ElapsedTicks overhead 0,00010946 ms.
Stopwatch.ElapsedMilliseconds overhead 0,00011758 ms.
The times are the average time per single call of the method based on 10000 samples.
The program was running on a machine with Intel Core i7-8850H CPU at 2.60 GHz with Windows 10 operating system.
Conclusion: for my application where the object creation is 20-30 ms the overhead of the Stopwatch is negligible.
static void Main(string[] args)
{
Worker(1); // jit Warmup
var stopWatchOfStopwatchStopwatch = System.Diagnostics.Stopwatch.StartNew();
var stopWatchOfLoop = System.Diagnostics.Stopwatch.StartNew();
Worker(100000000);
stopWatchOfLoop.Stop();
Console.WriteLine("Elapsed of inner SW: " + stopWatchOfLoop.Elapsed.ToString());
stopWatchOfStopwatchStopwatch.Stop();
Console.WriteLine("Elapsed of outer SW: " + stopWatchOfStopwatchStopwatch.Elapsed.ToString());
var stopwatchOfcompareLoop = System.Diagnostics.Stopwatch.StartNew();
Worker(100000000);
stopwatchOfcompareLoop.Stop();
Console.WriteLine("Elapsed of inner SW: " + stopWatchOfLoop.Elapsed.ToString());
}
static void Worker(int iterations)
{
for (int i = 0; i < iterations; i++)
{
Console.WriteLine("bla");
}
}
The difference is insignificant - but that pretty much depends on your performance goals :)

How do you convert Stopwatch ticks to nanoseconds, milliseconds and seconds?

This is a very basic question...quite embarassing, but here goes:
I have a Stopwatch block in C# code. I determine the elapsed time in ticks and then want to convert to ns, ms, s. I know that the Frequency is provided by the Stopwatch class and that it is required for conversion.
Thanks
Stopwatch.Elapsed is a TimeSpan, so you can do myStopwatch.Elapsed.TotalMilliseconds, myStopwatch.Elapsed.TotalSeconds, etc.
// Create new stopwatch
Stopwatch stopwatch = new Stopwatch();
// Begin timing
stopwatch.Start();
// Do something
for (int i = 0; i < 1000; i++)
{
Thread.Sleep(1);
}
// Stop timing
stopwatch.Stop();
// Write result
Console.WriteLine("Time elapsed (s): {0}", stopwatch.Elapsed.TotalSeconds);
Console.WriteLine("Time elapsed (ms): {0}", stopwatch.Elapsed.TotalMilliseconds);
Console.WriteLine("Time elapsed (ns): {0}", stopwatch.Elapsed.TotalMilliseconds * 1000000);
Output:
Time elapsed (s): 2.4976622
Time elapsed (ms): 2497.6622
Time elapsed (ns): 2497662200
Note that stopwatch.ElapsedMilliseconds returns a long and is thus only precise up to the millisecond, while stopwatch.Elapsed.TotalMilliseconds returns a double and has the same precision as stopwatch.ElapsedTicks, except it's easier to use. ILSpy shows that TimeSpan.TotalMilliseconds is computed using ticks anyway.
According to MSDN, Frequency tells you the number of ticks per second. Therefore:
Stopwatch sw = new Stopwatch();
// ...
double ticks = sw.ElapsedTicks;
double seconds = ticks / Stopwatch.Frequency;
double milliseconds = (ticks / Stopwatch.Frequency) * 1000;
double nanoseconds = (ticks / Stopwatch.Frequency) * 1000000000;
Stopwatch.Frequency gives you ticks/second.
So, if you have ticks, you can just divide by frequency to get seconds:
long ticks = sw.ElapsedTicks;
double ns = 1000000000.0 * (double)ticks / Stopwatch.Frequency;
double ms = ns / 1000000.0;
double s = ms / 1000;
For example, you can do:
static void Main()
{
Stopwatch sw = new Stopwatch();
sw.Start();
System.Threading.Thread.Sleep(3456);
sw.Stop();
long ticks = sw.ElapsedTicks;
double ns = 1000000000.0 * (double)ticks / Stopwatch.Frequency;
double ms = ns / 1000000.0;
double s = ms / 1000;
Console.WriteLine("{0}, {1}, {2}", ns, ms, s);
Console.ReadKey();
}
Which, on my system, prints:
3455650175.58075, 3455.65017558075, 3.45565017558075
Use this class:
public static class Utility
{
public static long ElapsedNanoSeconds(this Stopwatch watch)
{
return watch.ElapsedTicks * 1000000000 / Stopwatch.Frequency;
}
public static long ElapsedMicroSeconds(this Stopwatch watch)
{
return watch.ElapsedTicks * 1000000 / Stopwatch.Frequency;
}
}
Then you can get the elapsed nanoseconds/microseconds just like this:
var stopwatch = Stopwatch.StartNew();
//... measured code part
Console.WriteLine(stopwatch.ElapsedNanoSeconds());
// OR
Console.WriteLine(stopwatch.ElapsedMicroSeconds());
For milliseconds you can use the ElapsedMilliseconds() method of Stopwatch.
From the MSDN docs:
Use the Frequency and IsHighResolution fields to determine the precision and resolution of the Stopwatch timing implementation.
long frequency = Stopwatch.Frequency;
Console.WriteLine(" Timer frequency in ticks per second = {0}",
frequency);
long nanosecPerTick = (1000L*1000L*1000L) / frequency;
Console.WriteLine(" Timer is accurate within {0} nanoseconds",
nanosecPerTick);
Use the Elapsed property:
stopwatch.Elapsed.TotalMilliseconds

Environment.TickCount vs DateTime.Now

Is it ever OK to use Environment.TickCountto calculate time spans?
int start = Environment.TickCount;
// Do stuff
int duration = Environment.TickCount - start;
Console.WriteLine("That took " + duration " ms");
Because TickCount is signed and will rollover after 25 days (it takes 50 days to hit all 32 bits, but you have to scrap the signed bit if you want to make any sense of the math), it seems like it's too risky to be useful.
I'm using DateTime.Now instead. Is this the best way to do this?
DateTime start = DateTime.Now;
// Do stuff
TimeSpan duration = DateTime.Now - start;
Console.WriteLine("That took " + duration.TotalMilliseconds + " ms");
Environment.TickCount is based on GetTickCount() WinAPI function. It's in milliseconds
But the actual precision of it is about 15.6 ms. So you can't measure shorter time intervals (or you'll get 0)
Note: The returned value is Int32, so this counter rolls over each ~49.7 days. You shouldn't use it to measure such long intervals.
DateTime.Ticks is based on GetSystemTimeAsFileTime() WinAPI function. It's in 100s nanoseconds (tenths of microsoconds).
The actual precision of DateTime.Ticks depends on the system. On XP, the increment of system clock is about 15.6 ms, the same as in Environment.TickCount.
On Windows 7 its precision is 1 ms (while Environemnt.TickCount's is still 15.6 ms), however if a power saving scheme is used (usually on laptops) it can go down to 15.6 ms as well.
Stopwatch is based on QueryPerformanceCounter() WinAPI function (but if high-resolution performance counter is not supported by your system, DateTime.Ticks is used)
Before using StopWatch notice two problems:
it can be unreliable on multiprocessor systems (see MS kb895980, kb896256)
it can be unreliable if CPU frequency varies (read this article)
You can evaluate the precision on your system with simple test:
static void Main(string[] args)
{
int xcnt = 0;
long xdelta, xstart;
xstart = DateTime.UtcNow.Ticks;
do {
xdelta = DateTime.UtcNow.Ticks - xstart;
xcnt++;
} while (xdelta == 0);
Console.WriteLine("DateTime:\t{0} ms, in {1} cycles", xdelta / (10000.0), xcnt);
int ycnt = 0, ystart;
long ydelta;
ystart = Environment.TickCount;
do {
ydelta = Environment.TickCount - ystart;
ycnt++;
} while (ydelta == 0);
Console.WriteLine("Environment:\t{0} ms, in {1} cycles ", ydelta, ycnt);
Stopwatch sw = new Stopwatch();
int zcnt = 0;
long zstart, zdelta;
sw.Start();
zstart = sw.ElapsedTicks; // This minimizes the difference (opposed to just using 0)
do {
zdelta = sw.ElapsedTicks - zstart;
zcnt++;
} while (zdelta == 0);
sw.Stop();
Console.WriteLine("StopWatch:\t{0} ms, in {1} cycles", (zdelta * 1000.0) / Stopwatch.Frequency, zcnt);
Console.ReadKey();
}
Use Stopwatch class. There is a decent example on msdn: http://msdn.microsoft.com/en-us/library/system.diagnostics.stopwatch.aspx
Stopwatch stopWatch = Stopwatch.StartNew();
Thread.Sleep(10000);
stopWatch.Stop();
// Get the elapsed time as a TimeSpan value.
TimeSpan ts = stopWatch.Elapsed;
Why are you worried about rollover? As long as the duration you are measuring is under 24.9 days and you calculate the relative duration, you're fine. It doesn't matter how long the system has been running, as long as you only concern yourself with your portion of that running time (as opposed to directly performing less-than or greater-than comparisons on the begin and end points). I.e. this:
int before_rollover = Int32.MaxValue - 5;
int after_rollover = Int32.MinValue + 7;
int duration = after_rollover - before_rollover;
Console.WriteLine("before_rollover: " + before_rollover.ToString());
Console.WriteLine("after_rollover: " + after_rollover.ToString());
Console.WriteLine("duration: " + duration.ToString());
correctly prints:
before_rollover: 2147483642
after_rollover: -2147483641
duration: 13
You don't have to worry about the sign bit. C#, like C, lets the CPU handle this.
This is a common situation I've run into before with time counts in embedded systems. I would never compare beforerollover < afterrollover directly, for instance. I would always perform the subtraction to find the duration that takes rollover into account, and then base any other calculations on the duration.
Environment.TickCount seems to be much faster then the other solutions:
Environment.TickCount 71
DateTime.UtcNow.Ticks 213
sw.ElapsedMilliseconds 1273
The measurements were generated by the following code:
static void Main( string[] args ) {
const int max = 10000000;
//
//
for ( int j = 0; j < 3; j++ ) {
var sw = new Stopwatch();
sw.Start();
for ( int i = 0; i < max; i++ ) {
var a = Environment.TickCount;
}
sw.Stop();
Console.WriteLine( $"Environment.TickCount {sw.ElapsedMilliseconds}" );
//
//
sw = new Stopwatch();
sw.Start();
for ( int i = 0; i < max; i++ ) {
var a = DateTime.UtcNow.Ticks;
}
sw.Stop();
Console.WriteLine( $"DateTime.UtcNow.Ticks {sw.ElapsedMilliseconds}" );
//
//
sw = new Stopwatch();
sw.Start();
for ( int i = 0; i < max; i++ ) {
var a = sw.ElapsedMilliseconds;
}
sw.Stop();
Console.WriteLine( $"sw.ElapsedMilliseconds {sw.ElapsedMilliseconds}" );
}
Console.WriteLine( "Done" );
Console.ReadKey();
}
Here is kind of an updated&refreshed summary of what may be the most useful answers & comments in this thread + extra benchmarks and variants:
First thing first: As others have pointed out in comments, things have changed the last years and with "modern" Windows (Win XP ++) and .NET, and modern hardware there are no or little reasons not to use Stopwatch().
See MSDN for details. Quotations:
"Is QPC accuracy affected by processor frequency changes caused by power management or Turbo Boost technology?
No. If the processor has an invariant TSC, the QPC is not affected by these sort of changes. If the processor doesn't have an invariant TSC, QPC will revert to a platform hardware timer that won't be affected by processor frequency changes or Turbo Boost technology.
Does QPC reliably work on multi-processor systems, multi-core system, and systems with hyper-threading?
Yes
How do I determine and validate that QPC works on my machine?
You don't need to perform such checks.
Which processors have non-invariant TSCs?
[..Read further..]
"
But if you don't need the precision of Stopwatch() or at least want to know exactly about the performance of Stopwatch (static vs. instance-based) and other possible variants, continue reading:
I took over the benchmark above from cskwg, and extended the code for more variants. I have measured with a some years old i7 4700 MQ and C# 7 with VS 2017 (to be more precise, compiled with .NET 4.5.2, despite binary literals, it is C# 6 (used of this: string literals and 'using static'). Especially the Stopwatch() performance seems to be improved compared to the mentioned benchmark.
This is an example of results of 10 million repetitions in a loop, as always, absolute values are not important, but even the relative values may differ on other hardware:
32 bit, Release mode without optimization:
Measured: GetTickCount64() [ms]: 275
Measured: Environment.TickCount [ms]: 45
Measured: DateTime.UtcNow.Ticks [ms]: 167
Measured: Stopwatch: .ElapsedTicks [ms]: 277
Measured: Stopwatch: .ElapsedMilliseconds [ms]: 548
Measured: static Stopwatch.GetTimestamp [ms]: 193
Measured: Stopwatch+conversion to DateTime [ms]: 551
Compare that with DateTime.Now.Ticks [ms]: 9010
32 bit, Release mode, optimized:
Measured: GetTickCount64() [ms]: 198
Measured: Environment.TickCount [ms]: 39
Measured: DateTime.UtcNow.Ticks [ms]: 66 (!)
Measured: Stopwatch: .ElapsedTicks [ms]: 175
Measured: Stopwatch: .ElapsedMilliseconds [ms]: 491
Measured: static Stopwatch.GetTimestamp [ms]: 175
Measured: Stopwatch+conversion to DateTime [ms]: 510
Compare that with DateTime.Now.Ticks [ms]: 8460
64 bit, Release mode without optimization:
Measured: GetTickCount64() [ms]: 205
Measured: Environment.TickCount [ms]: 39
Measured: DateTime.UtcNow.Ticks [ms]: 127
Measured: Stopwatch: .ElapsedTicks [ms]: 209
Measured: Stopwatch: .ElapsedMilliseconds [ms]: 285
Measured: static Stopwatch.GetTimestamp [ms]: 187
Measured: Stopwatch+conversion to DateTime [ms]: 319
Compare that with DateTime.Now.Ticks [ms]: 3040
64 bit, Release mode, optimized:
Measured: GetTickCount64() [ms]: 148
Measured: Environment.TickCount [ms]: 31 (is it still worth it?)
Measured: DateTime.UtcNow.Ticks [ms]: 76 (!)
Measured: Stopwatch: .ElapsedTicks [ms]: 178
Measured: Stopwatch: .ElapsedMilliseconds [ms]: 226
Measured: static Stopwatch.GetTimestamp [ms]: 175
Measured: Stopwatch+conversion to DateTime [ms]: 246
Compare that with DateTime.Now.Ticks [ms]: 3020
It may be very interesting, that creating a DateTime value to print out the Stopwatch time seems to have nearly no costs. Interesting in a more academic than practical way is that static Stopwatch is slightly faster (as expected). Some optimization points are quite interesting.
For example, I cannot explain why Stopwatch.ElapsedMilliseconds only with 32 bit is so slow compared to it's other variants, for example the static one. This and DateTime.Now more than double their speed with 64 bit.
You can see: Only for millions of executions, the time of Stopwatch begins to matter. If this is really the case (but beware micro-optimizing too early), it may be interesting that with GetTickCount64(), but especially with DateTime.UtcNow, you have a 64 bit (long) timer with less precision than Stopwatch, but faster, so that you don't have to mess around with the 32 bit "ugly" Environment.TickCount.
As expected, DateTime.Now is by far the slowest of all.
If you run it, the code retrieves also your current Stopwatch accuracy and more.
Here is the full benchmark code:
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using static System.Environment;
[...]
[DllImport("kernel32.dll") ]
public static extern UInt64 GetTickCount64(); // Retrieves a 64bit value containing ticks since system start
static void Main(string[] args)
{
const int max = 10_000_000;
const int n = 3;
Stopwatch sw;
// Following Process&Thread lines according to tips by Thomas Maierhofer: https://codeproject.com/KB/testing/stopwatch-measure-precise.aspx
// But this somewhat contradicts to assertions by MS in: https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396#Does_QPC_reliably_work_on_multi-processor_systems__multi-core_system__and_________systems_with_hyper-threading
Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(1); // Use only the first core
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
Thread.CurrentThread.Priority = ThreadPriority.Highest;
Thread.Sleep(2); // warmup
Console.WriteLine($"Repeating measurement {n} times in loop of {max:N0}:{NewLine}");
for (int j = 0; j < n; j++)
{
sw = new Stopwatch();
sw.Start();
for (int i = 0; i < max; i++)
{
var tickCount = GetTickCount64();
}
sw.Stop();
Console.WriteLine($"Measured: GetTickCount64() [ms]: {sw.ElapsedMilliseconds}");
//
//
sw = new Stopwatch();
sw.Start();
for (int i = 0; i < max; i++)
{
var tickCount = Environment.TickCount; // only int capacity, enough for a bit more than 24 days
}
sw.Stop();
Console.WriteLine($"Measured: Environment.TickCount [ms]: {sw.ElapsedMilliseconds}");
//
//
sw = new Stopwatch();
sw.Start();
for (int i = 0; i < max; i++)
{
var a = DateTime.UtcNow.Ticks;
}
sw.Stop();
Console.WriteLine($"Measured: DateTime.UtcNow.Ticks [ms]: {sw.ElapsedMilliseconds}");
//
//
sw = new Stopwatch();
sw.Start();
for (int i = 0; i < max; i++)
{
var a = sw.ElapsedMilliseconds;
}
sw.Stop();
Console.WriteLine($"Measured: Stopwatch: .ElapsedMilliseconds [ms]: {sw.ElapsedMilliseconds}");
//
//
sw = new Stopwatch();
sw.Start();
for (int i = 0; i < max; i++)
{
var a = Stopwatch.GetTimestamp();
}
sw.Stop();
Console.WriteLine($"Measured: static Stopwatch.GetTimestamp [ms]: {sw.ElapsedMilliseconds}");
//
//
DateTime dt=DateTime.MinValue; // just init
sw = new Stopwatch();
sw.Start();
for (int i = 0; i < max; i++)
{
var a = new DateTime(sw.Elapsed.Ticks); // using variable dt here seems to make nearly no difference
}
sw.Stop();
//Console.WriteLine($"Measured: Stopwatch+conversion to DateTime [s] with millisecs: {dt:s.fff}");
Console.WriteLine($"Measured: Stopwatch+conversion to DateTime [ms]: {sw.ElapsedMilliseconds}");
Console.WriteLine();
}
//
//
sw = new Stopwatch();
var tickCounterStart = Environment.TickCount;
sw.Start();
for (int i = 0; i < max/10; i++)
{
var a = DateTime.Now.Ticks;
}
sw.Stop();
var tickCounter = Environment.TickCount - tickCounterStart;
Console.WriteLine($"Compare that with DateTime.Now.Ticks [ms]: {sw.ElapsedMilliseconds*10}");
Console.WriteLine($"{NewLine}General Stopwatch information:");
if (Stopwatch.IsHighResolution)
Console.WriteLine("- Using high-resolution performance counter for Stopwatch class.");
else
Console.WriteLine("- Using high-resolution performance counter for Stopwatch class.");
double freq = (double)Stopwatch.Frequency;
double ticksPerMicroSec = freq / (1000d*1000d) ; // microsecond resolution: 1 million ticks per sec
Console.WriteLine($"- Stopwatch accuracy- ticks per microsecond (1000 ms): {ticksPerMicroSec:N1}");
Console.WriteLine(" (Max. tick resolution normally is 100 nanoseconds, this is 10 ticks/microsecond.)");
DateTime maxTimeForTickCountInteger= new DateTime(Int32.MaxValue*10_000L); // tickCount means millisec -> there are 10.000 milliseconds in 100 nanoseconds, which is the tick resolution in .NET, e.g. used for TimeSpan
Console.WriteLine($"- Approximated capacity (maxtime) of TickCount [dd:hh:mm:ss] {maxTimeForTickCountInteger:dd:HH:mm:ss}");
// this conversion from seems not really accurate, it will be between 24-25 days.
Console.WriteLine($"{NewLine}Done.");
while (Console.KeyAvailable)
Console.ReadKey(false);
Console.ReadKey();
}
You probably want System.Diagnostics.StopWatch.
If you're looking for the functionality of Environment.TickCount but without the overhead of creating new Stopwatch objects, you can use the static Stopwatch.GetTimestamp() method (along with Stopwatch.Frequency) to calculate long time spans. Because GetTimestamp() returns a long, it won't overflow for a very, very long time (over 100,000 years, on the machine I'm using to write this). It's also much more accurate than Environment.TickCount which has a maximum resolution of 10 to 16 milliseconds.
Use
System.Diagnostics.Stopwatch
It has a property called
EllapsedMilliseconds
TickCount64
Doing some quick measurements on this new function, I found (optimized, release 64-bit, 1000mio loops):
Environment.TickCount: 2265
Environment.TickCount64: 2531
DateTime.UtcNow.Ticks: 69016
The measurements for not-optimized code were similar.
Test code:
static void Main( string[] args ) {
long start, end, length = 1000 * 1000 * 1000;
start = Environment.TickCount64;
for ( int i = 0; i < length; i++ ) {
var a = Environment.TickCount;
}
end = Environment.TickCount64;
Console.WriteLine( "Environment.TickCount: {0}", end - start );
start = Environment.TickCount64;
for ( int i = 0; i < length; i++ ) {
var a = Environment.TickCount64;
}
end = Environment.TickCount64;
Console.WriteLine( "Environment.TickCount64: {0}", end - start );
start = Environment.TickCount64;
for ( int i = 0; i < length; i++ ) {
var a = DateTime.UtcNow.Ticks;
}
end = Environment.TickCount64;
Console.WriteLine( "DateTime.UtcNow.Ticks: {0}", end - start );
}
You should use the Stopwatch class instead.
I use Environment.TickCount because:
The Stopwatch class is not in the Compact Framework.
Stopwatch uses the same underlying timing mechanism as TickCount, so the results won't be any more or less accurate.
The wrap-around problem with TickCount is cosmically unlikely to be hit (you'd have to leave your computer running for 27 days and then try to measure a time that just happens to span the wrap-around moment), and even if you did hit it the result would be a huge negative time span (so it would kind of stand out).
That being said, I would also recommend using Stopwatch, if it's available to you. Or you could take about 1 minute and write a Stopwatch-like class that wraps Environment.TickCount.
BTW, I see nothing in the Stopwatch documentation that mentions the wrap-around problem with the underlying timer mechanism, so I wouldn't be surprised at all to find that Stopwatch suffers from the same problem. But again, I wouldn't spend any time worrying about it.
I was going to say wrap it into a stopwatch class, but Grzenio already said the right thing, so I will give him an uptick. Such encapsulation factors out the decision as to which way is better, and this can change in time. I remember being shocked at how expensive it can be getting the time on some systems, so having one place that can implement the best technique can be very important.
For one-shot timing, it's even simpler to write
Stopwatch stopWatch = Stopwatch.StartNew();
...dostuff...
Debug.WriteLine(String.Format("It took {0} milliseconds",
stopWatch.EllapsedMilliseconds)));
I'd guess the cosmically unlikely wraparound in TickCount is even less of a concern for StopWatch, given that the ElapsedTicks field is a long. On my machine, StopWatch is high resolution, at 2.4e9 ticks per second. Even at that rate, it would take over 121 years to overflow the ticks field. Of course, I don't know what's going on under the covers, so take that with a grain of salt. However, I notice that the documentation for StopWatch doesn't even mention the wraparound issue, while the doc for TickCount does.
Overflow compensation
As said before, rollover may happen after 24.9 days, or, if you use an uint cast, after 49.8 days.
Because I did not want to pInvoke GetTickCount64, I wrote this overflow compensation. The sample code is using 'byte' to keep the numbers handy. Please have a look at it, it still might contain errors:
using System;
namespace ConsoleApp1 {
class Program {
//
static byte Lower = byte.MaxValue / 3;
static byte Upper = 2 * byte.MaxValue / 3;
//
///<summary>Compute delta between two TickCount values reliably, because TickCount might wrap after 49.8 days.</summary>
static short Delta( byte next, byte ticks ) {
if ( next < Lower ) {
if ( ticks > Upper ) {
return (short) ( ticks - ( byte.MaxValue + 1 + next ) );
}
}
if ( next > Upper ) {
if ( ticks < Lower ) {
return (short) ( ( ticks + byte.MaxValue + 1 ) - next );
}
}
return (short) ( ticks - next );
}
//
static void Main( string[] args ) {
// Init
Random rnd = new Random();
int max = 0;
byte last = 0;
byte wait = 3;
byte next = (byte) ( last + wait );
byte step = 0;
// Loop tick
for ( byte tick = 0; true; ) {
//
short delta = Delta( next, tick );
if ( delta >= 0 ) {
Console.WriteLine( "RUN: last: {0} next: {1} tick: {2} delta: {3}", last, next, tick, delta );
last = tick;
next = (byte) ( last + wait );
}
// Will overflow to 0 automatically
step = (byte) rnd.Next( 0, 11 );
tick += step;
max++; if ( max > 99999 ) break;
}
}
}
}

Categories