C # TimeSpan.FromTicks () inaccurate?

I have been using C # for some time to make a small game, and while testing this game on another PC, I came across some strange elapsed time issues.

I have everything updated in this game, based on the time elapsed since the last game cycle, as in most cases, but everything was in order on the second PC.

I found out that the problem was creating a TimeSpan using the FromTicks() method. I did a little test using the following code:

 class Program { static void Main(string[] args) { System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); sw.Start(); System.Threading.Thread.Sleep(TimeSpan.FromSeconds(1)); sw.Stop(); TimeSpan t = TimeSpan.FromTicks(sw.ElapsedTicks); Console.WriteLine(t.ToString()); Console.WriteLine(sw.Elapsed.ToString()); Console.ReadKey(); } } 

On my main PC, I ran this program and got the following:

  00: 00: 00.3528353
     00: 00: 00.9856987

Something I did not expect at all. I thought the second result was rather inaccurate, but the first was in excellent condition.

Then I ran the same program on another PC and got the following:

  00: 03: 20.6866734
     00: 00: 00.998287

I was very surprised.

My question here is not how I can fix this problem, I have already decided to use the second method, because it is accurate enough ... rather, I ask for enlightenment.

How could this be so? Why is the first result so inaccurate? Why does this change a lot on another machine?

I checked msdn in case I used the method incorrectly, but the examples there show that my results should be impossible ...

Note:
I think the CMOS battery is dying / dead, is that a factor?

+6
source share
3 answers

Summary:. The frequency of the stopwatch can differ on different hardware, which means that ticks (whose interval is based on frequency) have different sizes (and different tick sizes for timepan and datetime objects).

In short, use the Elapsed property instead:

  TimeSpan t = sw.Elapsed; 

... or use the Ticks Elapsed property if you need to perform calculations:

  TimeSpan t = TimeSpan.FromTicks(2*sw.Elapsed.Ticks); 

Long version with links:

http://msdn.microsoft.com/en-us/library/system.diagnostics.stopwatch.elapsedticks.aspx is the msdn page for your past ticks. It should be noted:

This property represents the number of ticks passed in the base timer. A tick is the smallest unit of time that a stopwatch timer can measure. Use the Frequency field to convert the ElapsedTicks Value to a few seconds.

And from the page in the Frequency field:

The timer frequency indicates the accuracy and resolution of the timer. For example, a timer frequency of 2 million ticks per second equals a timer resolution of 500 nanoseconds per tick. In other words, since one second equals 1 billion nanoseconds, a timer frequency of 2 million ticks per second is equivalent to 2 million ticks per 1 billion nanoseconds, which can be further simplified to 1 gallon per 500 nanoseconds.

The frequency value depends on the resolution of the base time mechanism. If the installed hardware and operating system supports a high-resolution performance counter, then the frequency value reflects the frequency of that counter. Otherwise, the frequency value is based on the frequency of the system timer.

Since the frequency of the stopwatch depends on the installed equipment and the operating system, the frequency value remains constant, and the system works.

Thus, the frequency of the stopwatch can be different on different hardware, which means that ticks have different sizes (and different tick sizes in timespan and datetime objects).

Interestingly, you are already using the Elapsed StopWatch property, which gives you time. sw.Elapsed is a TimeSpan that you probably need when you try to get a TimeSpan object. If you want to use ticks, you can use the Ticks property of this TimeSpan.

Alternatively, you can use ElapsedMilliseconds, which returns a long one.

+6
source

Temporary tilt and stopwatch Ticks are different. To reconcile, use the Stopwatch Elapsed property instead, which correctly converts to TimeSpan based on the ticks of the machine.

  System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); sw.Start(); System.Threading.Thread.Sleep(TimeSpan.FromSeconds(1)); sw.Stop(); // don't load a TimeSpan with ElapsedTicks, these have diff frequency, // call Elapsed instead to get TimeSpan. TimeSpan t = sw.Elapsed; Console.WriteLine(t.ToString()); Console.ReadKey(); 

Or, of course, you can divide by frequency, etc., but it is much more. The main takeaway - you should not view TimeSpan Ticks in the same way as Tullwatch.

Related Thread: What is a timer tick, a unit used by a stopwatch .ElapsedTicks

+6
source

Just for you information ... I tested it, and here's how to do it if you absolutely want to use "FromTicks". But if I were you, I would advise James Michael Har.

  System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); sw.Start(); System.Threading.Thread.Sleep(TimeSpan.FromSeconds(1)); sw.Stop(); // don't load a TimeSpan with ElapsedTicks, these have diff frequency, // call Elapsed instead to get TimeSpan. TimeSpan t1 = sw.Elapsed; Debug.Print("Millisecs: " + t1.TotalMilliseconds); // TimeSpan.Elapsed Code //if (!SafeNativeMethods.QueryPerformanceFrequency(out Stopwatch.Frequency)) //{ // Stopwatch.IsHighResolution = false; // Stopwatch.Frequency = 10000000L; // Stopwatch.tickFrequency = 1.0; //} //else //{ // Stopwatch.IsHighResolution = true; // Stopwatch.tickFrequency = 10000000.0; // Stopwatch.tickFrequency /= (double)Stopwatch.Frequency; //} //public TimeSpan Elapsed //{ // [__DynamicallyInvokable] // get // { // return new TimeSpan(this.GetElapsedDateTimeTicks()); // } //} //private long GetElapsedDateTimeTicks() //{ // long rawElapsedTicks = this.GetRawElapsedTicks(); // if (Stopwatch.IsHighResolution) // return (long)((double)rawElapsedTicks * Stopwatch.tickFrequency); // return rawElapsedTicks; //} TimeSpan t2; if (Stopwatch.IsHighResolution) { t2 = TimeSpan.FromTicks((long)((double)sw.ElapsedTicks * ((double)10000000.0 / (double)Stopwatch.Frequency))); } else { t2 = TimeSpan.FromTicks(sw.ElapsedTicks); } Debug.Assert(t1.TotalMilliseconds == t2.TotalMilliseconds); // true, return; 
0
source

Source: https://habr.com/ru/post/899532/


All Articles