madvise.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. #include "../config-host.h"
  2. /* SPDX-License-Identifier: MIT */
  3. /*
  4. * Description: basic madvise test
  5. */
  6. #include <errno.h>
  7. #include <stdio.h>
  8. #include <unistd.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <fcntl.h>
  12. #include <sys/types.h>
  13. #include <sys/time.h>
  14. #include <sys/mman.h>
  15. #include "helpers.h"
  16. #include "liburing.h"
  17. #define FILE_SIZE (128 * 1024)
  18. #define LOOPS 100
  19. #define MIN_LOOPS 10
  20. static unsigned long long utime_since(const struct timeval *s,
  21. const struct timeval *e)
  22. {
  23. long long sec, usec;
  24. sec = e->tv_sec - s->tv_sec;
  25. usec = (e->tv_usec - s->tv_usec);
  26. if (sec > 0 && usec < 0) {
  27. sec--;
  28. usec += 1000000;
  29. }
  30. sec *= 1000000;
  31. return sec + usec;
  32. }
  33. static unsigned long long utime_since_now(struct timeval *tv)
  34. {
  35. struct timeval end;
  36. gettimeofday(&end, NULL);
  37. return utime_since(tv, &end);
  38. }
  39. static int do_madvise(struct io_uring *ring, void *addr, off_t len, int advice)
  40. {
  41. struct io_uring_sqe *sqe;
  42. struct io_uring_cqe *cqe;
  43. int ret;
  44. sqe = io_uring_get_sqe(ring);
  45. if (!sqe) {
  46. fprintf(stderr, "failed to get sqe\n");
  47. return 1;
  48. }
  49. io_uring_prep_madvise(sqe, addr, len, advice);
  50. sqe->user_data = advice;
  51. ret = io_uring_submit_and_wait(ring, 1);
  52. if (ret != 1) {
  53. fprintf(stderr, "submit: %d\n", ret);
  54. return 1;
  55. }
  56. ret = io_uring_wait_cqe(ring, &cqe);
  57. if (ret) {
  58. fprintf(stderr, "wait: %d\n", ret);
  59. return 1;
  60. }
  61. ret = cqe->res;
  62. if (ret == -EINVAL || ret == -EBADF) {
  63. fprintf(stdout, "Madvise not supported, skipping\n");
  64. unlink(".madvise.tmp");
  65. exit(0);
  66. } else if (ret) {
  67. fprintf(stderr, "cqe->res=%d\n", cqe->res);
  68. }
  69. io_uring_cqe_seen(ring, cqe);
  70. return ret;
  71. }
  72. static long do_copy(int fd, char *buf, void *ptr)
  73. {
  74. struct timeval tv;
  75. gettimeofday(&tv, NULL);
  76. memcpy(buf, ptr, FILE_SIZE);
  77. return utime_since_now(&tv);
  78. }
  79. static int test_madvise(struct io_uring *ring, const char *filename)
  80. {
  81. unsigned long cached_read, uncached_read, cached_read2;
  82. int fd, ret;
  83. char *buf;
  84. void *ptr;
  85. fd = open(filename, O_RDONLY);
  86. if (fd < 0) {
  87. perror("open");
  88. return 1;
  89. }
  90. buf = t_malloc(FILE_SIZE);
  91. ptr = mmap(NULL, FILE_SIZE, PROT_READ, MAP_PRIVATE, fd, 0);
  92. if (ptr == MAP_FAILED) {
  93. perror("mmap");
  94. return 1;
  95. }
  96. cached_read = do_copy(fd, buf, ptr);
  97. if (cached_read == -1)
  98. return 1;
  99. cached_read = do_copy(fd, buf, ptr);
  100. if (cached_read == -1)
  101. return 1;
  102. ret = do_madvise(ring, ptr, FILE_SIZE, MADV_DONTNEED);
  103. if (ret)
  104. return 1;
  105. uncached_read = do_copy(fd, buf, ptr);
  106. if (uncached_read == -1)
  107. return 1;
  108. ret = do_madvise(ring, ptr, FILE_SIZE, MADV_DONTNEED);
  109. if (ret)
  110. return 1;
  111. ret = do_madvise(ring, ptr, FILE_SIZE, MADV_WILLNEED);
  112. if (ret)
  113. return 1;
  114. msync(ptr, FILE_SIZE, MS_SYNC);
  115. cached_read2 = do_copy(fd, buf, ptr);
  116. if (cached_read2 == -1)
  117. return 1;
  118. if (cached_read < uncached_read &&
  119. cached_read2 < uncached_read)
  120. return 0;
  121. return 2;
  122. }
  123. int main(int argc, char *argv[])
  124. {
  125. struct io_uring ring;
  126. int ret, i, good, bad;
  127. char *fname;
  128. if (argc > 1) {
  129. fname = argv[1];
  130. } else {
  131. fname = ".madvise.tmp";
  132. t_create_file(fname, FILE_SIZE);
  133. }
  134. if (io_uring_queue_init(8, &ring, 0)) {
  135. fprintf(stderr, "ring creation failed\n");
  136. goto err;
  137. }
  138. good = bad = 0;
  139. for (i = 0; i < LOOPS; i++) {
  140. ret = test_madvise(&ring, fname);
  141. if (ret == 1) {
  142. fprintf(stderr, "test_madvise failed\n");
  143. goto err;
  144. } else if (!ret)
  145. good++;
  146. else if (ret == 2)
  147. bad++;
  148. if (i >= MIN_LOOPS && !bad)
  149. break;
  150. }
  151. /* too hard to reliably test, just ignore */
  152. if ((0) && bad > good)
  153. fprintf(stderr, "Suspicious timings (%u > %u)\n", bad, good);
  154. if (fname != argv[1])
  155. unlink(fname);
  156. io_uring_queue_exit(&ring);
  157. return T_EXIT_PASS;
  158. err:
  159. if (fname != argv[1])
  160. unlink(fname);
  161. return T_EXIT_FAIL;
  162. }