-
Notifications
You must be signed in to change notification settings - Fork 5k
System Timer with 1 millisecond interval. #67088
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label. |
Tagging subscribers to this area: @mangod9 Issue DetailsSystem timers that can be called once every 1 millisecond.This is very difficult to do at the moment,. especially when it comes to cross-platform. As you can see, for small intervals, 15.6 ms is the best average. As you know, this is the standard Windows system timer resolution, which you can read in detail in the document from Microsoft called Timers, Timer Resolution, and Development of Efficient Code (http://download.microsoft.com/download/3/0/2/3027d574-c433-412a-a8b6-5e0a75d5b237/timer-resolution.docx)
So as you can see, it cannot be done without using operating system specific functions. or implementing through infinite loop and Task.Wait/Thread.Sleep methods.
|
I don't think Quick test:
Results: (Windows x64) |
I'm not sure this is something we can reliably provide as an API due to differing support of various hardware and Operating Systems/platforms. Maybe something could be provided with some sort of query that indicates whether such functionality is supported. But even then, OS level thread-scheduling and power management functions might get in the way. For reference, on Windows essentially anything needing higher than Some platforms, such as the |
For me it would be good, a new type like MultimediaTimer, which will be able to give intervals of 1ms. |
Would be nice that such feature could be enabled via OS: Windows 11 My understanding so far: After setting 1ms resolution via above APIs: So even though the sleep in timer thread is likely affected correctly by these APIs:
The problem is that the counts used to determine currentTime elapsing have a resolution of ~10-15ms because GetTickCount / GetTickCount64 is used:
Would it be possible to replace |
|
but then how is it done in programs that work with MIDI files, for example? Also, if it's not a documented feature, can't Microsoft document it? |
Many games and other multimedia apps don't use things like Instead they use things like (varying from scenario to scenario of course):
Drivers have access to additional APIs (like |
How about emitting |
Typically when you want to "delay" for a very brief period of time, you emit If you need to wait for a longer period of time, but without giving up your time slice, you'd use the system level fences. This is what DirectX12 and Vulkan use in coordination with the GPU fences. |
|
On Windows you can also use a waitable timer object with See https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-createwaitabletimerexw |
You typically don't want to use The This is also why in games you may not want to use the various built-in |
Yes, also time for call back excecution. |
So, only windows api is the blocker? |
This is not just a Windows limitation, this is a limitation of both hardware and software for almost any platform that might be targeted. Most platforms are not designed or oriented around real time execution, targeting sub millisecond execution is not something that really has any guarantees for most platforms and which often requires additional care and work to make partially possible in the first place |
I'm not advocating that the runtime uses these APIs to change system timers. What the user cannot change is the utilization of low resolution GetTickCount / GetTickCount64 in runtime system timers implementation, hence the ask if there could be a use of QueryPerformanceCounter timers, for example:
|
There are many more considerations than simply increasing the timer resolution or utilizing QPC within a timer. This is something that is going to be application specific and which needs to be considered at the very least thread wide for a given process, but more likely also managed even higher at the general process level. It is not something which can be trivially provided by the BCL. The BCL does, however, already expose all the relevant tools such that an interested user could roll their own scenario specific timer after having invoked the relevant platform specific APIs. |
hello! but i have a question. My platform z790 have a 3 timer resoltion in TSC tick. |
@Slendermid sounds like it could be related to "clock spread spectrum in the BIOS settings", though not sure. |
im thinking about that, because all z690/z790 on ddr4 memory dont have option to disable bclk spread spectrum, but i have a friend with z790 ddr5 board, and same values. |
You're trying to write a driver in C#? Good luck with that - you'd be better off with C/C++ or Rust.
This is an OS/hardware layer concern, and C# doesn't natively provide a way to even get a timer at that resolution, and so we're unlikely to be able to provide something like that in the first place. |
my code in driver: (also im not a good coder) #include <ntddk.h> i know is hardware issue or like that, but if system can get 1000 or 0.9999 randomly (instead of 0.9966) i think we can lock it on 1000. If the system has chosen 0.9966 timer res i can stable it to 1000, but if another programm call timer (1ms), it decrese to 0.9966. Im prefer 0.9999 or 1000 because that values have lowest Kernel Timer Latency. (1-3us vs ~950us). Also RTC tick with always stable 1000 timer res give me 1000us kernel latency. |
Some MS guys just did it for GO on Windows: https://devblogs.microsoft.com/go/high-resolution-timers-windows/ |
So maybe in .NET 10 then ? 😉 |
As per the above, there is a "lot" of complexity in doing this and doing it correctly. It's also not something that can be strictly guaranteed across all systems/hardware and the places it is needed are a bit more niche. Due to all of that, this isn't something I can see getting prioritized for .NET 10. However, there is nothing preventing a 3rd party library from being created that provides the functionality in the meantime. |
I did check the approach from https://devblogs.microsoft.com/go/high-resolution-timers-windows/
This isnt really about .net but more about windows. In dotnet you can get pretty much perfect timers if you use .net8.0 and run it on linux and use one of the mainLine Linux kernels which have the rt patch fully integrated since end of last year. (Provided your cpu has plenty of headroom) Small update: |
Wow, thanks for this amazing info! |
I now did clean the code a bit and created a semi clean version which is also on nuget: https://www.nuget.org/packages/QuickTickLib/ Just be aware that for the timer the event code is currently executed within the internal timing loop as i couldnt get a clean solution for that. The timer is set up in a way that it holds the interval provided as an average and is normaly accurate to within 1ms. Sleeping or delaying for one 1ms typically is more around 1.5ms which i guess is way better than 15.6ms Update (April 12th 2025): cleanup up that package so its pretty much safe to use now. |
System timers that can be called once every 1 millisecond.
This is very difficult to do at the moment,. especially when it comes to cross-platform.
Perhaps we should add such a high-precision system timer, it will come in handy for games or playing MIDI file.
As you can see, for small intervals, 15.6 ms is the best average. As you know, this is the standard Windows system timer resolution, which you can read in detail in the document from Microsoft called Timers, Timer Resolution, and Development of Efficient Code (http://download.microsoft.com/download/3/0/2/3027d574-c433-412a-a8b6-5e0a75d5b237/timer-resolution.docx)
So as you can see, it cannot be done without using operating system specific functions. or implementing through infinite loop and Task.Wait/Thread.Sleep methods.
The text was updated successfully, but these errors were encountered: