c# - Achieving realtime 1 millisecond accurate events without suffering from thread scheduling -
problem
i creating windows 7 based c# wpf application using .net 4.5, , 1 major features call functions interface custom hardware set of user defined cycle times. example user might choose 2 functions called every 10 or 20 milliseconds , every 500 milliseconds. the smallest cycle time user can choose 1 milliseconds.
at first seemed timings accurate , functions called every 1 millisecond required. later noticed 1-2% of timings not accurate, functions called 5 milliseconds late, , others reach 100 milliseconds late. cycle times greater 1 msec, faced problem thread slept @ time should have called external function (a 20 msecs function called 50 msecs late because thread sleeping , didnt call function)
after analysis concluded these delays sporadic, no noticeable pattern, , main possible reason behind these delays os scheduling , thread context switching, in other words our thread wasn't awake time need be.
as windows 7 not rtos, need find if can work around problem somehow. know sure problem fixable on windows, use other tools similar functionality can meet timing constraints maximum of 0.7 ms error tolerance.
our application multithreaded maximum of 30 threads running @ same , current peak cpu usage 13%
attempted solutions
we tried many different things, timing measured using stopwatch timer , ishighresolution true( other timers used did not notice difference):
1) creating separate thread , giving high priority - result: ineffective (using both terrible thread.sleep, , without , using continuous polling)
2) using c# task (thread pool), result: very little improvement
3) using multimedia timer 1ms periodicity, result: ineffective or worse, multimedia timers accurate @ waking os, os may choose run thread, no 1ms guarantee, then, delays bigger 4) created separate standalone c# project contained while loop , stopwatch timer, result: of time accuracy great even in microseconds, but thread sleeps 5) repeated point 4, set process priority realtime/high, result: very numbers, not single message had significant delay.
conclusion:
from previous found had 5 possible courses of action, need knowledgeable experience in such problems point in right direction:
1) our tool can optimized , threads managed somehow insure 1ms realtime requirement. maybe part of optimization setting process priority of tool high or realtime, not seem wise decisions, users using several other tools @ same time.
2) divide our tool 2 processes, 1 contains gui , non time critical operations, , other containing minimal amount of time critical operations , set high/real time priority, , use ipc (like wcf) communication between processes. benefit in 2 ways, 1. less probability of starvation other processes less operations happening. 2. process have less threads (much less or no) probability of thread sleeping
note: next 2 points deal kernel space, please note have little information kernel space , writing drivers, might making wrong assumptions how used.
3) creating driver in kernel space uses lower level interrupts every 1ms fire event forces thread perform designated task in process.
4) moving time critical components kernel space, interfacing main body of programs done through apis , callbacks.
5) perhaps of these not valid, , might need use windows rtos extension intervalzero rtos platform ?
the question itself
there 2 answers looking for, , hope backed sources.
1) threading , context switching problem ? or have been missing of time ?
2) of 5 options guaranteed fix problem, , if several are, easiest ? if none of these options can fix it, can? please remember other tools have bench-marked indeed reach required timing accuracy on windows, , when cpu under heavy load, 1 or 2 timings out of 100,000 off less 2 milliseconds, acceptable.
which of 5 options guaranteed fix problem?
this depends on accuracy trying achieve. if you're aiming +/- 1ms, have reasonable chance done without points 3) 5). combination of points 1) , 2) way go:
- split code time critical parts , less time critical parts (gui etc.) , put them separate processes. let them comunicate means of decent ipc (pipes, shared memory, , alike).
- raise process priority class , thread priority of time critical process. unfortunately, c# threadpriority enumeration permits
thread_priority_highest(2)
maximimum priority. therefore you'd have setthreadpriority function allows accessthread_priority_time_critical (15)
. process::priorityclass property allows accessrealtime_priority_class (24)
. note: code running @ such priorities push other code out of way. you'd have make code littly computation , very safe. - use processthread::processoraffinity property adjust proper core usage. hint: may want keep time critical threads away cpu_0 (property value 0x0001) because windows kernel prefers cpu specific operations. example: on platform 4 logical processors you'd specifiy processoreaffinity property 0x000e exclude cpu_0.
- the systems timer resolution set other applications. therefore, predictable when dictate systems timer resolution. applications/drivers set timer resolution 0.5ms. may beyond youre setting , can lead hiccups in application. see this answer on how set timer resolution 0.5ms. (note: support of resolution platform dependent.)
general remarks: depends on load. windows can pretty despite fact not "realtime os". however, realtime systems rely on low load. nothing guaranteed, not on rt-os when heavily loaded.
Comments
Post a Comment