Hello, Just out of curiosity, I wrote this program to test the latency using a vanilla 3.4 kernel's "real-time scheduler". Maybe it is of interest to someone on this list.
$ uname -srvmp Linux 3.3.8 #7 SMP PREEMPT Tue Jun 26 03:08:40 CEST 2012 x86_64 Intel(R) Core(TM) i3-2120T CPU @ 2.60GHz Tests were made while running a 1080p x264 movie and "shaking" a large glxgears window. Sample running as normal user without permission to change to realtime scheduler, i.e. running under the normal scheduler (SCHED_OTHER): $ ./rt_test Setting SCHED priority 1 Could not set scheduler: Operation not permitted CLOCK_REALTIME resolution: 1 ns Establishing handler for signal 34 timer ID is 0x1ae6010 ... Min, max diff -686, 694 µs; cumulative diff 1990 µs; overruns 0; calls 70913 Min, max diff -827, 1257 µs; cumulative diff 4003 µs; overruns 2; calls 71970 Min, max diff -645, 1193 µs; cumulative diff 4994 µs; overruns 1; calls 73028 Min, max diff -629, 635 µs; cumulative diff 4996 µs; overruns 0; calls 74087 Min, max diff -48, 65 µs; cumulative diff 4997 µs; overruns 0; calls 75146 Min, max diff -29, 34 µs; cumulative diff 4990 µs; overruns 0; calls 76204 Min, max diff -253, 160 µs; cumulative diff 4995 µs; overruns 0; calls 77263 Min, max diff -854, 868 µs; cumulative diff 4996 µs; overruns 0; calls 78323 Min, max diff -812, 1812 µs; cumulative diff 5990 µs; overruns 1; calls 79381 Min, max diff -635, 371 µs; cumulative diff 5990 µs; overruns 0; calls 80441 Min, max diff -536, 540 µs; cumulative diff 6000 µs; overruns 0; calls 81500 Min, max diff -855, 1229 µs; cumulative diff 6988 µs; overruns 1; calls 82558 Min, max diff -305, 435 µs; cumulative diff 7002 µs; overruns 0; calls 83618 Min, max diff -293, 304 µs; cumulative diff 6995 µs; overruns 0; calls 84677 Min, max diff -644, 647 µs; cumulative diff 6993 µs; overruns 0; calls 85737 Sample running under real-time scheduler (SCHED_FIFO): # ulimit -r 1 # ./rt_test Setting SCHED priority 1 CLOCK_REALTIME resolution: 1 ns Establishing handler for signal 34 timer ID is 0x1236010 ... Min, max diff -24, 36 µs; cumulative diff 2 µs; overruns 0; calls 35173 Min, max diff -15, 20 µs; cumulative diff -3 µs; overruns 0; calls 36178 Min, max diff -30, 24 µs; cumulative diff -3 µs; overruns 0; calls 37183 Min, max diff -17, 14 µs; cumulative diff -1 µs; overruns 0; calls 38187 Min, max diff -27, 22 µs; cumulative diff -4 µs; overruns 0; calls 39192 Min, max diff -68, 80 µs; cumulative diff 2 µs; overruns 0; calls 40199 Min, max diff -26, 32 µs; cumulative diff 0 µs; overruns 0; calls 41204 Min, max diff -23, 29 µs; cumulative diff -3 µs; overruns 0; calls 42209 Min, max diff -29, 28 µs; cumulative diff 3 µs; overruns 0; calls 43215 Min, max diff -24, 25 µs; cumulative diff -3 µs; overruns 0; calls 44220 Min, max diff -26, 28 µs; cumulative diff 2 µs; overruns 0; calls 45225 Min, max diff -19, 25 µs; cumulative diff -3 µs; overruns 0; calls 46231 Min, max diff -47, 57 µs; cumulative diff -1 µs; overruns 0; calls 48242 It looks good enough for the servo thread, at least on my computer! Here's the program, in case you want to try it yourself: Compile with $ gcc -Wall -lrt rt_test.c -o rt_test --- /* * Latency/precision test program for POSIX timers under Linux * real-time scheduling (SCHED_FIFO). * * Based on the sample code in 'man 2 timer_create', * copyright (c) 2009 Linux Foundation, written by Michael Kerrisk * <mtk.manpa...@gmail.com> * and released under the "Verbatim" License: * https://www.kernel.org/doc/man-pages/licenses.html#verbatim * * Modifications for this usage by Arvid Brodin <arv...@kth.se>. */ #include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <sched.h> #include <signal.h> #include <time.h> #include <errno.h> #define CLOCKID CLOCK_REALTIME #define SIG SIGRTMIN #define PERIOD 1000000 #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \ } while (0) static inline int min(int a, int b) { return (a < b) ? a : b; } static inline int max(int a, int b) { return (a > b) ? a : b; } /* Global variable to keep track of latency statistics etc. */ static struct { int mindiff; // Maximum negative deviation int maxdiff; // Maximum positive deviation int cumdiff; // Cumulative deviation from first call int calls; // Total number of calls made int overruns; // Number of completely missed calls int last_ns; } period_info; static void print_clockinfo() { struct timespec ts; if (clock_getres(CLOCK_REALTIME, &ts) != 0) { printf("Could not get clock info.\n"); return; } printf("CLOCK_REALTIME resolution: %ld ns\n", ts.tv_nsec); } /* * Print statistics. Called from main loop. */ static void print_diffs() { printf("Min, max diff %5d, %5d µs; cumulative diff %d µs; overruns %d; calls %d\n", period_info.mindiff / 1000, period_info.maxdiff / 1000, period_info.cumdiff / 1000, period_info.overruns, period_info.calls); period_info.mindiff = 0; period_info.maxdiff = 0; period_info.overruns = 0; } static struct sigaction sa; /* * Signal handler. Called every PERIOD ns. */ static void handler(int sig, siginfo_t *si, void *uc) { timer_t *tidp; struct timespec ts; int overruns; int diff; period_info.calls += 1; tidp = si->si_value.sival_ptr; overruns = timer_getoverrun(*tidp); if (overruns > 0) period_info.overruns += overruns; clock_gettime(CLOCKID, &ts); if (period_info.last_ns < 0) // First call period_info.last_ns = ts.tv_nsec - PERIOD; else if (ts.tv_nsec < period_info.last_ns) // Seconds wrapped period_info.last_ns -= 1000000000; diff = ts.tv_nsec - period_info.last_ns - PERIOD; period_info.mindiff = min(period_info.mindiff, diff); period_info.maxdiff = max(period_info.maxdiff, diff); period_info.cumdiff += diff; period_info.last_ns = ts.tv_nsec; } /* * Signal delivery causes system/library calls to return prematurely. * See 'man 7 signal' for details. This function repeatedly call * nanosleep() until (at least) 'sec' seconds has passed. */ static void sigsafe_sleep(int sec) { struct timespec rqtp, rmtp; struct timespec *ts_req, *ts_rem, *ts_tmp; int res; rqtp.tv_sec = sec; rqtp.tv_nsec = 0; ts_req = &rqtp; ts_rem = &rmtp; res = nanosleep(ts_req, ts_rem); while (res < 0 && errno == EINTR) { ts_tmp = ts_req; ts_req = ts_rem; ts_rem = ts_tmp; res = nanosleep(ts_req, ts_rem); } } int main(int argc, char *argv[]) { struct sched_param sched_param; timer_t timerid; struct sigevent sev; struct itimerspec its; int res; const int sched_policy = SCHED_FIFO; // Scheduler sched_param.sched_priority = sched_get_priority_min(sched_policy); printf("Setting SCHED priority %d\n", sched_param.sched_priority); res = sched_setscheduler(0, sched_policy, &sched_param); if (res < 0) perror("Could not set scheduler"); // Some init print_clockinfo(); period_info.mindiff = 0; period_info.maxdiff = 0; period_info.cumdiff = 0; period_info.last_ns = -1; // Establish handler for timer signal printf("Establishing handler for signal %d\n", SIG); sa.sa_flags = SA_SIGINFO; sa.sa_sigaction = handler; sigemptyset(&sa.sa_mask); if (sigaction(SIG, &sa, NULL) == -1) errExit("sigaction"); // Create the timer sev.sigev_notify = SIGEV_SIGNAL; sev.sigev_signo = SIG; sev.sigev_value.sival_ptr = &timerid; if (timer_create(CLOCKID, &sev, &timerid) == -1) errExit("timer_create"); printf("timer ID is 0x%lx\n", (long) timerid); // Start the timer its.it_value.tv_sec = 0; its.it_value.tv_nsec = PERIOD; its.it_interval.tv_sec = its.it_value.tv_sec; its.it_interval.tv_nsec = its.it_value.tv_nsec; if (timer_settime(timerid, 0, &its, NULL) == -1) errExit("timer_settime"); while (1) { sigsafe_sleep(1); print_diffs(); } // Not reached exit(EXIT_SUCCESS); } --- -- Arvid ------------------------------------------------------------------------------ Everyone hates slow websites. So do we. Make your web apps faster with AppDynamics Download AppDynamics Lite for free today: http://p.sf.net/sfu/appdyn_d2d_mar _______________________________________________ Emc-developers mailing list Emc-developers@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/emc-developers