/* * This was originally written by Mark Hahn. Obtained from * http://brain.mcmaster.ca/~hahn/realfeel.c */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define _GNU_SOURCE #include /* global vars */ int stopit; /* set to stop measuring */ #define SAMPLES 10000 int histogram[SAMPLES]; /* Milliseconds */ #define PAGE_SIZE 4096UL /* virtual memory page size */ #define OSCR_HZ 3686400 /* frequency of clock ticks */ #define OSCR 0x90000010 /* physical address of OSCR register */ unsigned long *oscr; /* ptr to OSCR */ void setup_clock (void) { int fd; void *map_base; off_t target; off_t page; #ifndef ARCHARM return; #endif fd = open ("/dev/mem", O_RDWR | O_SYNC); if (-1 == fd) { perror ("open of /dev/mem failed\n"); exit (1); } /* Map one page */ target = OSCR; page = target & ~(PAGE_SIZE - 1); map_base = mmap (0, PAGE_SIZE, PROT_READ, MAP_SHARED, fd, page); if (MAP_FAILED == map_base) { perror ("mmap failed"); (void) close (fd); exit (2); } oscr = map_base + (target - page); /* This does not end the mmap, * the mmap will go away when the process dies */ close (fd); } double second() { struct timeval tv; gettimeofday(&tv,0); return tv.tv_sec + 1e-6 * tv.tv_usec; } typedef unsigned long long u64; u64 rdtsc() { u64 tsc; #ifdef ARCHARM tsc = *oscr; #else __asm__ __volatile__("rdtsc" : "=A" (tsc)); #endif return tsc; } void selectsleep(unsigned us) { struct timeval tv; tv.tv_sec = 0; tv.tv_usec = us; select(0,0,0,0,&tv); } double secondsPerTick, ticksPerSecond; void calibrate() { double sumx = 0; double sumy = 0; double sumxx = 0; double sumxy = 0; double slope; // least squares linear regression of ticks onto real time // as returned by gettimeofday. const unsigned n = 30; unsigned i; for (i=0; i 2048) { fprintf(stderr, "max allowable interrupt frequency is 2048 Hz\n"); hz = 2048; } else if (hz <= 0) { fprintf(stderr, "zero or negative frequency doesn't make sense!\n"); hz = 1; } } } if (argv[optind] == NULL) { fprintf(stderr, "histogram file name required\n"); usage(); exit (2); } return argv[optind]; } #define msec(f) (1e3 * (f)) int main(int argc, char *argv[]) { int fd; double ideal; u64 last; double max_delay = 0; char *histfile = parse_options(argc, argv); if (mlockall(MCL_CURRENT|MCL_FUTURE) != 0) { perror("mlockall"); exit(1); } setup_clock (); set_realtime_priority(); calibrate(); printf("secondsPerTick=%f\n", secondsPerTick); printf("ticksPerSecond=%f\n", ticksPerSecond); fd = open("/dev/rtc",O_RDONLY); if (fd == -1) fatal("failed to open /dev/rtc"); ideal = 1.0 / hz; if (ioctl(fd, RTC_IRQP_SET, hz) == -1) fatal("ioctl(RTC_IRQP_SET) failed"); printf("Interrupt frequency: %d Hz\n",hz); if (bounded) { printf("running for %d samples\n", ncycles); } /* Enable periodic interrupts */ if (ioctl(fd, RTC_PIE_ON, 0) == -1) fatal("ioctl(RTC_PIE_ON) failed"); signal(SIGINT, signalled); last = rdtsc(); while (!stopit) { u64 now; double delay; int data; int ms; if (read(fd, &data, sizeof(data)) == -1) fatal("blocking read failed"); now = rdtsc(); delay = secondsPerTick * (now - last); if (delay > max_delay) { max_delay = delay; // printf("%.3f msec\n", -(1e3 * (ideal - delay))); } ms = (-(ideal - delay) + 1.0/20000.0) * 10000; if (ms < 0) ms = 0; /* hmmm */ if (ms >= SAMPLES) ms = SAMPLES; histogram[ms]++; if (bounded) { if (++current >= ncycles) { printf ("finished collecting %d samples\n", ncycles); printf ("maximum cycle time: %.3fms\n", -msec(ideal - max_delay)); break; } if ((current % 10000) == 0) { printf("%d cycles (max cycle time so far: %.3fms)\n", current, -(msec(ideal - max_delay))); } } last = now; } if (ioctl(fd, RTC_PIE_OFF, 0) == -1) fatal("ioctl(RTC_PIE_OFF) failed"); hist(histfile); return 0; }