kq_timer.c 3.2 KB

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