/* * Utility to estimate the overhead of timecounter hardware. * * cc tc.c * sudo ./a.out HPET; sudo ./a.out TSC; sudo ./a.out ACPI-fast */ #include #include #include #include #include #include #include static const char *progname; static void usage(int rc) { fprintf(stderr, "%s: [-h][-i ] [-s ] \n", progname); exit(rc); } int main(int argc, char *argv[]) { int ch, error; long delta, iterations, i, usecs; char *tc_choice; struct timespec ts1, ts2, ts; sbintime_t sbt1, sbt2; progname = basename(argv[0]); iterations = 1000000; usecs = 0; while ((ch = getopt(argc, argv, "i:s:")) != -1) { switch (ch) { case 'i': iterations = strtol(optarg, NULL, 0); break; case 's': usecs = strtol(optarg, NULL, 0); break; case 'h': usage(0); default: usage(1); } } argc -= optind; argv += optind; if (argc != 1) usage(1); tc_choice = argv[0]; error = sysctlbyname("kern.timecounter.hardware", NULL, NULL, tc_choice, strlen(tc_choice) + 1); if (error) { fprintf(stderr, "Error changing timecounter to \"%s\"\n", tc_choice); fprintf(stderr, "sysctl node kern.timecounter.choice lists " "valid timecounter names\n"); exit(1); } usleep(usecs); clock_gettime(CLOCK_UPTIME_PRECISE, &ts1); for (i = 0; i < iterations; i++) (void)clock_gettime(CLOCK_MONOTONIC_PRECISE, &ts); clock_gettime(CLOCK_UPTIME_PRECISE, &ts2); sbt1 = tstosbt(ts1); sbt2 = tstosbt(ts2); ts = sbttots(sbt2 - sbt1); delta = ts.tv_sec * 1000000000 + ts.tv_nsec; printf("%s: ts1 (%ld.%ld) ts2 (%ld.%ld) delta (%ld msecs)\n", tc_choice, ts1.tv_sec, ts1.tv_nsec, ts2.tv_sec, ts2.tv_nsec, delta / 1000000); }