#include #include #include #include #include #include #include #include #include #include #include #include #include // this program is partly ripped off the rtc docs in the linux kernel source tree // the cycle count count ripped from jackd typedef unsigned long long cycles_t; extern cycles_t cacheflush_time; #define rdtscll(val) \ __asm__ __volatile__("rdtsc" : "=A" (val)) static inline cycles_t get_cycles (void) { unsigned long long ret; rdtscll(ret); return ret; } int main(int argc, char *argv[]) { if (argc < 3) { std::cout << "usage: wakeup [freqency(hz)] [number of interrupts]" << std::endl; } std::stringstream args; args << argv[1] << " " << argv[2]; int freq; args >> freq; int number; args >> number; std::cout << "freq: " << freq << " #: " << number << std::endl; if (number < 3) { std::cout << "number of irq's must be >= 3" << std::endl; return(0); } // an array to store the cycles for each interrupt in. cycles_t *cycles = new cycles_t[number]; std::cout << "setting up /dev/rtc..." << std::endl; int fd; fd = open("/dev/rtc", O_RDONLY); if (fd == -1) { perror("/dev/rtc"); exit(errno); } int retval = ioctl(fd, RTC_IRQP_SET, freq); if (retval == -1) { perror("ioctl"); exit(errno); } // we poll only on a single descriptor, the /dev/rtc one struct pollfd fds[1]; pollfd pfd; pfd.fd = fd; pfd.events = POLLRDNORM|POLLRDBAND; fds[0] = pfd; // we set the timeout to 8 periods int timeout; timeout = 8*( (int)( (1.0f/(float)freq)*1000.0f ) ); std::cout << "locking memory..." << std::endl; mlockall(MCL_CURRENT); // std::cout << "sleeping 1 sec" << std::endl; // sleep(1); std::cout << "turning irq on, beginning measurement (might take a while)..." << std::endl; retval = ioctl(fd, RTC_PIE_ON, 0); if (retval == -1) { perror("ioctl"); exit(errno); } unsigned long data; for (int i = 0; i < number; ++i) { // first we poll, until data is available retval = poll(fds, 1, timeout); if (retval == -1) { perror("poll"); exit(errno); } // then we take a timestamp; cycles[i] = get_cycles(); // std::cout << "irq!" << std::endl; // then we read it retval = read(fd, &data, sizeof(unsigned long)); if (retval == -1) { perror("read"); exit(errno); } // see if the high bytes of the data contains a number of irq > 1. probably wrong, data = (data >> 16); if (data > 1) {std::cout << "more than 1 irq happened inbetween this and last wakeup" << std::endl;} } std::cout << "...measurement done" << std::endl; // first one is often skewed double mean_diff = ((double)cycles[number-1] - (double)cycles[1])/(double)(number-2); // std::cout << "0: \t" << cycles[0] << std::endl; double min_diff, max_diff; min_diff = max_diff = (double)(cycles[2] - cycles[1]); unsigned int min_diff_i, max_diff_i; min_diff_i = max_diff_i = 2; double mean_diff_diff = 0; for (int i = 2; i < number; ++i) { double diff = (double)(cycles[i] - cycles[i-1]); if (diff < min_diff) {min_diff = diff; min_diff_i = i;} if (diff > max_diff) {max_diff = diff; max_diff_i = i;} mean_diff_diff += fabs(mean_diff - diff); // std::cout << i << ": \t" << cycles[i] << std::endl; } mean_diff_diff /= (double)(number - 2); std::cout << std::endl << "mean cycle difference betweem two wakeups: " << mean_diff << " cycles" << std::endl << std::endl; std::cout << "min. cycle difference betweem two wakeups: " << min_diff << " cycles (#: " << min_diff_i << ") \n diff from mean diff: " << fabs(min_diff - mean_diff) << std::endl << std::endl; std::cout << "max. cycle difference betweem two wakeups: " << max_diff << " cycles (#: " << max_diff_i << ") \n diff from mean diff: " << fabs(max_diff - mean_diff) << std::endl << std::endl; std::cout << "mean difference from mean difference: " << mean_diff_diff << " cycles" << std::endl; // return success close(fd); return 1; }