kq_timer.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. #include <sys/event.h>
  2. #include <sys/time.h>
  3. #include <stdio.h>
  4. #include <sched.h>
  5. #include <err.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <unistd.h>
  9. #include <getopt.h>
  10. #include <signal.h>
  11. #include <stdbool.h>
  12. static int verbose;
  13. static int usage(void)
  14. {
  15. fputs("kq_timer [--verbose] [--period ms]\n", stderr);
  16. exit (EXIT_SUCCESS);
  17. }
  18. static double diff_ms(const struct timespec *time1, const struct timespec *time0)
  19. {
  20. return (time1->tv_sec - time0->tv_sec) * 1000
  21. + (time1->tv_nsec - time0->tv_nsec) / 1000000.0;
  22. }
  23. static void sig_handler(int sig)
  24. {
  25. signal(SIGINT, SIG_DFL);
  26. }
  27. int main(int argc, char *argv[])
  28. {
  29. struct kevent change; /* event we want to monitor */
  30. struct kevent event; /* event that was triggered */
  31. int kq, nev; /* handlers */
  32. int ch; /* opt long */
  33. int period = 1000; /* Default to 1 sec. */
  34. size_t counter = 0;
  35. size_t total = 0;
  36. FILE *fd = NULL;
  37. char template[64];
  38. int rc = EXIT_FAILURE;
  39. struct timespec t0 = { 0, 0};
  40. const struct sched_param param = {.sched_priority = 49};
  41. static struct option longopts[] = {
  42. { "period", required_argument, NULL, 'p' },
  43. { "verbose", no_argument , &verbose, 1 },
  44. { NULL, 0, NULL, 0 }
  45. };
  46. while ((ch = getopt_long(argc, argv, "hvp:", longopts, NULL)) != -1) {
  47. switch (ch) {
  48. case 'v':
  49. verbose = 1;
  50. break;
  51. case 'p':
  52. period = atoi(optarg);
  53. break;
  54. case 0:
  55. /* long option */
  56. break;
  57. default:
  58. usage();
  59. }
  60. }
  61. argc -= optind;
  62. argv += optind;
  63. if (*argv)
  64. usage();
  65. /* create a new kernel event queue */
  66. if ((kq = kqueue()) == -1)
  67. err(EXIT_FAILURE, "kqueue() failure");
  68. /* initalise kevent structure */
  69. EV_SET(&change, 1, EVFILT_TIMER, EV_ADD | EV_ENABLE, NOTE_MSECONDS, 1, 0);
  70. /* Dummy file to store measurements */
  71. strncpy(template, "/tmp/timer.XXXXXX", sizeof template);
  72. if (mkstemp(template) == -1) {
  73. warn("mkstemp() failure");
  74. goto exit_kqueue;
  75. }
  76. fd = fopen(template, "w");
  77. if (fd == NULL) {
  78. warn("fopen() failure");
  79. goto exit_kqueue;
  80. }
  81. printf("Log file: %s\n", template);
  82. /* process priority */
  83. sched_setscheduler(0, SCHED_FIFO, &param);
  84. signal(SIGINT, sig_handler);
  85. while (true) {
  86. nev = kevent(kq, &change, 1, &event, 1, NULL);
  87. if (nev < 0) {
  88. /* interrupted */
  89. break;
  90. }
  91. if (nev > 0) {
  92. /* measurements */
  93. struct timespec t1;
  94. clock_gettime(CLOCK_MONOTONIC, &t1);
  95. if (!(t0.tv_sec == 0 && t0.tv_nsec == 0))
  96. fprintf(fd, "%06.3f\n", diff_ms(&t1, &t0));
  97. t0 = t1;
  98. if (event.flags & EV_ERROR) {
  99. fprintf(stderr, "EV_ERROR: %s\n", strerror(event.data));
  100. rc = EXIT_FAILURE;
  101. break;
  102. }
  103. /* verbose mode */
  104. ++counter;
  105. if (counter == period) {
  106. if (verbose) {
  107. fputs(".", stdout);
  108. fflush(stdout);
  109. }
  110. counter = 0;
  111. ++total;
  112. }
  113. }
  114. }
  115. rc = 0;
  116. fclose(fd);
  117. fprintf(stdout, "\n%zu entries stored.\n", total);
  118. exit_kqueue:
  119. close(kq);
  120. return rc ? EXIT_FAILURE : EXIT_SUCCESS;
  121. }