This question already has answers here:
High resolution timer in C#
(5 answers)
Closed 3 years ago.
I want to have a timer with about 5millisecond resolution. but the current Timer in .Net has a resolution of about 50ms.
I could not find any working solution that creates a high resolution timer, although some claim that you can do it in C#.
In regards to the information that the OP was specifically asking about the Timer class which fires events at regular intervals. I have amended this answer, with my old answer below the horizontal rule.
I tested the following code with the Timer class, and it seems like it can get at least within the 14 - 15 millisecond range on my machine. Try it out for yourself and see if you can reproduce this. So sub-50 millisecond response times are possible, but it can't get down to exactly one millisecond.
using System;
using System.Timers;
using System.Diagnostics;
public static class Test
{
public static void Main(String[] args)
{
Timer timer = new Timer();
timer.Interval = 1;
timer.Enabled = true;
Stopwatch sw = Stopwatch.StartNew();
long start = 0;
long end = sw.ElapsedMilliseconds;
timer.Elapsed += (o, e) =>
{
start = end;
end = sw.ElapsedMilliseconds;
Console.WriteLine("{0} milliseconds passed", end - start);
};
Console.ReadLine();
}
}
NB: The following is my old answer, when I thought the OP was talking about timing things. The following is merely useful information with respect to timing the duration of things, but doesn't provide any way of firing events at a regular interval. For that purpose, the Timer class is necessary.
Try using the Stopwatch class within System.Diagnostics: http://msdn.microsoft.com/en-us/library/system.diagnostics.stopwatch.aspx
You can query it to check if it's high resolution through it's IsHighResolution field. Also, you can check the exact resolution of the Stopwatch:
int resolution = 1E9 / Stopwatch.Frequency;
Console.WriteLine("The minimum measurable time on this system is: {0} nanoseconds", resolution);
If you're worried about where this is actually sourced, the documentation seems to imply that it actually internally calls the lower level Win32 functions:
The Stopwatch class assists the manipulation of timing-related
performance counters within managed code. Specifically, the Frequency
field and GetTimestamp method can be used in place of the unmanaged
Win32 APIs QueryPerformanceFrequency and QueryPerformanceCounter.
What about this one?
public class HiResTimer
{
private bool isPerfCounterSupported = false;
private Int64 frequency = 0;
// Windows CE native library with QueryPerformanceCounter().
private const string lib = "coredll.dll";
[DllImport(lib)]
private static extern int QueryPerformanceCounter(ref Int64 count);
[DllImport(lib)]
private static extern int QueryPerformanceFrequency(ref Int64 frequency);
public HiResTimer()
{
// Query the high-resolution timer only if it is supported.
// A returned frequency of 1000 typically indicates that it is not
// supported and is emulated by the OS using the same value that is
// returned by Environment.TickCount.
// A return value of 0 indicates that the performance counter is
// not supported.
int returnVal = QueryPerformanceFrequency(ref frequency);
if (returnVal != 0 && frequency != 1000)
{
// The performance counter is supported.
isPerfCounterSupported = true;
}
else
{
// The performance counter is not supported. Use
// Environment.TickCount instead.
frequency = 1000;
}
}
public Int64 Frequency
{
get
{
return frequency;
}
}
public Int64 Value
{
get
{
Int64 tickCount = 0;
if (isPerfCounterSupported)
{
// Get the value here if the counter is supported.
QueryPerformanceCounter(ref tickCount);
return tickCount;
}
else
{
// Otherwise, use Environment.TickCount.
return (Int64)Environment.TickCount;
}
}
}
static void Main()
{
HiResTimer timer = new HiResTimer();
// This example shows how to use the high-resolution counter to
// time an operation.
// Get counter value before the operation starts.
Int64 counterAtStart = timer.Value;
// Perform an operation that takes a measureable amount of time.
for (int count = 0; count < 10000; count++)
{
count++;
count--;
}
// Get counter value when the operation ends.
Int64 counterAtEnd = timer.Value;
// Get time elapsed in tenths of a millisecond.
Int64 timeElapsedInTicks = counterAtEnd - counterAtStart;
Int64 timeElapseInTenthsOfMilliseconds =
(timeElapsedInTicks * 10000) / timer.Frequency;
MessageBox.Show("Time Spent in operation (tenths of ms) "
+ timeElapseInTenthsOfMilliseconds +
"\nCounter Value At Start: " + counterAtStart +
"\nCounter Value At End : " + counterAtEnd +
"\nCounter Frequency : " + timer.Frequency);
}
}
I found a solution to this problem in the following blog:
http://web.archive.org/web/20110910100053/http://www.indigo79.net/archives/27#comment-255
It tells you how to use the multimedia timer to have a timer with high frequency. It is working just fine for me!!!
Here is an implementation based on StopWatch timer
https://gist.github.com/DraTeots/436019368d32007284f8a12f1ba0f545
It works on all platforms and is high precision wherever StopWatch.IsHighPrecision == true
Its Elapsed event is guaranteed to be non overlapping (which might be important to know, because state changes inside the event handler may be left unprotected against multi threaded access)
Here is how to use it:
Console.WriteLine($"IsHighResolution = {HighResolutionTimer.IsHighResolution}");
Console.WriteLine($"Tick time length = {HighResolutionTimer.TickLength} [ms]");
var timer = new HighResolutionTimer(0.5f);
// UseHighPriorityThread = true, sets the execution thread
// to ThreadPriority.Highest. It doesn't provide any precision gain
// in most of the cases and may do things worse for other threads.
// It is suggested to do some studies before leaving it true
timer.UseHighPriorityThread = false;
timer.Elapsed += (s, e) => { /*... e.Delay*/ }; // The call back with real delay info
timer.Start();
timer.Stop(); // by default Stop waits for thread.Join()
// which, if called not from Elapsed subscribers,
// would mean that all Elapsed subscribers
// are finished when the Stop function exits
timer.Stop(joinThread:false) // Use if you don't care and don't want to wait
Here is a benchmark (and a live example):
https://gist.github.com/DraTeots/5f454968ae84122b526651ad2d6ef2a3
The results of setting the timer for 0.5 ms on Windows 10:
It is also worth to mention that:
I had the same precision on mono on Ubuntu.
While playing with the benchmark, the maximum and a very rare deviation I saw was about 0.5 ms
(which probably means nothing, it is not realtime systems, but still worth mentioning)
Stopwatch ticks are not TimeSpan ticks. On that Windows 10 machine
HighResolutionTimer.TickLength is 0.23[ns].
CPU usage of the benchmark is 10% for 0.5ms interval and 0.1% for 200ms interval
Pretty late to the party still might be useful for someone looking for an answer as nothing has been changed for over a decade in the topic.
Background
Any .NET delay instructions would always come down to system clock resolution, the one you set with timeBeginPeriod(). No matter if it's a Thread.Sleep(N), Threading.Timer or Waitable.WaitOne(N). Yet time resolution of DateTime.Now() and System.Diagnostic.Stopwatch is way higher so there is a way of implementing precise timing events known as hot loop. Hot loops yet prone to being threatened badly by OS since those tend to occupy processor core at full. And here's what we do to prevent this:
Surrender thread time quant in a hot loop to other threads once there's no more need for it by calling Thread.Sleep(0) or .WaitOne(0)
Below is a code piece showing simple implementation of high resolution scheduler:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
/// <summary>
/// High resolution scheduler.
/// License: public domain (no restrictions or obligations)
/// Author: Vitaly Vinogradov
/// </summary>
public class HiResScheduler : IDisposable
{
/// <summary>
/// Scheduler would automatically downgrade itself to cold loop (Sleep(1)) when there are no
/// tasks earlier than the treshold.
/// </summary>
public const int HOT_LOOP_TRESHOLD_MS = 16;
protected class Subscriber : IComparable<Subscriber>, IComparable
{
public Action Callback { get; set; }
public double DelayMs { get; set; }
public Subscriber(double delay, Action callback)
{
DelayMs = delay;
Callback = callback;
}
public int CompareTo(Subscriber other)
{
return DelayMs.CompareTo(other.DelayMs);
}
public int CompareTo(object obj)
{
if (ReferenceEquals(obj, null))
return -1;
var other = obj as Subscriber;
if (ReferenceEquals(other, null))
return -1;
return CompareTo(other);
}
}
private Thread _spinner;
private ManualResetEvent _allowed = new ManualResetEvent(false);
private AutoResetEvent _wakeFromColdLoop = new AutoResetEvent(false);
private bool _disposing = false;
private bool _adding = false;
private List<Subscriber> _subscribers = new List<Subscriber>();
private List<Subscriber> _pendingSubscribers = new List<Subscriber>();
public bool IsActive { get { return _allowed.WaitOne(0); } }
public HiResScheduler()
{
_spinner = new Thread(DoSpin);
_spinner.Start();
}
public void Start()
{
_allowed.Set();
}
public void Pause()
{
_allowed.Reset();
}
public void Enqueue(double delayMs, Action callback)
{
lock (_pendingSubscribers)
{
_pendingSubscribers.Add(new Subscriber(delayMs, callback));
_adding = true;
if (delayMs <= HOT_LOOP_TRESHOLD_MS * 2)
_wakeFromColdLoop.Set();
}
}
private void DoSpin(object obj)
{
var sw = new Stopwatch();
sw.Start();
var nextFire = null as Subscriber;
while (!_disposing)
{
_allowed.WaitOne();
if (nextFire != null && sw.Elapsed.TotalMilliseconds >= nextFire?.DelayMs)
{
var diff = sw.Elapsed.TotalMilliseconds;
sw.Restart();
foreach (var item in _subscribers)
item.DelayMs -= diff;
foreach (var item in _subscribers.Where(p => p.DelayMs <= 0).ToList())
{
item.Callback?.Invoke();
_subscribers.Remove(item);
}
nextFire = _subscribers.FirstOrDefault();
}
if (_adding)
lock (_pendingSubscribers)
{
_subscribers.AddRange(_pendingSubscribers);
_pendingSubscribers.Clear();
_subscribers.Sort();
_adding = false;
nextFire = _subscribers.FirstOrDefault();
}
if (nextFire == null || nextFire.DelayMs > HOT_LOOP_TRESHOLD_MS)
_wakeFromColdLoop.WaitOne(1);
else
_wakeFromColdLoop.WaitOne(0);
}
}
public void Dispose()
{
_disposing = true;
}
}
The system clock "ticks" at a constant rate. In order to raise the accuracy of timer dependent function*s, call **timeGetDevCaps* which determines the minimum supported timer resolution.
Then call timeBeginPeriod setting the timer resolution to its minimum.
Caution: By invoking timeBeginPeriod, other timer dependent function can be significantly affected such as the system clock, system power usage, and the scheduler. Thus start your application with timeBeginPeriod and end it with timeEndPeriod
The previous example doesn't work unless the frequency is in milliseconds; the perf timer frequency is rarely in ms.
private static Int64 m_iPerfFrequency = -1;
public static double GetPerfCounter()
{
// see if we need to get the frequency
if (m_iPerfFrequency < 0)
{
if (QueryPerformanceFrequency(out m_iPerfFrequency) == 0)
{
return 0.0;
}
}
Int64 iCount = 0;
if (QueryPerformanceCounter(out iCount) == 0)
{
return 0.0;
}
return (double)iCount / (double)m_iPerfFrequency;
}
[DllImport("kernel32.dll", SetLastError = true)]
public static extern int QueryPerformanceCounter(out Int64 iCount);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern int QueryPerformanceFrequency(out Int64 iFrequency);
This returns the perf counter in seconds. The reason you'd use the perf timer is to share a timer with legacy C++ code, or get a more precise timer than the C# StopWatch class.
You could use QueryPerformanceCounter() and QueryPerformanceTimer() as outlined in this article.
Related
In unity3d I'm trying to read the system usage in order to see the CPU and RAM usage whilst a person is playing a VR game. I know how I can show it on the computer screen and how to keep it away from the players VR screen.
I have been looking all around Google for as far as I know. Most of them lead to the same answer which I cannot seem to get working correctly.
I have been checking out the post: https://answers.unity.com/questions/506736/measure-cpu-and-memory-load-in-code.html which leads me to the stackoverflow page: How to get the CPU Usage in C#?
In these posts they always get the problem of having the CPU usage stuck at 100%, even though this is incorrect. I have been trying the System.Threading.Thread.Sleep(1000). But this locks the entire game to 1fps due to it waiting 1 sec every second. And even with having 1fps I cannot get any other read than 100%.
In this code I'm using the Sleep thread which slows down the game to 1fps
using UnityEngine;
using System.Diagnostics;
using TMPro;
public class DebugUIManager : MonoBehaviour
{
private PerformanceCounter cpuCounter;
[SerializeField] private TMP_Text cpuCounterText;
private void Start()
{
cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total");
}
private void Update()
{
cpuCounterText.text = getCurrentCpuUsage();
}
private string getCurrentCpuUsage()
{
dynamic firstValue = cpuCounter.NextValue() + "% CPU";
System.Threading.Thread.Sleep(1000);
dynamic secondValue = cpuCounter.NextValue() + "% CPU";
return secondValue;
}
}
Whenever I change the
private string getCurrentCpuUsage()
{
dynamic firstValue = cpuCounter.NextValue() + "% CPU";
System.Threading.Thread.Sleep(1000);
dynamic secondValue = cpuCounter.NextValue() + "% CPU";
return secondValue;
}
to
private string getCurrentCpuUsage()
{
return cpuCounter.NextValue() + "%";
}
the game won't get dropped in fps, but it also doesn't do anything still.
I haven't been getting any error messages because it runs without issues. But I would really like to know how to get the CPU usage, so I can figure out the rest myself.
Any answers helping would be appreciated.
I tried this and also couldn't get PerformanceCounter to run correctly (always returned 100% like for you)
However I've found a good alternative here and used it to re-build your DebugUIManager on it
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using TMPro;
using UnityEngine;
public class DebugUIManager : MonoBehaviour
{
[Header("Components")]
[SerializeField] private TMP_Text cpuCounterText;
[Header("Settings")]
[Tooltip("In which interval should the CPU usage be updated?")]
[SerializeField] private float updateInterval = 1;
[Tooltip("The amount of physical CPU cores")]
[SerializeField] private int processorCount;
[Header("Output")]
public float CpuUsage;
private Thread _cpuThread;
private float _lasCpuUsage;
private void Start()
{
Application.runInBackground = true;
cpuCounterText.text = "0% CPU";
// setup the thread
_cpuThread = new Thread(UpdateCPUUsage)
{
IsBackground = true,
// we don't want that our measurement thread
// steals performance
Priority = System.Threading.ThreadPriority.BelowNormal
};
// start the cpu usage thread
_cpuThread.Start();
}
private void OnValidate()
{
// We want only the physical cores but usually
// this returns the twice as many virtual core count
//
// if this returns a wrong value for you comment this method out
// and set the value manually
processorCount = SystemInfo.processorCount / 2;
}
private void OnDestroy()
{
// Just to be sure kill the thread if this object is destroyed
_cpuThread?.Abort();
}
private void Update()
{
// for more efficiency skip if nothing has changed
if (Mathf.Approximately(_lasCpuUsage, CpuUsage)) return;
// the first two values will always be "wrong"
// until _lastCpuTime is initialized correctly
// so simply ignore values that are out of the possible range
if (CpuUsage < 0 || CpuUsage > 100) return;
// I used a float instead of int for the % so use the ToString you like for displaying it
cpuCounterText.text = CpuUsage.ToString("F1") + "% CPU";
// Update the value of _lasCpuUsage
_lasCpuUsage = CpuUsage;
}
/// <summary>
/// Runs in Thread
/// </summary>
private void UpdateCPUUsage()
{
var lastCpuTime = new TimeSpan(0);
// This is ok since this is executed in a background thread
while (true)
{
var cpuTime = new TimeSpan(0);
// Get a list of all running processes in this PC
var AllProcesses = Process.GetProcesses();
// Sum up the total processor time of all running processes
cpuTime = AllProcesses.Aggregate(cpuTime, (current, process) => current + process.TotalProcessorTime);
// get the difference between the total sum of processor times
// and the last time we called this
var newCPUTime = cpuTime - lastCpuTime;
// update the value of _lastCpuTime
lastCpuTime = cpuTime;
// The value we look for is the difference, so the processor time all processes together used
// since the last time we called this divided by the time we waited
// Then since the performance was optionally spread equally over all physical CPUs
// we also divide by the physical CPU count
CpuUsage = 100f * (float)newCPUTime.TotalSeconds / updateInterval / processorCount;
// Wait for UpdateInterval
Thread.Sleep(Mathf.RoundToInt(updateInterval * 1000));
}
}
}
I am trying to create a timer, which, for example, every 3 seconds during eg 15 seconds will perform an action.
I tried to use gameTime.ElapsedGameTime.TotalSeconds and loop, but unfortunately it doesn't work.
I have an Attack () function that reduces player statistics when an enemy attacks it. I would like that in case of one particular enemy, this function for a specified period of time would subtract player's HP, eg for every 3 seconds. I guess it should be done in the Update function to access gameTime, unfortunately, I have no idea how to do it.
public override Stats Attack()
{
attack = true;
return new Stats(0, -stats.Damage, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}
public override void Update(GameTime gameTime)
{
spriteDirection = Vector2.Zero; // reset input
Move(Direction); // gets the state of my keyborad
float deltaTime = (float)gameTime.ElapsedGameTime.TotalSeconds; // make movement framerate independant
spriteDirection *= Speed; // add hero's speed to movement
position += (spriteDirection * deltaTime); // adding deltaTime to stabilize movement
totalPosition = new Vector2((int)((BottomBoundingBox.Center.X) / 32.0f), (int)((BottomBoundingBox.Center.Y) / 32.0f));
base.Update(gameTime);
}
I will make it simple, so you need to modify my code to achieve your desire result.
My best guess is that you want to have a special effect when your monsters hit your player.
First, you need to check if the monster actually hits the player (if collision is detected):
if (collision)//if it's true
{
// Apply your special effect if it is better than
// the one currently affecting the target :
if (player.PoisonModifier <= poisonModifier) {
player.PoisonModifier = poisonModifier;
player.ModifierDuration = modifierDuration;
}
//player.setColor(Color.Blue);//change color to blue
player.hitPoints -= Poision.Damage;//or enemy.PoisonDamage or whatever you define here
hit.Expire();//this can be for the arrow or bullet from your enemy or simply just a normal hit
}
In your Player class, you need:
public float ModifierDuration {
get {
return modifierDuration;
}
set {
modifierDuration = value;
modiferCurrentTime = 0;
}
}
Then in Update method of Player class:
// If the modifier has finished,
if (modiferCurrentTime > modifierDuration) {
// reset the modifier.
//stop losing HP code is here
modiferCurrentTime = 0;//set the time to zero
setColor(Color.White);//set back the color of your player
}
count += gameTime.ElapsedGameTime.TotalSeconds;//timer for actions every 3s
if (posionModifier != 0 && modiferCurrentTime <= modifierDuration) {
// Modify the hp of the enemy.
player.setHP(player.getCurrentHP() - posionDamage);
//Or change it to every 3s
//if (count > 3) {
// count = 0;
//DoSubtractHP(player);
//}
// Update the modifier timer.
modiferCurrentTime += (float) gameTime.ElapsedGameTime.TotalSeconds;
setColor(Color.Blue);//change the color to match the special effect
}
Hope this helps!
You need to store the start time, or the last time that the action was carried out. Then during each update compare the elapsed time to the stored time. If 3 seconds have passed then perform the action, store the current time and repeat the process.
I do not know monogame, but if I were doing this in one of my C# applications, I would use a timer, and pass in anything that the timer would need to modify.
There is good info here https://learn.microsoft.com/en-us/dotnet/api/system.timers.timer?view=netframework-4.8 and I stole a bit of code from here and modified it as an example to demonstrate my idea. I extended the System.Timer to allow it to run for a duration and stop itself. You can set the frequency and duration and forget about it. Assuming that you are able to update this information from a timer.
class Program
{
private static FixedDurationTimer aTimer;
static void Main(string[] args)
{
// Create a timer and set a two second interval.
aTimer = new FixedDurationTimer();
aTimer.Interval = 2000;
// Hook up the Elapsed event for the timer.
aTimer.Elapsed += OnTimedEvent;
// Start the timer
aTimer.StartWithDuration(TimeSpan.FromSeconds(15));
Console.WriteLine("Press the Enter key to exit the program at any time... ");
Console.ReadLine();
}
private static void OnTimedEvent(Object source, System.Timers.ElapsedEventArgs e)
{
FixedDurationTimer timer = source as FixedDurationTimer;
if (timer.Enabled)
{
Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);
}
}
public class FixedDurationTimer : System.Timers.Timer
{
public TimeSpan Duration { get; set; }
private Stopwatch _stopwatch;
public void StartWithDuration(TimeSpan duration)
{
Duration = duration;
_stopwatch = new Stopwatch();
Start();
_stopwatch.Start();
}
public FixedDurationTimer()
{
Elapsed += StopWhenDurationIsReached;
}
private void StopWhenDurationIsReached(object sender, ElapsedEventArgs e)
{
if (_stopwatch != null && Duration != null)
{
if (_stopwatch.Elapsed > Duration)
{
Console.WriteLine("Duration has been met, stopping");
Stop();
}
}
}
}
}
You could see examples of how to pass objects into the timer here (#JaredPar's example) How do I pass an object into a timer event?
string theString = ...;
timer.Elapsed += (sender, e) => MyElapsedMethod(sender, e, theString);
static void MyElapsedMethod(object sender, ElapsedEventArgs e, string theString) {
...
}
One way to do this would be to use coroutines. MonoGame does not have built-in support for them like other game engines, but they are not too complicated to implement yourself. You need some knowledge of the yield keyword and enumerators to understand them, but once abstracted away they make your game code way easier to write and understand.
Here's an example of what your gameplay logic would look using a Coroutine system like the one described below:
public void Attack(Enemy enemyAttacking)
{
if (enemyAttacking.Type == "OneParticularEnemy")
{
StartCoroutine(RunDamageOverTimeAttack());
}
}
// This coroutine starts a second coroutine that applies damage over time, it
// then waits 15 seconds before terminating the second coroutine.
public IEnumerator RunDamageOverTimeAttack()
{
var cr = StartCoroutine(ApplyDamageOverTime());
yield return 15000; // in milleseconds (ms), i.e. 15000 ms is 15 seconds
cr.IsFinished = true;
}
// This coroutine applies the damage every 3 seconds until the coroutine is finished
public IEnumerator ApplyDamageOverTime()
{
while (true)
{
ApplyDamageToPlayer();
yield return 3000;
}
}
The code reads very close to the way you described the actual problem you're trying to solve. Now for the coroutine system...
The StartCouroutine method creates a Coroutine class instance and stores it. During the Update step of the game loop you iterate through the coroutines and update them, providing gameTime to calculate when the next step of the method should run. Each step executes the code in the routine until a yield is found OR until the method ends naturally. Once the coroutine is finished you clear them out. This logic looks something like this:
private List<Coroutine> coroutines = new List<Coroutine>();
public Coroutine StartCoroutine(IEnumerator routine)
{
var cr = new Coroutine(routine);
couroutines.Add(cr);
return cr;
}
public void UpdateCoroutines(GameTime gameTime)
{
// copied in case list is modified during coroutine updates
var coroutinesToUpdate = coroutines.ToArray();
foreach (coroutine in coroutinesToUpdate)
coroutine.Update(gameTime);
coroutines.RemoveAll(c => c.IsFinished);
}
public void Update(GameTime gameTime)
{
// normal update logic that would invoke Attack(), then...
UpdateCoroutines(gameTime);
}
A Coroutine class is responsible for tracking the time remaining between steps of the routine, and tracking when the routine is finished. It looks something like this:
public class Coroutine
{
private IEnumerator routine;
private double? wait;
public Coroutine(IEnumerator routine)
{
this.routine = routine;
}
public bool IsFinished { get; set; }
public void Update(GameTime gameTime)
{
if (IsFinished) return;
if (wait.HasValue)
{
var timeRemaining = wait.Value - gameTime.ElapsedGameTime.TotalMilliseconds;
wait = timeRemaining < 0 ? null : timeRemaining;
// If wait has a value we still have time to burn before the
// the next increment, so we return here.
if (wait.HasValue) return;
}
if (!routine.MoveNext())
{
IsFinished= true;
}
else
{
wait = routine.Current as double?;
}
}
}
This may seem considerably more complex than other solutions provided here, and it may be overkill, but Coroutines allow you to forgo tracking a bunch of state in tracking variables, making complex scenarios easier to follow and cleaner to read. For example, here's a arrow spawning strategy I used Coroutines for in Ludum Dare 37. It spawns 3 arrows 600 milleseconds apart with a 3 second wait between them: https://github.com/srakowski/LD37/blob/477cf515d599eba7c4b55c3f57952865d894f741/src/LD37/GameObjects/BurstArrowSpawnBehavior.cs
If you'd like more social proof of the value of Coroutines take a look at Unity. Unity is one of the more popular game engines, and it has Coroutine support. They describe a scenario where it is useful in their documentation: https://docs.unity3d.com/Manual/Coroutines.html.
I use this for my game :
Public Async Function DelayTask(Time As Double) As Threading.Tasks.Task
Await Threading.Tasks.Task.Delay(TimeSpan.FromSeconds(Time))
End Function
Converted to C# :
public async System.Threading.Tasks.Task DelayTask(double Time)
{
await System.Threading.Tasks.Task.Delay(TimeSpan.FromSeconds(Time));
}
You would use it like this in an Async Function :
Await DelayTask(1.5);
The number is in seconds, you can change this by changing the TimeSpan.whateverformat.
Considering that you'll have various things that affect your stats maybe you're better off at having an update subroutine in your Stats class that will check a list of effects that are scheduled to update after one point in time.
This would be better for performance than having each effect relying on its own thread.
Given the attached LINQ-Pad snippet.
It creates 8 tasks, executes for 500ms and draws a graph on when the threads were actually running.
On a 4 core CPU it may look like this:
Now, if I add a Thread.Sleep or a Task.Delay within the thread loops, I can visualize the clock of the windows system timer (~15ms):
Now, there's also the timeBeginPeriod function, where I can lower the system timer's resolution (in the example to 1ms). And here's the difference. With Thread.Sleep I get this chart (what I expected):
When using Task.Delay I get the same graph as when the time would be set to 15ms:
Question: Why does the TPL ignore the timer setting?
Here is the code (you need LinqPad 5.28 beta to run the Chart)
void Main()
{
const int Threads = 8;
const int MaxTask = 20;
const int RuntimeMillis = 500;
const int Granularity = 10;
ThreadPool.SetMinThreads(MaxTask, MaxTask);
ThreadPool.SetMaxThreads(MaxTask, MaxTask);
var series = new bool[Threads][];
series.Initialize(i => new bool[RuntimeMillis * Granularity]);
Watch.Start();
var tasks = Async.Tasks(Threads, i => ThreadFunc(series[i], pool));
tasks.Wait();
series.ForAll((x, y) => series[y][x] ? new { X = x / (double)Granularity, Y = y + 1 } : null)
.Chart(i => i.X, i => i.Y, LINQPad.Util.SeriesType.Point)
.Dump();
async Task ThreadFunc(bool[] data, Rendezvous p)
{
double now;
while ((now = Watch.Millis) < RuntimeMillis)
{
await Task.Delay(10);
data[(int)(now * Granularity)] = true;
}
}
}
[DllImport("winmm.dll")] internal static extern uint timeBeginPeriod(uint period);
[DllImport("winmm.dll")] internal static extern uint timeEndPeriod(uint period);
public class Rendezvous
{
private readonly object lockObject = new object();
private readonly int max;
private int n = 0;
private readonly ManualResetEvent waitHandle = new ManualResetEvent(false);
public Rendezvous(int count)
{
this.max = count;
}
public void Join()
{
lock (this.lockObject)
{
if (++this.n >= max)
waitHandle.Set();
}
}
public void Wait()
{
waitHandle.WaitOne();
}
public void Reset()
{
lock (this.lockObject)
{
waitHandle.Reset();
this.n = 0;
}
}
}
public static class ArrayExtensions
{
public static void Initialize<T>(this T[] array, Func<int, T> init)
{
for (int n = 0; n < array.Length; n++)
array[n] = init(n);
}
public static IEnumerable<TReturn> ForAll<TValue, TReturn>(this TValue[][] array, Func<int, int, TReturn> func)
{
for (int y = 0; y < array.Length; y++)
{
for (int x = 0; x < array[y].Length; x++)
{
var result = func(x, y);
if (result != null)
yield return result;
}
}
}
}
public static class Watch
{
private static long start;
public static void Start() => start = Stopwatch.GetTimestamp();
public static double Millis => (Stopwatch.GetTimestamp() - start) * 1000.0 / Stopwatch.Frequency;
public static void DumpMillis() => Millis.Dump();
}
public static class Async
{
public static Task[] Tasks(int tasks, Func<int, Task> thread)
{
return Enumerable.Range(0, tasks)
.Select(i => Task.Run(() => thread(i)))
.ToArray();
}
public static void JoinAll(this Thread[] threads)
{
foreach (var thread in threads)
thread.Join();
}
public static void Wait(this Task[] tasks)
{
Task.WaitAll(tasks);
}
}
timeBeginPeriod() is a legacy function, dates back to Windows 3.1. Microsoft would love to get rid of it, but can't. It has a pretty gross machine-wide side-effect, it increases the clock interrupt rate. The clock interrupt is the "heart-beat" of the OS, it determines when the thread scheduler runs and when sleeping threads can be revived.
The .NET Thread.Sleep() function is not actually implemented by the CLR, it passes the job to the host. Any you'd use to run this test simply delegates the job to the Sleep() winapi function. Which is affected by the clock interrupt rate, as documented in the MSDN article:
To increase the accuracy of the sleep interval, call the timeGetDevCaps function to determine the supported minimum timer resolution and the timeBeginPeriod function to set the timer resolution to its minimum. Use caution when calling timeBeginPeriod, as frequent calls can significantly affect the system clock, system power usage, and the scheduler.
The caution at the end is why Microsoft isn't very happy about it. This does get misused, one of the more egregious cases was noted by one of the founders of this web site in this blog post. Beware of Greeks bearing gifts.
That this changes the accuracy of timers is not exactly a feature. You would not want your program to behave differently just because the user started a browser. So the .NET designers did something about it. Task.Delay() uses System.Threading.Timer under the hood. Instead of just blindly relying on the interrupt rate, it divides the period you specify by 15.6 to calculate the number of time slices. Slightly off from the ideal value btw, which is 15.625, but a side-effect of integer math. So the timer behaves predictably and no longer misbehaves when the clock rate is lowered to 1 msec, it always takes at least one slice. 16 msec in practice since the GetTickCount() unit is milliseconds.
Task.Delay() is implemented via TimerQueueTimer (ref DelayPromise). The resolution of the latter does not change based on timeBeginPeriod(), though this appears to be a recent change in Windows (ref VS Feedback).
Update:
I isolated the problem to its core components and a much shorter minimal working example in another question:
Observable.Interval not updating UI with expected frequency
I need to display a sequence of images (which are read from a folder) as a "movie", at a constant, previously known, frame-rate.
I have an Image control in WPF, whose Source is data-bound to a ViewModel property Image. I then proceed to update that image on a timely basis, using an Observable.Interval event source. For each elapsed interval, the UpdateImage is called, which updates the image inside a Task.Run() call.
My problem is: when I experimentally increase effective frame-rate (which depends on actual frame-rate and also on playback speed), the playback keeps being at normal speed up tu a given value. Above that value, it starts to look slower.
I believe that it has to do with RaisePropertyChanged call, but I'm not sure. I tried using SubscribeOnDispatcher (or whas it ObserveOnDispatcher?) but anyway it didnt have an effect.
Questions are:
- What I am doing wrong?
- How could I investigate and resolve the problem?
UPDATE:
It's worth mentioning that the getter for Image calls CreateImageForIndex(), which is a method that could have a non-trivial cost. Would it be possible to "async" it?
ViewModel (partial):
CancellationTokenSource _cancelPlay;
double _speed;
public void Play(double speed)
{
_speed = speed;
_cancelPlay = new CancellationTokenSource();
Observable.Interval(TimeSpan.FromSeconds(1.0 / (Math.Abs(speed) * Exame.Model.Configurações.FrameRate)))
.Subscribe(t => ExecuteRun(), _cancelPlay.Token);
}
public void Stop()
{
_cancelPlay?.Cancel();
}
void ExecuteRun()
{
Task.Run(() =>
{
Index = Math.Max(0, Math.Min(_model.MaxIndex, Index + 1 * Math.Sign(_speed)));
});
}
public int Index
{
get { return _model.Index; }
set
{
_model.Index = value;
RaisePropertyChanged(null); // this tells view to get a new value for `Image` too!
}
}
public ImageSource Image => _model.CreateImageForIndex(Index);
I've followed a hint from #Enigmativity (in the other answer I posted), that in Windows the resolution of timers is 15ms at most.
So I tested another strategy: spinning a while loop with an "when elapsed" condition, similar to a game loop, measuring time with a Stopwatch, and everything is working fine now.
public void Play(double speed)
{
_speed = speed;
_cancelPlay?.Cancel();
_cancelPlay = new CancellationTokenSource();
Task.Run(() => PlayLoop(_cancelPlay.Token), _cancelPlay.Token);
}
void PlayLoop(CancellationToken token)
{
var sw = Stopwatch.StartNew();
double previous = sw.ElapsedMilliseconds;
double timeInterval = 1000.0 / (Math.Abs(_speed) * _exame.Model.Configurações.FrameRate);
while (!token.IsCancellationRequested)
{
var current = sw.ElapsedMilliseconds;
var elapsed = current - previous;
if (elapsed > timeInterval)
{
Índice = Math.Max(0, Math.Min(ÍndiceMáximo, Índice + 1 * Math.Sign(_speed)));
previous = current;
}
}
}
This question already has answers here:
High resolution timer in C#
(5 answers)
Closed 3 years ago.
I want to have a timer with about 5millisecond resolution. but the current Timer in .Net has a resolution of about 50ms.
I could not find any working solution that creates a high resolution timer, although some claim that you can do it in C#.
In regards to the information that the OP was specifically asking about the Timer class which fires events at regular intervals. I have amended this answer, with my old answer below the horizontal rule.
I tested the following code with the Timer class, and it seems like it can get at least within the 14 - 15 millisecond range on my machine. Try it out for yourself and see if you can reproduce this. So sub-50 millisecond response times are possible, but it can't get down to exactly one millisecond.
using System;
using System.Timers;
using System.Diagnostics;
public static class Test
{
public static void Main(String[] args)
{
Timer timer = new Timer();
timer.Interval = 1;
timer.Enabled = true;
Stopwatch sw = Stopwatch.StartNew();
long start = 0;
long end = sw.ElapsedMilliseconds;
timer.Elapsed += (o, e) =>
{
start = end;
end = sw.ElapsedMilliseconds;
Console.WriteLine("{0} milliseconds passed", end - start);
};
Console.ReadLine();
}
}
NB: The following is my old answer, when I thought the OP was talking about timing things. The following is merely useful information with respect to timing the duration of things, but doesn't provide any way of firing events at a regular interval. For that purpose, the Timer class is necessary.
Try using the Stopwatch class within System.Diagnostics: http://msdn.microsoft.com/en-us/library/system.diagnostics.stopwatch.aspx
You can query it to check if it's high resolution through it's IsHighResolution field. Also, you can check the exact resolution of the Stopwatch:
int resolution = 1E9 / Stopwatch.Frequency;
Console.WriteLine("The minimum measurable time on this system is: {0} nanoseconds", resolution);
If you're worried about where this is actually sourced, the documentation seems to imply that it actually internally calls the lower level Win32 functions:
The Stopwatch class assists the manipulation of timing-related
performance counters within managed code. Specifically, the Frequency
field and GetTimestamp method can be used in place of the unmanaged
Win32 APIs QueryPerformanceFrequency and QueryPerformanceCounter.
What about this one?
public class HiResTimer
{
private bool isPerfCounterSupported = false;
private Int64 frequency = 0;
// Windows CE native library with QueryPerformanceCounter().
private const string lib = "coredll.dll";
[DllImport(lib)]
private static extern int QueryPerformanceCounter(ref Int64 count);
[DllImport(lib)]
private static extern int QueryPerformanceFrequency(ref Int64 frequency);
public HiResTimer()
{
// Query the high-resolution timer only if it is supported.
// A returned frequency of 1000 typically indicates that it is not
// supported and is emulated by the OS using the same value that is
// returned by Environment.TickCount.
// A return value of 0 indicates that the performance counter is
// not supported.
int returnVal = QueryPerformanceFrequency(ref frequency);
if (returnVal != 0 && frequency != 1000)
{
// The performance counter is supported.
isPerfCounterSupported = true;
}
else
{
// The performance counter is not supported. Use
// Environment.TickCount instead.
frequency = 1000;
}
}
public Int64 Frequency
{
get
{
return frequency;
}
}
public Int64 Value
{
get
{
Int64 tickCount = 0;
if (isPerfCounterSupported)
{
// Get the value here if the counter is supported.
QueryPerformanceCounter(ref tickCount);
return tickCount;
}
else
{
// Otherwise, use Environment.TickCount.
return (Int64)Environment.TickCount;
}
}
}
static void Main()
{
HiResTimer timer = new HiResTimer();
// This example shows how to use the high-resolution counter to
// time an operation.
// Get counter value before the operation starts.
Int64 counterAtStart = timer.Value;
// Perform an operation that takes a measureable amount of time.
for (int count = 0; count < 10000; count++)
{
count++;
count--;
}
// Get counter value when the operation ends.
Int64 counterAtEnd = timer.Value;
// Get time elapsed in tenths of a millisecond.
Int64 timeElapsedInTicks = counterAtEnd - counterAtStart;
Int64 timeElapseInTenthsOfMilliseconds =
(timeElapsedInTicks * 10000) / timer.Frequency;
MessageBox.Show("Time Spent in operation (tenths of ms) "
+ timeElapseInTenthsOfMilliseconds +
"\nCounter Value At Start: " + counterAtStart +
"\nCounter Value At End : " + counterAtEnd +
"\nCounter Frequency : " + timer.Frequency);
}
}
I found a solution to this problem in the following blog:
http://web.archive.org/web/20110910100053/http://www.indigo79.net/archives/27#comment-255
It tells you how to use the multimedia timer to have a timer with high frequency. It is working just fine for me!!!
Here is an implementation based on StopWatch timer
https://gist.github.com/DraTeots/436019368d32007284f8a12f1ba0f545
It works on all platforms and is high precision wherever StopWatch.IsHighPrecision == true
Its Elapsed event is guaranteed to be non overlapping (which might be important to know, because state changes inside the event handler may be left unprotected against multi threaded access)
Here is how to use it:
Console.WriteLine($"IsHighResolution = {HighResolutionTimer.IsHighResolution}");
Console.WriteLine($"Tick time length = {HighResolutionTimer.TickLength} [ms]");
var timer = new HighResolutionTimer(0.5f);
// UseHighPriorityThread = true, sets the execution thread
// to ThreadPriority.Highest. It doesn't provide any precision gain
// in most of the cases and may do things worse for other threads.
// It is suggested to do some studies before leaving it true
timer.UseHighPriorityThread = false;
timer.Elapsed += (s, e) => { /*... e.Delay*/ }; // The call back with real delay info
timer.Start();
timer.Stop(); // by default Stop waits for thread.Join()
// which, if called not from Elapsed subscribers,
// would mean that all Elapsed subscribers
// are finished when the Stop function exits
timer.Stop(joinThread:false) // Use if you don't care and don't want to wait
Here is a benchmark (and a live example):
https://gist.github.com/DraTeots/5f454968ae84122b526651ad2d6ef2a3
The results of setting the timer for 0.5 ms on Windows 10:
It is also worth to mention that:
I had the same precision on mono on Ubuntu.
While playing with the benchmark, the maximum and a very rare deviation I saw was about 0.5 ms
(which probably means nothing, it is not realtime systems, but still worth mentioning)
Stopwatch ticks are not TimeSpan ticks. On that Windows 10 machine
HighResolutionTimer.TickLength is 0.23[ns].
CPU usage of the benchmark is 10% for 0.5ms interval and 0.1% for 200ms interval
Pretty late to the party still might be useful for someone looking for an answer as nothing has been changed for over a decade in the topic.
Background
Any .NET delay instructions would always come down to system clock resolution, the one you set with timeBeginPeriod(). No matter if it's a Thread.Sleep(N), Threading.Timer or Waitable.WaitOne(N). Yet time resolution of DateTime.Now() and System.Diagnostic.Stopwatch is way higher so there is a way of implementing precise timing events known as hot loop. Hot loops yet prone to being threatened badly by OS since those tend to occupy processor core at full. And here's what we do to prevent this:
Surrender thread time quant in a hot loop to other threads once there's no more need for it by calling Thread.Sleep(0) or .WaitOne(0)
Below is a code piece showing simple implementation of high resolution scheduler:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
/// <summary>
/// High resolution scheduler.
/// License: public domain (no restrictions or obligations)
/// Author: Vitaly Vinogradov
/// </summary>
public class HiResScheduler : IDisposable
{
/// <summary>
/// Scheduler would automatically downgrade itself to cold loop (Sleep(1)) when there are no
/// tasks earlier than the treshold.
/// </summary>
public const int HOT_LOOP_TRESHOLD_MS = 16;
protected class Subscriber : IComparable<Subscriber>, IComparable
{
public Action Callback { get; set; }
public double DelayMs { get; set; }
public Subscriber(double delay, Action callback)
{
DelayMs = delay;
Callback = callback;
}
public int CompareTo(Subscriber other)
{
return DelayMs.CompareTo(other.DelayMs);
}
public int CompareTo(object obj)
{
if (ReferenceEquals(obj, null))
return -1;
var other = obj as Subscriber;
if (ReferenceEquals(other, null))
return -1;
return CompareTo(other);
}
}
private Thread _spinner;
private ManualResetEvent _allowed = new ManualResetEvent(false);
private AutoResetEvent _wakeFromColdLoop = new AutoResetEvent(false);
private bool _disposing = false;
private bool _adding = false;
private List<Subscriber> _subscribers = new List<Subscriber>();
private List<Subscriber> _pendingSubscribers = new List<Subscriber>();
public bool IsActive { get { return _allowed.WaitOne(0); } }
public HiResScheduler()
{
_spinner = new Thread(DoSpin);
_spinner.Start();
}
public void Start()
{
_allowed.Set();
}
public void Pause()
{
_allowed.Reset();
}
public void Enqueue(double delayMs, Action callback)
{
lock (_pendingSubscribers)
{
_pendingSubscribers.Add(new Subscriber(delayMs, callback));
_adding = true;
if (delayMs <= HOT_LOOP_TRESHOLD_MS * 2)
_wakeFromColdLoop.Set();
}
}
private void DoSpin(object obj)
{
var sw = new Stopwatch();
sw.Start();
var nextFire = null as Subscriber;
while (!_disposing)
{
_allowed.WaitOne();
if (nextFire != null && sw.Elapsed.TotalMilliseconds >= nextFire?.DelayMs)
{
var diff = sw.Elapsed.TotalMilliseconds;
sw.Restart();
foreach (var item in _subscribers)
item.DelayMs -= diff;
foreach (var item in _subscribers.Where(p => p.DelayMs <= 0).ToList())
{
item.Callback?.Invoke();
_subscribers.Remove(item);
}
nextFire = _subscribers.FirstOrDefault();
}
if (_adding)
lock (_pendingSubscribers)
{
_subscribers.AddRange(_pendingSubscribers);
_pendingSubscribers.Clear();
_subscribers.Sort();
_adding = false;
nextFire = _subscribers.FirstOrDefault();
}
if (nextFire == null || nextFire.DelayMs > HOT_LOOP_TRESHOLD_MS)
_wakeFromColdLoop.WaitOne(1);
else
_wakeFromColdLoop.WaitOne(0);
}
}
public void Dispose()
{
_disposing = true;
}
}
The system clock "ticks" at a constant rate. In order to raise the accuracy of timer dependent function*s, call **timeGetDevCaps* which determines the minimum supported timer resolution.
Then call timeBeginPeriod setting the timer resolution to its minimum.
Caution: By invoking timeBeginPeriod, other timer dependent function can be significantly affected such as the system clock, system power usage, and the scheduler. Thus start your application with timeBeginPeriod and end it with timeEndPeriod
The previous example doesn't work unless the frequency is in milliseconds; the perf timer frequency is rarely in ms.
private static Int64 m_iPerfFrequency = -1;
public static double GetPerfCounter()
{
// see if we need to get the frequency
if (m_iPerfFrequency < 0)
{
if (QueryPerformanceFrequency(out m_iPerfFrequency) == 0)
{
return 0.0;
}
}
Int64 iCount = 0;
if (QueryPerformanceCounter(out iCount) == 0)
{
return 0.0;
}
return (double)iCount / (double)m_iPerfFrequency;
}
[DllImport("kernel32.dll", SetLastError = true)]
public static extern int QueryPerformanceCounter(out Int64 iCount);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern int QueryPerformanceFrequency(out Int64 iFrequency);
This returns the perf counter in seconds. The reason you'd use the perf timer is to share a timer with legacy C++ code, or get a more precise timer than the C# StopWatch class.
You could use QueryPerformanceCounter() and QueryPerformanceTimer() as outlined in this article.