set-timer-lat.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. /* set_timer latency test
  2. * John Stultz (john.stultz@linaro.org)
  3. * (C) Copyright Linaro 2014
  4. * Licensed under the GPLv2
  5. *
  6. * This test makes sure the set_timer api is correct
  7. *
  8. * To build:
  9. * $ gcc set-timer-lat.c -o set-timer-lat -lrt
  10. *
  11. * This program is free software: you can redistribute it and/or modify
  12. * it under the terms of the GNU General Public License as published by
  13. * the Free Software Foundation, either version 2 of the License, or
  14. * (at your option) any later version.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU General Public License for more details.
  20. */
  21. #include <stdio.h>
  22. #include <unistd.h>
  23. #include <time.h>
  24. #include <string.h>
  25. #include <signal.h>
  26. #include <stdlib.h>
  27. #include <pthread.h>
  28. #ifdef KTEST
  29. #include "../kselftest.h"
  30. #else
  31. static inline int ksft_exit_pass(void)
  32. {
  33. exit(0);
  34. }
  35. static inline int ksft_exit_fail(void)
  36. {
  37. exit(1);
  38. }
  39. #endif
  40. #define CLOCK_REALTIME 0
  41. #define CLOCK_MONOTONIC 1
  42. #define CLOCK_PROCESS_CPUTIME_ID 2
  43. #define CLOCK_THREAD_CPUTIME_ID 3
  44. #define CLOCK_MONOTONIC_RAW 4
  45. #define CLOCK_REALTIME_COARSE 5
  46. #define CLOCK_MONOTONIC_COARSE 6
  47. #define CLOCK_BOOTTIME 7
  48. #define CLOCK_REALTIME_ALARM 8
  49. #define CLOCK_BOOTTIME_ALARM 9
  50. #define CLOCK_HWSPECIFIC 10
  51. #define CLOCK_TAI 11
  52. #define NR_CLOCKIDS 12
  53. #define NSEC_PER_SEC 1000000000ULL
  54. #define UNRESONABLE_LATENCY 40000000 /* 40ms in nanosecs */
  55. #define TIMER_SECS 1
  56. int alarmcount;
  57. int clock_id;
  58. struct timespec start_time;
  59. long long max_latency_ns;
  60. char *clockstring(int clockid)
  61. {
  62. switch (clockid) {
  63. case CLOCK_REALTIME:
  64. return "CLOCK_REALTIME";
  65. case CLOCK_MONOTONIC:
  66. return "CLOCK_MONOTONIC";
  67. case CLOCK_PROCESS_CPUTIME_ID:
  68. return "CLOCK_PROCESS_CPUTIME_ID";
  69. case CLOCK_THREAD_CPUTIME_ID:
  70. return "CLOCK_THREAD_CPUTIME_ID";
  71. case CLOCK_MONOTONIC_RAW:
  72. return "CLOCK_MONOTONIC_RAW";
  73. case CLOCK_REALTIME_COARSE:
  74. return "CLOCK_REALTIME_COARSE";
  75. case CLOCK_MONOTONIC_COARSE:
  76. return "CLOCK_MONOTONIC_COARSE";
  77. case CLOCK_BOOTTIME:
  78. return "CLOCK_BOOTTIME";
  79. case CLOCK_REALTIME_ALARM:
  80. return "CLOCK_REALTIME_ALARM";
  81. case CLOCK_BOOTTIME_ALARM:
  82. return "CLOCK_BOOTTIME_ALARM";
  83. case CLOCK_TAI:
  84. return "CLOCK_TAI";
  85. };
  86. return "UNKNOWN_CLOCKID";
  87. }
  88. long long timespec_sub(struct timespec a, struct timespec b)
  89. {
  90. long long ret = NSEC_PER_SEC * b.tv_sec + b.tv_nsec;
  91. ret -= NSEC_PER_SEC * a.tv_sec + a.tv_nsec;
  92. return ret;
  93. }
  94. void sigalarm(int signo)
  95. {
  96. long long delta_ns;
  97. struct timespec ts;
  98. clock_gettime(clock_id, &ts);
  99. alarmcount++;
  100. delta_ns = timespec_sub(start_time, ts);
  101. delta_ns -= NSEC_PER_SEC * TIMER_SECS * alarmcount;
  102. if (delta_ns < 0)
  103. printf("%s timer fired early: FAIL\n", clockstring(clock_id));
  104. if (delta_ns > max_latency_ns)
  105. max_latency_ns = delta_ns;
  106. }
  107. int do_timer(int clock_id, int flags)
  108. {
  109. struct sigevent se;
  110. timer_t tm1;
  111. struct itimerspec its1, its2;
  112. int err;
  113. /* Set up timer: */
  114. memset(&se, 0, sizeof(se));
  115. se.sigev_notify = SIGEV_SIGNAL;
  116. se.sigev_signo = SIGRTMAX;
  117. se.sigev_value.sival_int = 0;
  118. max_latency_ns = 0;
  119. alarmcount = 0;
  120. err = timer_create(clock_id, &se, &tm1);
  121. if (err) {
  122. if ((clock_id == CLOCK_REALTIME_ALARM) ||
  123. (clock_id == CLOCK_BOOTTIME_ALARM)) {
  124. printf("%-22s %s missing CAP_WAKE_ALARM? : [UNSUPPORTED]\n",
  125. clockstring(clock_id),
  126. flags ? "ABSTIME":"RELTIME");
  127. return 0;
  128. }
  129. printf("%s - timer_create() failed\n", clockstring(clock_id));
  130. return -1;
  131. }
  132. clock_gettime(clock_id, &start_time);
  133. if (flags) {
  134. its1.it_value = start_time;
  135. its1.it_value.tv_sec += TIMER_SECS;
  136. } else {
  137. its1.it_value.tv_sec = TIMER_SECS;
  138. its1.it_value.tv_nsec = 0;
  139. }
  140. its1.it_interval.tv_sec = TIMER_SECS;
  141. its1.it_interval.tv_nsec = 0;
  142. err = timer_settime(tm1, flags, &its1, &its2);
  143. if (err) {
  144. printf("%s - timer_settime() failed\n", clockstring(clock_id));
  145. return -1;
  146. }
  147. while (alarmcount < 5)
  148. sleep(1);
  149. printf("%-22s %s max latency: %10lld ns : ",
  150. clockstring(clock_id),
  151. flags ? "ABSTIME":"RELTIME",
  152. max_latency_ns);
  153. timer_delete(tm1);
  154. if (max_latency_ns < UNRESONABLE_LATENCY) {
  155. printf("[OK]\n");
  156. return 0;
  157. }
  158. printf("[FAILED]\n");
  159. return -1;
  160. }
  161. int main(void)
  162. {
  163. struct sigaction act;
  164. int signum = SIGRTMAX;
  165. int ret = 0;
  166. /* Set up signal handler: */
  167. sigfillset(&act.sa_mask);
  168. act.sa_flags = 0;
  169. act.sa_handler = sigalarm;
  170. sigaction(signum, &act, NULL);
  171. printf("Setting timers for every %i seconds\n", TIMER_SECS);
  172. for (clock_id = 0; clock_id < NR_CLOCKIDS; clock_id++) {
  173. if ((clock_id == CLOCK_PROCESS_CPUTIME_ID) ||
  174. (clock_id == CLOCK_THREAD_CPUTIME_ID) ||
  175. (clock_id == CLOCK_MONOTONIC_RAW) ||
  176. (clock_id == CLOCK_REALTIME_COARSE) ||
  177. (clock_id == CLOCK_MONOTONIC_COARSE) ||
  178. (clock_id == CLOCK_HWSPECIFIC))
  179. continue;
  180. ret |= do_timer(clock_id, TIMER_ABSTIME);
  181. ret |= do_timer(clock_id, 0);
  182. }
  183. if (ret)
  184. return ksft_exit_fail();
  185. return ksft_exit_pass();
  186. }