Johan Borkhuis wrote: > Jan, Philippe, > > Attached is my test program, based on cyclictest. I removed all the > unneeded parts, and set all the options to the right values, as used for > my test. I use the PPC8540 internal highres timer, but this can be > disabled by undef-ing the define at the top of the program. > I compiled the program using the same compiler-settings as used by the > latency program. > > The commands I use to run the test are: > /usr/xenomai/bin/latency -P 60 > ./cyclictest-Xenomai -q > > The -q option gives shows the output at the end of the test run, instead > of the running data, to examine all the recorded data add the -v option. > The -h option enables the PPC8540 highres timer. > > This are the results from a test run using the attached > cyclictest-Xenomai and the standard latency test (both are run in > separate terminals): > > bash-3.00# ./cyclictest-Xenomai -q -h #T: 0 P:80 I:10000 O: 0 > C: 100 Min: -3.181 Avg: -0.025 Max: 2.392 > #T: 1 P:79 I:10000 O: 0 C: 100 Min: -1.787 Avg: 1.377 Max: 139.257 > #T: 2 P:78 I:10000 O: 0 C: 100 Min: -1.836 Avg: 5.518 Max: 553.623 > #T: 3 P:77 I:10000 O: 0 C: 100 Min: -1.932 Avg: 3.153 Max: 317.275 > #T: 4 P:76 I:10000 O: 0 C: 100 Min: -1.740 Avg: 0.435 Max: 45.203 > #T: 5 P:75 I:10000 O: 0 C: 100 Min: -1.980 Avg: 0.047 Max: 5.443 > #T: 6 P:74 I:10000 O: 0 C: 100 Min: -2.148 Avg: 0.015 Max: 2.537 > #T: 7 P:73 I:10000 O: 0 C: 100 Min: -1.811 Avg: 0.020 Max: 2.440 > #T: 8 P:72 I:10000 O: 0 C: 100 Min: -1.667 Avg: 0.011 Max: 2.416 > #T: 9 P:71 I:10000 O: 0 C: 100 Min: -1.788 Avg: 0.051 Max: 5.347 > > bash-3.00# /usr/xenomai/bin/latency -P 60 > == Sampling period: 100 us > == Test mode: periodic user-mode task > == All results in microseconds > warming up... > RTT| 00:00:01 (periodic user-mode task, 100 us period, priority 60) > RTH|---lat min|---lat avg|---lat max|-overrun|--lat best|--lat worst > RTD| -5.453| -4.492| -2.090| 0| -5.453| -2.090 > RTD| -5.381| -4.492| 3.699| 0| -5.453| 3.699 > RTD| -5.453| -4.492| -1.321| 0| -5.453| 3.699 > RTD| -5.357| -4.492| 1.201| 0| -5.453| 3.699 > RTD| -5.477| -4.468| 3.003| 0| -5.477| 3.699 > RTD| -5.405| -4.516| 1.417| 0| -5.477| 3.699 > RTD| -5.429| -4.420| 7.207| 0| -5.477| 7.207 > RTD| -5.285| -4.108| 28.588| 0| -5.477| 28.588 > RTD| -5.429| -4.324| 770.282| 10| -5.477| 770.282 > RTD| -5.477| -4.492| 2.210| 10| -5.477| 770.282 > RTD| -5.405| -4.468| -0.504| 10| -5.477| 770.282 > RTD| -5.309| -4.468| -0.312| 10| -5.477| 770.282 > ---|----------|----------|----------|--------|---------------------- > RTS| -5.477| -4.420| 770.282| 10| 00:00:13/00:00:13 > > Kind regards, > Johan Borkhuis > > > ------------------------------------------------------------------------ > > /* > * High resolution timer test software > * > * This program is free software; you can redistribute it and/or > * modify it under the terms of the GNU General Public License Veriosn > * 2 as published by the Free Software Foundation; > * > */ > > #define VERSION_STRING "V 0.11-Xenomai" > > #define USE_PPC8540_TIMER > > #include <getopt.h> > #include <signal.h> > #include <stdlib.h> > #include <stdio.h> > #include <time.h> > #include <unistd.h> > > #include <linux/unistd.h> > > #include <sys/types.h> > #include <sys/mman.h> > > #include <native/task.h> > > #define USEC_PER_SEC 1000000 > #define NSEC_PER_SEC 1000000000 > > /* Must be power of 2 ! */ > #define VALBUF_SIZE 1024*1024 > > /* Struct to transfer parameters to the thread */ > struct thread_param { > int prio; > unsigned long max_cycles; > struct thread_stat *stats; > int bufmsk; > unsigned long interval; > }; > > /* Struct for statistics */ > struct thread_stat { > unsigned long cycles; > unsigned long cyclesread; > double min; > double max; > double act; > double avg; > double *values; > pthread_t thread; > int threadstarted; > RT_TASK task; > unsigned long overruns; > }; > > static int shutdown = 0; > static int hwtimer = 0; > static int priority = 80; > static int num_threads = 10; > static int max_cycles = 100; > static int verbose = 0; > static int quiet = 0; > static int interval = 10000; > > /* > * High res timer for PPC 8540 > * Timebase is running at CCB/8. CCB is running at 333MHz, so TB is running > * at 41.6667 MHz, which results in 24 nsec/tick > */ > #ifdef USE_PPC8540_TIMER > > /* Correction needed: clock is 0.1% off */ > #define TB_TICKS_NSEC ((24.0)*1.001) > > __inline__ unsigned long get_tbl(void) { > unsigned long tbl; > asm volatile("mftb %0" : "=r" (tbl)); > return tbl; > } > > __inline__ unsigned long get_tbu(void) { > unsigned long tbl; > asm volatile("mftbu %0" : "=r" (tbl)); > return tbl; > } > > void timeStampGet(clockid_t which_clock, struct timespec *curtime) > { > unsigned long lo, hi, hi2; > unsigned long long tr; > long double tmpVal; > > if(hwtimer == 0) > { > clock_gettime(which_clock, curtime); > return; > } > > do { > hi = get_tbu(); > lo = get_tbl(); > hi2 = get_tbu(); > } while (hi2 != hi); > > tr = ((unsigned long long) hi << 32) | lo; > tmpVal = (((long double)tr)*TB_TICKS_NSEC)/1000000000.0; > curtime->tv_sec = (int)tmpVal; > curtime->tv_nsec = (int)((tmpVal - (int)tmpVal) * 1000000000); > } > #else > void timeStampGet(clockid_t which_clock, struct timespec *curtime) > { > clock_gettime(which_clock, curtime); > return; > } > #endif > > static inline void tsnorm(struct timespec *ts) > { > while (ts->tv_nsec >= NSEC_PER_SEC) { > ts->tv_nsec -= NSEC_PER_SEC; > ts->tv_sec++; > } > } > > static double calcdiff(struct timespec t1, struct timespec t2) > { > double diff; > diff = USEC_PER_SEC * ((int) t1.tv_sec - (int) t2.tv_sec); > diff += ((int) t1.tv_nsec - (int) t2.tv_nsec) / 1000.0; > return diff; > } > > /* > * timer thread > * > */ > void timerthread(void *param) > { > struct thread_param *par = param; > struct timespec now, next, interval; > struct thread_stat *stat = par->stats; > int n = 1; > RTIME start_ticks; > RT_TIMER_INFO timer_info; > int err; > > interval.tv_sec = par->interval / USEC_PER_SEC; > interval.tv_nsec = (par->interval % USEC_PER_SEC) * 1000; > > err = rt_timer_inquire(&timer_info); > if (err) { > fprintf(stderr, "latency: rt_timer_inquire, code %d\n", err); > return; > } > > start_ticks = timer_info.date + rt_timer_ns2ticks(1000000); > err = rt_task_set_periodic(NULL, start_ticks, > rt_timer_ns2ticks(par->interval * 1000)); > if (err) { > fprintf(stderr, "latency: failed to set periodic, code %d\n", err); > return; > } > > /* Get current time */ > timeStampGet(CLOCK_MONOTONIC, &now); > next = now; > next.tv_sec++; > > stat->threadstarted++; > > while (!shutdown) { > double diff; > unsigned long ov; > > if (rt_task_wait_period(&ov)) > break; > stat->overruns += ov; > > timeStampGet(CLOCK_MONOTONIC, &now); > if (n) { n= 0; } /* Ignore first period */ > else { > diff = calcdiff(now, next); > if (diff < stat->min) > stat->min = diff; > if (diff > stat->max) > stat->max = diff; > stat->avg += diff; > > stat->act = diff; > > stat->cycles++; > > if (par->bufmsk) > stat->values[stat->cycles & par->bufmsk] = diff; > } > > next.tv_sec = now.tv_sec + interval.tv_sec; > next.tv_nsec = now.tv_nsec + interval.tv_nsec; > tsnorm(&next); > > if (par->max_cycles && par->max_cycles == stat->cycles) > break; > } > > stat->threadstarted = -1; > return; > } > > /* Print usage information */ > static void display_help(void) > { > printf("cyclictest_xenomai %s\n", VERSION_STRING); > printf("Usage:\n" > "cyclictest <options>\n\n" > "-h --hwtimer use hardware timer\n" > "-i INTV --interval=INTV base interval of thread in us > default=1000\n" > "-l LOOPS --loops=LOOPS number of loops: default=100\n" > "-p PRIO --prio=PRIO priority of highest prio thread: > default=80\n" > "-q --quiet print only a summary on exit\n" > "-t NUM --threads=NUM number of threads: default=10\n" > "-v --verbose output values on stdout for > statistics\n" > " format: n:c:v n=tasknum c=count > v=value in us\n" > ); > exit(0); > } > > /* Process commandline options */ > static void process_options (int argc, char *argv[]) > { > int error = 0; > for (;;) { > int option_index = 0; > /** Options for getopt */ > static struct option long_options[] = { > {"hwtimer", no_argument, NULL, 'h'}, > {"interval", required_argument, NULL, 'i'}, > {"loops", required_argument, NULL, 'l'}, > {"priority", required_argument, NULL, 'p'}, > {"quiet", no_argument, NULL, 'q'}, > {"threads", required_argument, NULL, 't'}, > {"verbose", no_argument, NULL, 'v'}, > {"help", no_argument, NULL, '?'}, > {NULL, 0, NULL, 0} > }; > int c = getopt_long (argc, argv, "hi:l:p:qt:vx", > long_options, &option_index); > if (c == -1) > break; > switch (c) { > case 'h': hwtimer = 1; break; > case 'i': interval = atoi(optarg); break; > case 'l': max_cycles = atoi(optarg); break; > case 'p': priority = atoi(optarg); break; > case 'q': quiet = 1; break; > case 't': num_threads = atoi(optarg); break; > case 'v': verbose = 1; break; > case '?': error = 1; break; > } > } > > if (priority < 0 || priority > 99 || num_threads < 1) > error = 1; > > if (error) > display_help (); > } > > static void sighand(int sig) > { > shutdown = 1; > } > > static void print_stat(struct thread_param *par, int index, int verbose) > { > struct thread_stat *stat = par->stats; > > if (!verbose) { > if (quiet != 1) { > printf("%cT:%2d P:%2d I:%ld O:%4ld C:%7lu " > "Min:%10.3lf Avg:%10.3lf Max:%10.3lf \n", > quiet == 2 ? '#' : ' ', > index, par->prio, par->interval, > stat->overruns, stat->cycles, stat->min, > stat->cycles ? > stat->avg/stat->cycles : 0, stat->max); > } > } > } > > int main(int argc, char **argv) > { > struct thread_param *par; > struct thread_stat *stat; > int i, ret = -1; > char task_name[16]; > > if (geteuid()) { > printf("need to run as root!\n"); > exit(-1); > } > > process_options(argc, argv); > > /* Lock all pages from being swapped out */ > if (mlockall(MCL_CURRENT|MCL_FUTURE) != 0) { > perror("mlockall"); > exit(1); > } > > signal(SIGINT, sighand); > signal(SIGTERM, sighand); > > par = calloc(num_threads, sizeof(struct thread_param)); > if (!par) > goto out; > stat = calloc(num_threads, sizeof(struct thread_stat)); > if (!stat) > goto outpar; > > for (i = 0; i < num_threads; i++) { > if (verbose) { > stat[i].values = calloc(VALBUF_SIZE, sizeof(double)); > if (!stat[i].values) > goto outall; > par[i].bufmsk = VALBUF_SIZE - 1; > } > > par[i].prio = priority; > if (priority) > priority--; > par[i].interval = interval; > par[i].max_cycles = max_cycles; > par[i].stats = &stat[i]; > stat[i].min = 1000000.0; > stat[i].max = -1000000.0; > stat[i].avg = 0.0; > snprintf(task_name, sizeof(task_name), "TimerTest-%d", i+1); > if((rt_task_create(&stat[i].task, task_name, 0, priority, T_FPU)) || > (rt_task_start(&stat[i].task, &timerthread, &par[i]))) > goto outall; > stat[i].threadstarted = 1; > } > > while (!shutdown) { > int allstopped = 0; > > for (i = 0; i < num_threads; i++) { > print_stat(&par[i], i, verbose); > if(max_cycles && stat[i].cycles >= max_cycles) > allstopped++; > } > usleep(10000); > if (shutdown || allstopped) > break; > if (!verbose && !quiet) > printf("\033[%dA", num_threads); > } > ret = 0; > > outall: > shutdown = 1; > usleep(50000); > > if (verbose) { > for (i = 0; i < num_threads; i++) { > unsigned int j; > if(par[i].stats->cycles > VALBUF_SIZE) > par[i].stats->cycles = VALBUF_SIZE; > j = 0; > > while (par[i].stats->cycles != j) { > double diff = par[i].stats->values[j]; > printf("%8d:%8u:%10.3lf\n", i, j++, diff); > } > } > } > > if (quiet) > quiet = 2; > > for (i = 0; i < num_threads; i++) { > if (stat[i].threadstarted > 0) { > rt_task_delete(&stat[i].task); > } > if (stat[i].threadstarted) { > if (quiet) > print_stat(&par[i], i, 0); > } > if (stat[i].values) > free(stat[i].values); > } > free(stat); > outpar: > free(par); > out: > exit(ret); > }
I don't see anything suspicious right now, so please consider capturing a trace with the latency as I suggested. That should give a full picture of what is happening when latency detects that huge delay. Jan
signature.asc
Description: OpenPGP digital signature
_______________________________________________ Xenomai-help mailing list Xenomai-help@gna.org https://mail.gna.org/listinfo/xenomai-help