min-timeout.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. #include "../config-host.h"
  2. /* SPDX-License-Identifier: MIT */
  3. /*
  4. * Description: test min timeout handling
  5. *
  6. */
  7. #include <errno.h>
  8. #include <stdio.h>
  9. #include <unistd.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include <fcntl.h>
  13. #include <sys/resource.h>
  14. #include <sys/time.h>
  15. #include <pthread.h>
  16. #include "liburing.h"
  17. #include "helpers.h"
  18. #define NPIPES 8
  19. #define NWRITES 6
  20. #define WAIT_USEC (250000)
  21. static int no_min_timeout;
  22. struct d {
  23. int fd[NPIPES];
  24. long delay;
  25. };
  26. static void *thread_fn(void *data)
  27. {
  28. struct d *d = data;
  29. char buf[32];
  30. int i;
  31. memset(buf, 0x55, sizeof(buf));
  32. for (i = 0; i < NWRITES; i++) {
  33. int ret;
  34. usleep(d->delay);
  35. ret = write(d->fd[i], buf, sizeof(buf));
  36. if (ret != sizeof(buf)) {
  37. fprintf(stderr, "bad write %d\n", ret);
  38. break;
  39. }
  40. }
  41. return NULL;
  42. }
  43. /*
  44. * Allow 25% tolerance
  45. */
  46. static int within_range(unsigned int target, unsigned int msec)
  47. {
  48. unsigned int high, low;
  49. low = (target * 3) / 4;
  50. high = (target * 5) / 4;
  51. return (msec >= low && msec <= high);
  52. }
  53. static int test(int flags, int expected_ctx, int min_wait, int write_delay,
  54. int nr_cqes, int msec_target)
  55. {
  56. struct io_uring_cqe *cqe;
  57. struct io_uring_sqe *sqe;
  58. struct io_uring ring;
  59. struct __kernel_timespec ts;
  60. struct rusage s, e;
  61. pthread_t thread;
  62. struct d d;
  63. struct io_uring_params p = { .flags = flags, };
  64. int ret, fds[NPIPES][2], i;
  65. struct timeval start_time;
  66. char buf[32];
  67. void *tret;
  68. long ttime;
  69. ret = io_uring_queue_init_params(NPIPES, &ring, &p);
  70. if (ret == -EINVAL)
  71. return T_EXIT_SKIP;
  72. if (!(p.features & IORING_FEAT_MIN_TIMEOUT)) {
  73. no_min_timeout = 1;
  74. return T_EXIT_SKIP;
  75. }
  76. for (i = 0; i < NPIPES; i++) {
  77. if (pipe(fds[i]) < 0) {
  78. perror("pipe");
  79. return 1;
  80. }
  81. d.fd[i] = fds[i][1];
  82. }
  83. d.delay = write_delay;
  84. pthread_create(&thread, NULL, thread_fn, &d);
  85. for (i = 0; i < NPIPES; i++) {
  86. sqe = io_uring_get_sqe(&ring);
  87. io_uring_prep_read(sqe, fds[i][0], buf, sizeof(buf), 0);
  88. }
  89. ts.tv_sec = 0;
  90. ts.tv_nsec = WAIT_USEC * 1000LL;
  91. gettimeofday(&start_time, NULL);
  92. getrusage(RUSAGE_THREAD, &s);
  93. ret = io_uring_submit_and_wait_min_timeout(&ring, &cqe, 8, &ts, min_wait, NULL);
  94. if (ret != NPIPES)
  95. fprintf(stderr, "submit_and_wait=%d\n", ret);
  96. getrusage(RUSAGE_THREAD, &e);
  97. e.ru_nvcsw -= s.ru_nvcsw;
  98. ttime = mtime_since_now(&start_time);
  99. if (!within_range(msec_target, ttime)) {
  100. fprintf(stderr, "Expected %d msec, got %ld msec\n", msec_target,
  101. ttime);
  102. fprintf(stderr, "flags=%x, min_wait=%d, write_delay=%d\n",
  103. flags, min_wait, write_delay);
  104. }
  105. /* will usually be accurate, but allow for offset of 1 */
  106. if (e.ru_nvcsw != expected_ctx &&
  107. (e.ru_nvcsw - expected_ctx > 1))
  108. fprintf(stderr, "%ld ctx switches, expected %d\n", e.ru_nvcsw,
  109. expected_ctx);
  110. for (i = 0; i < NPIPES; i++) {
  111. ret = io_uring_peek_cqe(&ring, &cqe);
  112. if (ret)
  113. break;
  114. io_uring_cqe_seen(&ring, cqe);
  115. }
  116. if (i != nr_cqes)
  117. fprintf(stderr, "Got %d CQEs, expected %d\n", i, nr_cqes);
  118. pthread_join(thread, &tret);
  119. for (i = 0; i < NPIPES; i++) {
  120. close(fds[i][0]);
  121. close(fds[i][1]);
  122. }
  123. return T_EXIT_PASS;
  124. }
  125. int main(int argc, char *argv[])
  126. {
  127. int ret;
  128. if (argc > 1)
  129. return T_EXIT_SKIP;
  130. ret = test(0, NWRITES + 1, 0, 2000, NWRITES, WAIT_USEC / 1000);
  131. if (ret == T_EXIT_FAIL)
  132. return T_EXIT_FAIL;
  133. if (no_min_timeout)
  134. return T_EXIT_SKIP;
  135. ret = test(0, NWRITES + 1, 50000, 2000, NWRITES, 50);
  136. if (ret == T_EXIT_FAIL)
  137. return T_EXIT_FAIL;
  138. ret = test(0, NWRITES + 1, 500000, 2000, NWRITES, 500);
  139. if (ret == T_EXIT_FAIL)
  140. return T_EXIT_FAIL;
  141. /* no writes within min timeout, but it's given. expect 1 cqe */
  142. ret = test(0, 1, 10000, 20000, 1, 20);
  143. if (ret == T_EXIT_FAIL)
  144. return T_EXIT_FAIL;
  145. /* same as above, but no min timeout. should time out and we get 6 */
  146. ret = test(0, NWRITES + 1, 0, 20000, NWRITES, WAIT_USEC / 1000);
  147. if (ret == T_EXIT_FAIL)
  148. return T_EXIT_FAIL;
  149. ret = test(IORING_SETUP_SINGLE_ISSUER | IORING_SETUP_DEFER_TASKRUN, 1,
  150. 0, 2000, NWRITES, WAIT_USEC / 1000);
  151. if (ret == T_EXIT_FAIL)
  152. return T_EXIT_FAIL;
  153. ret = test(IORING_SETUP_SINGLE_ISSUER | IORING_SETUP_DEFER_TASKRUN, 1,
  154. 50000, 2000, NWRITES, 50);
  155. if (ret == T_EXIT_FAIL)
  156. return T_EXIT_FAIL;
  157. ret = test(IORING_SETUP_SINGLE_ISSUER | IORING_SETUP_DEFER_TASKRUN, 1,
  158. 500000, 2000, NWRITES, 500);
  159. if (ret == T_EXIT_FAIL)
  160. return T_EXIT_FAIL;
  161. /* no writes within min timeout, but it's given. expect 1 cqe */
  162. ret = test(IORING_SETUP_SINGLE_ISSUER | IORING_SETUP_DEFER_TASKRUN, 1,
  163. 10000, 20000, 1, 20);
  164. if (ret == T_EXIT_FAIL)
  165. return T_EXIT_FAIL;
  166. /* same as above, but no min timeout. should time out and we get 6 */
  167. ret = test(IORING_SETUP_SINGLE_ISSUER | IORING_SETUP_DEFER_TASKRUN, 1,
  168. 0, 20000, NWRITES, WAIT_USEC / 1000);
  169. if (ret == T_EXIT_FAIL)
  170. return T_EXIT_FAIL;
  171. return ret;
  172. }