main.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. #define _GNU_SOURCE
  2. #include <unistd.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <sched.h>
  6. #include <err.h>
  7. #include <sys/time.h>
  8. #include <signal.h>
  9. #include <sys/syscall.h>
  10. #include <sys/timerfd.h>
  11. #include <linux/unistd.h>
  12. #include <linux/kernel.h>
  13. #include <linux/types.h>
  14. #include <sys/syscall.h>
  15. #include <stdbool.h>
  16. #define gettid() syscall(__NR_gettid)
  17. static int do_print;
  18. static int do_quit;
  19. static size_t loops;
  20. #ifndef __NR_sched_setattr
  21. #ifdef __x86_64__
  22. #define __NR_sched_setattr 314L
  23. #define __NR_sched_getattr 315L
  24. #endif
  25. #endif
  26. struct sched_attr {
  27. __u32 size;
  28. __u32 sched_policy;
  29. __u64 sched_flags;
  30. __s32 sched_nice;
  31. __s32 sched_priority;
  32. __u64 sched_runtime;
  33. __u64 sched_deadline;
  34. __u64 sched_period;
  35. };
  36. long sched_setattr(pid_t pid, const struct sched_attr *attr,
  37. unsigned int flags)
  38. {
  39. return syscall(__NR_sched_setattr, pid, attr, flags);
  40. }
  41. long sched_getattr(pid_t pid, struct sched_attr *attr,
  42. unsigned int size, unsigned int flags)
  43. {
  44. return syscall(__NR_sched_getattr, pid, attr, size, flags);
  45. }
  46. static void sig_handler(int signum)
  47. {
  48. switch (signum)
  49. {
  50. case SIGQUIT:
  51. case SIGTERM:
  52. case SIGINT:
  53. signal(SIGINT, SIG_DFL);
  54. do_quit = 1;
  55. __attribute__((fallthrough));
  56. case SIGUSR1:
  57. do_print = 1;
  58. break;
  59. case SIGHUP:
  60. loops = 0;
  61. default:
  62. break;
  63. }
  64. }
  65. static int deadline(size_t period_ms)
  66. {
  67. int rc = 0;
  68. #ifndef EDF
  69. int tfd = -1;
  70. struct itimerspec itval;
  71. tfd = timerfd_create(CLOCK_MONOTONIC, 0);
  72. if (tfd == -1)
  73. err(-1, "timerfd");
  74. itval.it_interval.tv_sec = 0;
  75. itval.it_interval.tv_nsec = period_ms * 1000 * 1000;
  76. itval.it_value.tv_sec = 0;
  77. itval.it_value.tv_nsec = itval.it_interval.tv_nsec;
  78. rc = timerfd_settime(tfd, 0, &itval, NULL);
  79. if (rc)
  80. err(-1, "timerfd_settime");
  81. do {
  82. static unsigned long long overrun;
  83. rc = read(tfd, &overrun, sizeof overrun);
  84. if (rc == -1) {
  85. err(-1, "Timer read");
  86. }
  87. ++loops;
  88. if (do_print) {
  89. do_print = 0;
  90. fprintf(stdout, "Loops: %zu.\n", loops);
  91. }
  92. } while(!do_quit);
  93. #else
  94. struct sched_attr attr;
  95. unsigned int flags = 0;
  96. attr.size = sizeof attr;
  97. attr.sched_flags = 0;
  98. attr.sched_nice = 0;
  99. attr.sched_priority = 0;
  100. attr.sched_policy = SCHED_DEADLINE;
  101. attr.sched_runtime = (period_ms - 1) * 1000 * 1000;
  102. attr.sched_period = attr.sched_deadline = period_ms * 1000 * 1000;
  103. rc = sched_setattr(0, &attr, flags);
  104. if (rc)
  105. err(EXIT_FAILURE, "sched_setattr");
  106. do {
  107. ++loops;
  108. if (do_print) {
  109. do_print = 0;
  110. fprintf(stdout, "Loops: %zu.\n", loops);
  111. }
  112. sched_yield();
  113. } while(!do_quit);
  114. #endif
  115. printf("last counter => %zu.\n", loops);
  116. }
  117. #define SEC_NSEC 1000000000U
  118. static __attribute__((const)) u_int64_t timespec_sub_to_ns(struct timespec t1,
  119. struct timespec t2)
  120. {
  121. u_int64_t diff;
  122. if (t1.tv_nsec < t2.tv_nsec) {
  123. diff = SEC_NSEC * (u_int64_t)(t1.tv_sec - t2.tv_sec -1);
  124. diff += (u_int64_t)(t1.tv_nsec - t2.tv_nsec);
  125. diff += SEC_NSEC;
  126. } else {
  127. diff = SEC_NSEC * (u_int64_t)(t1.tv_sec - t2.tv_sec);
  128. diff += (u_int64_t)(t1.tv_nsec - t2.tv_nsec);
  129. }
  130. return diff;
  131. }
  132. int main(int argc, char *argv[])
  133. {
  134. int rc;
  135. struct sigaction sa = {0};
  136. struct timespec t0, t1;
  137. /* Set up the structure to specify the new action. */
  138. sigemptyset (&sa.sa_mask);
  139. sigaddset(&sa.sa_mask, SIGINT);
  140. sa.sa_handler = &sig_handler;
  141. sa.sa_flags = 0;
  142. sigaddset(&sa.sa_mask, SIGTERM);
  143. sigaddset(&sa.sa_mask, SIGINT);
  144. sigaddset(&sa.sa_mask, SIGHUP);
  145. sigaddset(&sa.sa_mask, SIGUSR1);
  146. sigaddset(&sa.sa_mask, SIGQUIT);
  147. if (sigaction (SIGINT, &sa, NULL) == -1) {
  148. perror("sigaction");
  149. exit(EXIT_FAILURE);
  150. }
  151. sigaction (SIGTERM, &sa, NULL);
  152. sigaction (SIGQUIT, &sa, NULL);
  153. sigaction (SIGUSR1, &sa, NULL);
  154. sigaction (SIGHUP, &sa, NULL);
  155. printf("[%d] Starting deadline thread.\n", getpid());
  156. clock_gettime(CLOCK_MONOTONIC, &t0);
  157. rc = deadline(5);
  158. clock_gettime(CLOCK_MONOTONIC, &t1);
  159. size_t to = timespec_sub_to_ns(t1, t0) / 1000000;
  160. printf("Time: %lums. average : %lums.\n", to, to / loops);
  161. return rc ? EXIT_FAILURE : EXIT_SUCCESS;
  162. }