/* * A periodic real-time process that reads /dev/ptimer. It also measures * the interval between two instance releases. * * Copyright (C) 2001 MontaVista Software Inc. * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * */ #include #include #include #include #include #include #include #include #include /* * CONFIGURE */ #define NUM_DATA 10000 //#define NUM_DATA 20 #define PERIOD 1 /* in HZ */ #define TEST_DURATION NUM_DATA*PERIOD/HZ #define MIN_CLOCK_RES 10 /* in usec */ /* * DEBUG */ // #define DEBUG printf #define DEBUG (void) /* * IOCTL CMD */ #define PTIMER_SET_PERIOD 0 #define PTIMER_GET_PERIOD 1 /* * in micro-seconds (usec) */ long time_diff(struct timeval *t2, struct timeval *t1) { long diff; /* NOTE : should we worry about overflow or underflow ? */ diff = (t1->tv_sec - t2->tv_sec) * 1000000; if (t1->tv_usec >= t2->tv_usec) { diff += t1->tv_usec - t2->tv_usec; } else { diff -= t2->tv_usec - t1->tv_usec; } return diff; } /* * We collect n consective time stamps. * We then collect n consecutive different time vals * Then we potentially have 2*n-1 intervals. * We guess the smallest non-zero interval is the clock resolution * * If the resolution is bigger than MIN_CLOCK_RES, we return 1. Otherwise * we return 0. */ #define NUM_TIME_STAMP 20 int checkClockRes() { struct timeval timestamp[2*NUM_TIME_STAMP]; int i; uint clockres; for (i=0; i< NUM_TIME_STAMP; i++) { gettimeofday(×tamp[i], 0); } for (i=NUM_TIME_STAMP; i< 2*NUM_TIME_STAMP; ) { gettimeofday(×tamp[i], 0); if ( (timestamp[i-1].tv_sec != timestamp[i].tv_sec) || (timestamp[i-1].tv_usec != timestamp[i].tv_usec) ) { DEBUG("sample %d : (%ld, %ld)\n", i, timestamp[i].tv_sec, timestamp[i].tv_usec); i++; } } clockres = 0xffffffff; for (i=1; i< 2*NUM_TIME_STAMP; i++) { uint diff; diff = time_diff(×tamp[i-1], ×tamp[i]); DEBUG("diff = %ld\n", diff); assert(diff >= 0); if ( (clockres > diff) && (diff > 0) ) clockres = diff; } printf("We think your clock resolution is %d micro-seconds.\n", clockres); if (clockres > MIN_CLOCK_RES) { return 1; } else { return 0; } } void check_realtime() { int sched_policy; struct sched_param sched_param; sched_policy = sched_getscheduler(0); switch (sched_policy) { case SCHED_FIFO: printf("current sched policy is SCHED_FIFO.\n"); break; case SCHED_RR: printf("current sched policy is SCHED_RR.\n"); break; case SCHED_OTHER: printf("current sched policy is SCHED_OTHER.\n"); break; default: printf("error!\n"); exit(-1); } sched_getparam(0, &sched_param); printf("current sched priority is %d in the range [%d, %d]\n", sched_param.sched_priority, sched_get_priority_min(sched_policy), sched_get_priority_max(sched_policy)); } void start_realtime() { struct sched_param sched_param; printf("Bump up the process to real-time priority 10.\n"); sched_param.sched_priority = 10; sched_setscheduler(0, SCHED_FIFO, &sched_param); } void end_realtime() { struct sched_param sched_param; printf("Go back to normal SCHED_OTHER scheduling.\n"); sched_param.sched_priority = 0; sched_setscheduler(0, SCHED_OTHER, &sched_param); } long interval[NUM_DATA]; long overrun; long min, max; main(int argc, const char **argv) { unsigned long period; int fd = open("/dev/ptimer", O_RDONLY); int i; struct timeval prev, curr; long count; int ret; int realtime; /* test clock res */ if (checkClockRes()) { printf("Your machine clock is fine enough to the test!\n"); exit(-1); } if (fd < 0) { printf("failed to open /dev/ptimer\n"); printf("Did you do insmod ptimer.o and mknod /dev/ptimer c 240 0?\n"); exit(-1); } if (ioctl(fd, PTIMER_GET_PERIOD, &period) < 0) { printf("failed to get period\n"); exit(-1); } /* we use 1 sec period */ if (ioctl(fd, PTIMER_SET_PERIOD, PERIOD) < 0) { printf("failed to set period\n"); exit(-1); } ioctl(fd, PTIMER_GET_PERIOD, &period); printf("Test period is %d\n", period); printf("Test duration is expected to be %d seconds. \n", TEST_DURATION); printf("Start collecting data ... \n"); /* realtime or not */ if ((argc == 2) && (strcmp(argv[1], "realtime") == 0)) { realtime=1; } else { realtime=0; } if (realtime) start_realtime(); /* get rid of the first noise data */ min=LONG_MAX; max=0; read(fd, &count, sizeof(count)); read(fd, &count, sizeof(count)); gettimeofday(&prev, 0); for(i=0; i< NUM_DATA; i++) { ret = read(fd, &count, sizeof(count)); gettimeofday(&curr, 0); if (ret != sizeof(count)) { printf("read ptimer failed. Aborting test ...\n"); exit(-1); } if (count > 1) overrun ++; interval[i] = time_diff(&prev, &curr); if (interval[i] > max) max = interval[i]; if (interval[i] < min) min = interval[i]; prev.tv_sec = curr.tv_sec; prev.tv_usec = curr.tv_usec; } if (realtime) end_realtime(); /* display data - maybe not a good idea. :-0 */ #if 0 for (i=0; i< NUM_DATA; i++) { printf("%ld\n", interval[i]); } #endif /* write data to a data file */ { FILE *file = fopen("data", "w"); if (file == NULL) { printf("create 'data' file failed.\n"); exit(-1); } fprintf(file, "%d %ld %ld %ld\n", NUM_DATA, overrun, min, max); for (i=0; i< NUM_DATA; i++) { fprintf(file, "%d\n", interval[i]); } fclose(file); } }