wq-aff.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. #include "../config-host.h"
  2. /* SPDX-License-Identifier: MIT */
  3. /*
  4. * Description: test that io-wq affinity is correctly set for SQPOLL
  5. */
  6. #include <stdio.h>
  7. #include <unistd.h>
  8. #include <fcntl.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include "liburing.h"
  12. #include "helpers.h"
  13. #define IOWQ_CPU 0
  14. #define SQPOLL_CPU 1
  15. static int verify_comm(pid_t pid, const char *name, int cpu)
  16. {
  17. char comm[64], buf[64];
  18. cpu_set_t set;
  19. int fd, ret;
  20. sprintf(comm, "/proc/%d/comm", pid);
  21. fd = open(comm, O_RDONLY);
  22. if (fd < 0) {
  23. perror("open");
  24. return T_EXIT_SKIP;
  25. }
  26. ret = read(fd, buf, sizeof(buf));
  27. if (ret < 0) {
  28. close(fd);
  29. return T_EXIT_SKIP;
  30. }
  31. if (strncmp(buf, name, strlen(name) - 1)) {
  32. close(fd);
  33. return T_EXIT_SKIP;
  34. }
  35. close(fd);
  36. ret = sched_getaffinity(pid, sizeof(set), &set);
  37. if (ret < 0) {
  38. perror("sched_getaffinity");
  39. return T_EXIT_SKIP;
  40. }
  41. if (CPU_COUNT(&set) != 1) {
  42. fprintf(stderr, "More than one CPU set in mask\n");
  43. return T_EXIT_FAIL;
  44. }
  45. if (!CPU_ISSET(cpu, &set)) {
  46. fprintf(stderr, "Wrong CPU set in mask\n");
  47. return T_EXIT_FAIL;
  48. }
  49. return T_EXIT_PASS;
  50. }
  51. static int verify_affinity(pid_t pid, int sqpoll)
  52. {
  53. pid_t wq_pid, sqpoll_pid = -1;
  54. char name[64];
  55. int ret;
  56. wq_pid = pid + 2;
  57. if (sqpoll)
  58. sqpoll_pid = pid + 1;
  59. /* verify we had the pids right */
  60. sprintf(name, "iou-wrk-%d", pid);
  61. ret = verify_comm(wq_pid, name, IOWQ_CPU);
  62. if (ret != T_EXIT_PASS)
  63. return ret;
  64. if (sqpoll_pid != -1) {
  65. sprintf(name, "iou-sqp-%d", pid);
  66. ret = verify_comm(sqpoll_pid, name, SQPOLL_CPU);
  67. if (ret != T_EXIT_PASS)
  68. return ret;
  69. }
  70. return T_EXIT_PASS;
  71. }
  72. static int test(int sqpoll)
  73. {
  74. struct io_uring_params p = { };
  75. struct io_uring ring;
  76. struct io_uring_sqe *sqe;
  77. char buf[64];
  78. int fds[2], ret;
  79. cpu_set_t set;
  80. if (sqpoll) {
  81. p.flags = IORING_SETUP_SQPOLL | IORING_SETUP_SQ_AFF;
  82. p.sq_thread_cpu = SQPOLL_CPU;
  83. }
  84. io_uring_queue_init_params(8, &ring, &p);
  85. CPU_ZERO(&set);
  86. CPU_SET(IOWQ_CPU, &set);
  87. ret = io_uring_register_iowq_aff(&ring, sizeof(set), &set);
  88. if (ret) {
  89. fprintf(stderr, "register aff: %d\n", ret);
  90. return T_EXIT_FAIL;
  91. }
  92. if (pipe(fds) < 0) {
  93. perror("pipe");
  94. return T_EXIT_FAIL;
  95. }
  96. sqe = io_uring_get_sqe(&ring);
  97. io_uring_prep_read(sqe, fds[0], buf, sizeof(buf), 0);
  98. sqe->flags |= IOSQE_ASYNC;
  99. io_uring_submit(&ring);
  100. usleep(10000);
  101. ret = verify_affinity(getpid(), sqpoll);
  102. io_uring_queue_exit(&ring);
  103. return ret;
  104. }
  105. static int test_invalid_cpu(void)
  106. {
  107. struct io_uring_params p = { };
  108. struct io_uring ring;
  109. int ret, nr_cpus;
  110. nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
  111. if (nr_cpus < 0) {
  112. perror("sysconf(_SC_NPROCESSORS_ONLN");
  113. return T_EXIT_SKIP;
  114. }
  115. p.flags = IORING_SETUP_SQPOLL | IORING_SETUP_SQ_AFF;
  116. p.sq_thread_cpu = 16 * nr_cpus;
  117. ret = io_uring_queue_init_params(8, &ring, &p);
  118. if (ret == -EPERM) {
  119. return T_EXIT_SKIP;
  120. } else if (ret != -EINVAL) {
  121. fprintf(stderr, "Queue init: %d\n", ret);
  122. return T_EXIT_FAIL;
  123. }
  124. io_uring_queue_exit(&ring);
  125. return T_EXIT_PASS;
  126. }
  127. int main(int argc, char *argv[])
  128. {
  129. int ret;
  130. if (argc > 1)
  131. return T_EXIT_SKIP;
  132. ret = test_invalid_cpu();
  133. if (ret == T_EXIT_SKIP) {
  134. return T_EXIT_SKIP;
  135. } else if (ret != T_EXIT_PASS) {
  136. fprintf(stderr, "test sqpoll cpu failed\n");
  137. return T_EXIT_FAIL;
  138. }
  139. ret = test(1);
  140. if (ret == T_EXIT_SKIP) {
  141. return T_EXIT_SKIP;
  142. } else if (ret != T_EXIT_PASS) {
  143. fprintf(stderr, "test sqpoll failed\n");
  144. return T_EXIT_FAIL;
  145. }
  146. return T_EXIT_PASS;
  147. }