/* * test minimum select time * * ./prog usec [method [duration]] */ #include #include #include #include #include #include #include #include #include enum { M_SELECT =0 , M_POLL, M_USLEEP, M_NANOSLEEP, M_KQUEUE, M_KQUEUETO, M_ALARMF, M_ALARMN, M_SYSCALL }; static const char *names[] = { "select", "poll", "usleep", "nanosleep", "kqueue", "alarmf", "alarmn", "syscall" }; struct bintime tick_bt = { 0, ((uint64_t)1<<63) / 500 }; static void sigalarm(int t) { } int main(int argc, char *argv[]) { struct timeval ta, tb; int usec = 1, total = 0, method = M_SELECT, count = 0, t, i; int kq; if (argc > 1) usec = atoi(argv[1]); /*if (usec <= 0) usec = 1; else */if (usec > 500000) usec = 500000; if (argc > 2) { if (!strcmp(argv[2], "poll")) method = M_POLL; else if (!strcmp(argv[2], "usleep")) method = M_USLEEP; else if (!strcmp(argv[2], "nanosleep")) method = M_NANOSLEEP; else if (!strcmp(argv[2], "kqueue")) { method = M_KQUEUE; kq = kqueue(); } else if (!strcmp(argv[2], "kqueueto")) { method = M_KQUEUETO; kq = kqueue(); } else if (!strcmp(argv[2], "alarmf")) { method = M_ALARMF; signal(SIGALRM, sigalarm); } else if (!strcmp(argv[2], "alarmn")) { method = M_ALARMN; signal(SIGALRM, sigalarm); struct itimerval itv = {{ 0, usec }, { 0, usec }}; setitimer(ITIMER_REAL, &itv, NULL); } else if (!strcmp(argv[2], "syscall")) method = M_SYSCALL; } if (argc > 3) total = atoi(argv[3]); if (total < 1) total = 1; else if (total > 30) total = 30; /* fprintf(stderr, "testing %s for %dus over %ds\n", names[method], usec, total); */ gettimeofday(&ta, NULL); for (;;) { for (i = 1000; i >= 0; i--) { if (method == M_SELECT) { struct timeval to = { 0, usec }; // struct timeval to = { 0x7fffffffffffffff, 0 }; select(0, NULL, NULL, NULL, &to); } else if (method == M_POLL) { poll(NULL, 0, (usec + 999) / 1000); } else if (method == M_USLEEP) { usleep(usec); } else if (method == M_NANOSLEEP) { struct timespec ts = { 0, usec }; // struct timespec ts = { 0x7fffffffffffffff, 0 }; nanosleep(&ts, NULL); } else if (method == M_KQUEUE) { struct timespec ts = { 0, usec }; struct kevent ke; EV_SET(&ke, 0, EVFILT_TIMER, EV_ADD, 0, (usec + 999) / 1000, NULL); kevent(kq, &ke, 1, NULL, 0, NULL); kevent(kq, NULL, 0, &ke, 1, NULL); } else if (method == M_KQUEUETO) { struct timespec ts = { 0, usec }; struct kevent ke; EV_SET(&ke, 0, EVFILT_READ, EV_ADD, 0, 0, NULL); kevent(kq, &ke, 1, NULL, 0, NULL); kevent(kq, NULL, 0, &ke, 1, &ts); } else if (method == M_ALARMF) { struct itimerval itv = {{ 0, 0 }, { 0, usec }}; setitimer(ITIMER_REAL, &itv, NULL); poll(NULL, 0, INFTIM); } else if (method == M_ALARMN) { poll(NULL, 0, INFTIM); } else { fcntl(0, O_NONBLOCK); } count++; } gettimeofday(&tb, NULL); timersub(&tb, &ta, &tb); if (tb.tv_sec > total) break; } /* fprintf(stderr, "%dus actually took %dus\n", usec, (int)(tb.tv_sec * 1000000 + tb.tv_usec) / count ); */ t = ((uint64_t)tb.tv_sec * 1000000 + tb.tv_usec) * 100 / count; fprintf(stdout, "%d %d.%02d (%+d.%02d)\n", usec, t / 100, t % 100, (t - usec * 100) / 100, (t - usec * 100) % 100); return 0; }