OK, that title was perhaps vague, but allow me to explain.
I'm dealing with a large list, of hundreds of messages to be sent to a CAN bus as byte arrays. Each of these messages has an Interval property detailing how often the message must be sent, in milliseconds. But I'll get back to that.
So I have a thread. The thread loops through this giant list of messages until stopped, with the body roughly like this:
Stopwatch timer = new Stopwatch();
sw.Start();
while(!ShouldStop)
{
foreach(Message msg in list)
{
if(msg.IsReadyToSend(timer)) msg.Send();
}
}
This works great, with phenomenal accuracy in honoring the Message objects' Interval. However, it hogs an entire CPU. The problem is that, because of the massive number of messages and the nature of the CAN bus, there is generally less than half a millisecond before the thread has to send another message. There would never be a case the thread would be able to sleep for, say, more than 15 milliseconds.
What I'm trying to figure out is if there is a way to do this that allows for the thread to block or yield momentarily, allowing the processor to sleep and save some cycles. Would I get any kind of accuracy at all if I try splitting the work into a thread per message? Is there any other way of doing this that I'm not seeing?
EDIT: It may be worth mentioning that the Message's Interval property is not absolute. As long as the thread continues to spew messages, the receiver should be happy, but if the thread regularly sleeps for, say, 25 ms because of higher priority threads stealing its time-slice, it could raise red flags for the receiver.
Based on the updated requirement there is very good chance that default setup with Sleep(0) could be enough - messages may be sent in small bursts, but it sounds like is ok. Using multimedia timer may make burst less noticeable. Building more tolerance to receiver of the messages may be better approach (if possible).
If you need hard milliseconds accuracy with good guarantees - C# on Windows is not the best choice - separate hardware (even Adruino) may be needed, or at least lower level code that C#.
Windows is not RT OS, so you can't really get sub-millisecond accuracy.
Busy loop (possibly on high-pri thread) as you have is common approach if you need sub-millisecond accuracy.
You can try using Multimedia timers (sample - Multimedia timer interrupts in C# (first two interrupts are bad)), as well to change default time slice to 1ms (see Why are .NET timers limited to 15 ms resolution? for sample/explanation).
In any case you should be aware that your code can loose its time-slice if there are other higher priority threads to be scheduled and all your efforts would be lost.
Note: you obviously should consider if more sensible data structure is more suitable (i.e. heap or priority queue may work better to find next item).
As you have discovered, the most accurate way to "wait" on a CPU is to poll the RTC. However that is computationally intensive. If you are needing to get to the clock accuracy in timing, there is no other way.
However, in your original post, you said that the timing was in the order of 15ms.
On my 3.3GHz Quad Core i5 at home, 15ms x 3.3GHz = 50 Million Clock cycles (or 200 million if you count all the cores).
That is an eternity.
Loose sleep timing is most likely more than accurate enough for your purposes.
To be frank if you needed Hard RT, C# on the .net VM running on the .net GC on the Windows Kernel is the wrong choice.
Related
I am developing an application which analyses real-time financial data. Currently my main computational cycle has the following design:
long cycle_counter=0;
while (process_data)
{
(analyse data, issue instruction - 5000 lines of straightforwasrd code with computations)
cycle_counter++;
Thread.Sleep(5);
}
When I run this application on my notebook (one Core i5) processor, the cycle runs 200-205 times per second - a sort of as expected (if you don't bother about why it runs more than 200 times a second).
But when I deploy the application on "real" workstation, which has 2 6-core Xeon processors and 24 GB of fast RAM, and which loads Win7 in about 3 seconds, the application runs the cycle about 67 times per second.
My questions are:
why is this happening?
how can I influence the number of runs per second in this situation?
are there any better solutions for running the cycle 200-1000 times per second? I am now thinking about just removing Thread.Sleep() (the way I use it here is criticised a lot). With 12 cores I have no problems using one core just for this cycle. But there my be some downside to such solution?
Thank you for your ideas.
The approach you're taking is simply fundamentally broken. Polling strategies are in general a bad way to go, and any time you do a Sleep for a reason other than "I want to give the rest of my timeslice back to the operating system", you're probably doing something wrong.
A better way to approach the problem is:
Make a threadsafe queue of unprocessed work
Make one thread that puts new work in the queue
Make n threads that take work out of the queue and do the work. n should be the number of CPUs you have minus one. If you have more than n threads then at least two threads are trading off CPU time, which is making them both slower!
The worker threads do nothing but sit in a loop taking work out of the queue and doing the work.
If the queue is empty then the "take work out" blocks.
When new work arrives, one of the blocked threads is reactivated.
How to build a queue with these properties is a famous problem called The Producer/Consumer Problem. There are lots of articles on how to do it any many implementations of blocking producer-consumer queues. I recommend finding an existing debugged one rather than trying to write your own; getting it right can be tricky.
Windows is not a RTOS (Real Time Operating System), so you cannot precisely determine when your thread will resume. Thread.Sleep(5) really means "wake me up no sooner then 5ms". The actual sleep time is determined by the specific hardware and mostly by the system load. You can try to workaround the system load issue by running your application on a higher priority.
BTW, System.Threading.Timer is a better approach (above comments still apply though).
The resolution of Sleep is dictated by the current timer tick interval and is usually either 10 or 15 milliseconds depending on the edition of Windows. This can be changed, however, by issuing a timeBeginPeriod command. See this answer.
Check your timer's actual frequency: many hardware timers have actual resolution
65536 ticks per hour = 65536 / 3600 = 18.204 ticks per second
So called "18.2" constant, that's why the actual timer's resolution is 1/18.2 = 55 ms; in the case of Sleep(5) it means that is could be either Sleep(0) or Sleep(55) depending on round up.
Not sure it is the best approach but another approach.
Try BlockingCollection and all you do in the producer is add and sleep.
The consumer then has the option to work full time if needed.
This still does not explain why the higher powered PC ran less cycles.
Is it OK for you to run your loop 200 times per second on average?
var delay = TimeSpan.FromMillseconds(5);
while (process_data) {
Console.WriteLine("do work");
var now = DateTime.Now;
if (now < nextDue)
System.Threading.Thread.Sleep(nextDue - now);
nextDue = nextDue.Add(delay);
}
Using this technique, your loop will execute somewhat stumbling, but it should be OK on average, as the code depends neither on the resolution of Sleep nor on the resolution of DateTime.Now.
You might even combine this approach with a Timer.
I've started the a desktop app development in C# (VS2010 .Net Fw 4.0) involving several timers.
At first, I was using System.Timers in order to send data by USB to a data bus. My point is that I need to send different periodic binary messages with several specific intervals of time such as 10ms, 20ms, 40ms, 100ms, 500ms, 1000ms ....
In each timer I have a callback function who has to send the correct data flow for each raised event.
The problem is when I have the full amount of signals working, the real interval is different than expected (3000ms raises to 3500, 100ms to 340) because when I add the 10ms to 40ms timers, the cpu is overload almost 100% and loses all the precission.
I'm working in VMWare with 2GB RAM and 2CPU cores. The Host machine is an i7-2600K CPU # 3,40GHz. I think this is no the problem.(but I think).
Before I wrote here, i was looking for an answer about how to be more exact with timing, using the most optimized resource consumption. but all I found it was unespecific.
I already knows about System.Diagnostics.Stopwatch reading about it here but this class have not events. Also System.Windows.Forms.Timer but is more imprecise, and with low resolution.
There is a good implementation here with microseconds resolution but it is the reason of my overloading CPU!
What do you think about my further steps!? I'll appreciate any help or idea you have
10% timing resolution is the goal in 10ms' interval!
I will clarify any extra info you need!
Every n*x milliseconds I perform an action where n = 0, 1, 2, ...; x is some increment.
Example - every 25 milliseconds I perform a calculation.
This action can take fewer than x seconds for each increment. As a result, I need a way in C# to wait the remaining (x - actual_time) milliseconds.
Example - if the calculation only takes 20 milliseconds, I need to wait 5 more milliseconds before re-running the calculation.
Please advise.
Thanks,
Kevin
I need a way in C# to wait the remaining (x - actual_time) milliseconds.
I presume that is C# running on Windows.
And there is your problem. Windows is not a "realtime" operating system.
The best you can do if you need millisecond-grade timing precision is to set the thread priority of your thread extremely high, and then busy-wait while querying the high performance timer (Stopwatch).
You cannot yield to another thread; the other thread could run for as much as 16 milliseconds before the operating system context switches it, and of course unless you are the highest priority thread, you have no guarantee that control is coming back to you after those 16 milliseconds are up.
Now, setting thread priority high and then busy waiting is one of the most rude things you can possibly do; essentially you will be taking control of the user's machine and not allowing them to do anything else with it.
Therefore what I would do is abandon this course of action entirely. Either, (1) consider obtaining an operating system designed for realtime process control if that is in fact your application, rather than an operating system designed for multitasking a bunch of line-of-business applications. Or (2) abandon your requirement that the action happen exactly every 25 milliseconds. Just perform the calculation once and yield the remainder of your quantum to another thread. When you get control back, see if more than 25 ms has passed since you yielded; if it has not, yield again. If it has, start over and perform the calculation.
That level of accuracy will be very difficult to achieve in a non real-time operating system like Windows. Your best bet might be to look into the multimedia timers.
The other .NET timers won't have the kind of resolution your need.
At 25ms, you may be the wrong side of the resolution of your available timers in .Net.
However - as a general solution I'd probably attempt this a different way to your "do calculation..wait until 25ms has passed" approach.
A better way may well be to use a System.Timers.Timer, on a 25ms trigger, to trigger the calculation.
var timer = new Timer(25);
timer.Elapsed += (sender, eventArgs) =>
{
DoCalc();
};
timer.Start();
In the above example, a DoCalc method will be called every 25 ms (timer resolution issues notwithstanding). You would need to consider what to do if your calculation overran it's allotted time though. As it stands, the above code would allow a second calculation to start, even if the previous had not completed.
This is a difficult one, and your options are fairly limited, as Eric Lippert and Matt Burland indicate. Basically, you can either
resort to using multimedia timers (google "multimedia timer component" or "winmm.dll"), which, although supporting time resolutions down to 0.500 ms, are no longer recommended as of Windows Vista, require Win32 interop and may bump up your CPU usage quite noticeably, or
come up with an approximated time slicing algorithm that will use the standard timer (whose resolution is usually 15.625 ms on multicore desktops), dynamically varying the timer interval upon each tick based on the difference of desired and actual time elapsed since the last timer tick (you can measure this fairly accurately using high resolution CPU performance counters, e.g. the Stopwatch class).
The latter solution will statistically give you a 40Hz timer in your sample use case, but you'll have significant jitter due to the low resolution of the timer you are using.
This is the tradeoff, the call is yours to make.
Here's a high-precision timer I wrote. I get roughly <1ms avg precision on 25ms interval. But if Windows is busy it may come in late. It's fairly lean on CPU utilization. Feel free to use. It uses Sleep(1) when the next tick is more than 15ms away and then SpinUntil (which yields as needed) to keep CPU usage at bay. Uses .NET4 features.
Link: High Precision Timer
Is there a simple way to determine how many milliseconds I need to "Sleep" for in order to "emulate" a 2 mhz speed. In other words, I want to execute an instruction, call System.Threading.Thread.Sleep() function for an X amount of milliseconds in order to emulate 2 mhz. This doesn't need to be exact to the millisecond, but is there a ball park I can get? Some forumlate that divides the PC clock speed by the 2 mhz or something?
Thanks
A 2 MHz clock has a 500 ns period. Sleep's argument is in milliseconds, so even if you used Sleep(1), you would miss 2,000 cycles.
Worse, Sleep does not promise that it will return after X milliseconds, only that it will return after at least X milliseconds.
Your best bet would be to use some kind of Timer with an event that keeps the program from consuming or producing data too quickly.
For the user, a pause of less than 100 ms or so will generally be imperceptible. Based on that, instead of attempting to sleep after each instruction, you'd be much better off executing for something like 50 ms, then sleeping for an appropriate length of time, then executing for another 50 ms.
Also note, however, that most processors with a 2 MHz clock (e.g. a Z80) did not actually execute 2 million instructions per second. A 2 MHz Z80 took a minimum of four processor clocks to fetch one instruction giving a maximum instruction rate of 500 KHz.
Note that sleeping is not at all a good proxy for running code on a less capable CPU. There are many things that affect computational performance other than clock rate. In many cases, clock rate is a second or third (or 10'th) order determinate of computational performance.
Also note that QueryPerformanceCounter() while high resolution is expensive on most systems (3000 to 5000 CPU clocks in many cases). The reason is that it requires a system call and several reads from the HPET in the system's south bridge. (note, this varies by system).
Could you help us better understand what you are trying to do?
As I mentioned in my comment on James Black's answer: do not poll a timer call (like QPC or the direct X stufF). Your thread will simply consume massive amounts of CPU cycles and not let ANY thread at a lower priority run, and will eat up most of the time at its priority. Note that the NT Scheduler does adjust thread priorities. This is called 'boosting'. If your thread is boosted and hits one of your polling loops, then it will almost assuredly cause perf problems. This is very bad behavior from a system perspective. Avoid it if at all possible.
Said another way: Windows is a mult-tasking OS and users run lots of things. Be aware that your app is running in a larger context and its behavior can have system wide implications.
The problem you will have is that the minimum sleep on windows seems to be about 20-50ms, so though you may put that you want to sleep for 1ms, it will wake up later, due to the fact that other processes will be running, and the time slice is quite large.
If you must have a small time such as 500ns (1/2e06 * 1000) then you will want to use DirectX, as it has a high-resolution timer, so that you can just loop until the pause is done, but, you will need to take over the computer, not allow other processes to interrupt what is going on.
I am using the code below
Thread.Sleep(5);
at the end of a while loop. To try and get a 5ms delay between iterations.
Sometimes it sleeps for 16ms. This I understand and accept, since it depends on when the CPU gets around to servicing the thread. However once it has woken the next iteration it seems to wake immediately after the sleep call (I am logging with timestamps). Is there a problem with using such a short sleep interval that it is treated as zero?
Your problem is like that on most modern machines, DateTime.UtcNow has a resolution of about 10-15ms (though I see the documentation says it's about 10ms since NT 3.5). If you want higher resolution timing, see the Stopwatch class, specifically Stopwatch.GetTimestamp().
Also note that Stopwatch will only use the high-resolution timers if they are available (Stopwatch.IsHighResolution will tell you at run-time). If not, it falls back to DateTime.UtcNow.Ticks.
Most likely, the problem is simply that your timer has limited resolution. If it only updates, say, every 10ms, you're going to see the same timestamp on some iterations, even if 5ms have passed.
Which timer are you using to generate your timestamps?
If I remember correctly NT time slicing, which was introduced in the NT kernel and was still active in the same way as of XP, operates right around the 5ms mark. We were building a realtime application and ran in to that problem. You will not be able to consistently get a 5ms sleep time. What we found was that you will sometimes get 10 - 16 ms, sometimes no ms and occasionally yet rarely get 5 ms.
I was doing these tests around 5 years ago though so things may have changed since then.
What sort of system are you running this on? Small intervals can depend on the processor and how high a resolution it supports. I ran an app on a handheld once where the resolution of the timer itself was 16ms. So it may be hardware related. Try increasing the time period to say 30ms and see if it works then.