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

Attachment: signature.asc
Description: OpenPGP digital signature

_______________________________________________
Xenomai-help mailing list
Xenomai-help@gna.org
https://mail.gna.org/listinfo/xenomai-help

Reply via email to