inspect.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. #include "test/jemalloc_test.h"
  2. #define TEST_UTIL_EINVAL(node, a, b, c, d, why_inval) do { \
  3. assert_d_eq(mallctl("experimental.utilization." node, \
  4. a, b, c, d), EINVAL, "Should fail when " why_inval); \
  5. assert_zu_eq(out_sz, out_sz_ref, \
  6. "Output size touched when given invalid arguments"); \
  7. assert_d_eq(memcmp(out, out_ref, out_sz_ref), 0, \
  8. "Output content touched when given invalid arguments"); \
  9. } while (0)
  10. #define TEST_UTIL_QUERY_EINVAL(a, b, c, d, why_inval) \
  11. TEST_UTIL_EINVAL("query", a, b, c, d, why_inval)
  12. #define TEST_UTIL_BATCH_EINVAL(a, b, c, d, why_inval) \
  13. TEST_UTIL_EINVAL("batch_query", a, b, c, d, why_inval)
  14. #define TEST_UTIL_VALID(node) do { \
  15. assert_d_eq(mallctl("experimental.utilization." node, \
  16. out, &out_sz, in, in_sz), 0, \
  17. "Should return 0 on correct arguments"); \
  18. expect_zu_eq(out_sz, out_sz_ref, "incorrect output size"); \
  19. expect_d_ne(memcmp(out, out_ref, out_sz_ref), 0, \
  20. "Output content should be changed"); \
  21. } while (0)
  22. #define TEST_UTIL_BATCH_VALID TEST_UTIL_VALID("batch_query")
  23. #define TEST_MAX_SIZE (1 << 20)
  24. TEST_BEGIN(test_query) {
  25. size_t sz;
  26. /*
  27. * Select some sizes that can span both small and large sizes, and are
  28. * numerically unrelated to any size boundaries.
  29. */
  30. for (sz = 7; sz <= TEST_MAX_SIZE && sz <= SC_LARGE_MAXCLASS;
  31. sz += (sz <= SC_SMALL_MAXCLASS ? 1009 : 99989)) {
  32. void *p = mallocx(sz, 0);
  33. void **in = &p;
  34. size_t in_sz = sizeof(const void *);
  35. size_t out_sz = sizeof(void *) + sizeof(size_t) * 5;
  36. void *out = mallocx(out_sz, 0);
  37. void *out_ref = mallocx(out_sz, 0);
  38. size_t out_sz_ref = out_sz;
  39. assert_ptr_not_null(p,
  40. "test pointer allocation failed");
  41. assert_ptr_not_null(out,
  42. "test output allocation failed");
  43. assert_ptr_not_null(out_ref,
  44. "test reference output allocation failed");
  45. #define SLABCUR_READ(out) (*(void **)out)
  46. #define COUNTS(out) ((size_t *)((void **)out + 1))
  47. #define NFREE_READ(out) COUNTS(out)[0]
  48. #define NREGS_READ(out) COUNTS(out)[1]
  49. #define SIZE_READ(out) COUNTS(out)[2]
  50. #define BIN_NFREE_READ(out) COUNTS(out)[3]
  51. #define BIN_NREGS_READ(out) COUNTS(out)[4]
  52. SLABCUR_READ(out) = NULL;
  53. NFREE_READ(out) = NREGS_READ(out) = SIZE_READ(out) = -1;
  54. BIN_NFREE_READ(out) = BIN_NREGS_READ(out) = -1;
  55. memcpy(out_ref, out, out_sz);
  56. /* Test invalid argument(s) errors */
  57. TEST_UTIL_QUERY_EINVAL(NULL, &out_sz, in, in_sz,
  58. "old is NULL");
  59. TEST_UTIL_QUERY_EINVAL(out, NULL, in, in_sz,
  60. "oldlenp is NULL");
  61. TEST_UTIL_QUERY_EINVAL(out, &out_sz, NULL, in_sz,
  62. "newp is NULL");
  63. TEST_UTIL_QUERY_EINVAL(out, &out_sz, in, 0,
  64. "newlen is zero");
  65. in_sz -= 1;
  66. TEST_UTIL_QUERY_EINVAL(out, &out_sz, in, in_sz,
  67. "invalid newlen");
  68. in_sz += 1;
  69. out_sz_ref = out_sz -= 2 * sizeof(size_t);
  70. TEST_UTIL_QUERY_EINVAL(out, &out_sz, in, in_sz,
  71. "invalid *oldlenp");
  72. out_sz_ref = out_sz += 2 * sizeof(size_t);
  73. /* Examine output for valid call */
  74. TEST_UTIL_VALID("query");
  75. expect_zu_le(sz, SIZE_READ(out),
  76. "Extent size should be at least allocation size");
  77. expect_zu_eq(SIZE_READ(out) & (PAGE - 1), 0,
  78. "Extent size should be a multiple of page size");
  79. /*
  80. * We don't do much bin checking if prof is on, since profiling
  81. * can produce extents that are for small size classes but not
  82. * slabs, which interferes with things like region counts.
  83. */
  84. if (!opt_prof && sz <= SC_SMALL_MAXCLASS) {
  85. expect_zu_le(NFREE_READ(out), NREGS_READ(out),
  86. "Extent free count exceeded region count");
  87. expect_zu_le(NREGS_READ(out), SIZE_READ(out),
  88. "Extent region count exceeded size");
  89. expect_zu_ne(NREGS_READ(out), 0,
  90. "Extent region count must be positive");
  91. expect_true(NFREE_READ(out) == 0 || (SLABCUR_READ(out)
  92. != NULL && SLABCUR_READ(out) <= p),
  93. "Allocation should follow first fit principle");
  94. if (config_stats) {
  95. expect_zu_le(BIN_NFREE_READ(out),
  96. BIN_NREGS_READ(out),
  97. "Bin free count exceeded region count");
  98. expect_zu_ne(BIN_NREGS_READ(out), 0,
  99. "Bin region count must be positive");
  100. expect_zu_le(NFREE_READ(out),
  101. BIN_NFREE_READ(out),
  102. "Extent free count exceeded bin free count");
  103. expect_zu_le(NREGS_READ(out),
  104. BIN_NREGS_READ(out),
  105. "Extent region count exceeded "
  106. "bin region count");
  107. expect_zu_eq(BIN_NREGS_READ(out)
  108. % NREGS_READ(out), 0,
  109. "Bin region count isn't a multiple of "
  110. "extent region count");
  111. expect_zu_le(
  112. BIN_NFREE_READ(out) - NFREE_READ(out),
  113. BIN_NREGS_READ(out) - NREGS_READ(out),
  114. "Free count in other extents in the bin "
  115. "exceeded region count in other extents "
  116. "in the bin");
  117. expect_zu_le(NREGS_READ(out) - NFREE_READ(out),
  118. BIN_NREGS_READ(out) - BIN_NFREE_READ(out),
  119. "Extent utilized count exceeded "
  120. "bin utilized count");
  121. }
  122. } else if (sz > SC_SMALL_MAXCLASS) {
  123. expect_zu_eq(NFREE_READ(out), 0,
  124. "Extent free count should be zero");
  125. expect_zu_eq(NREGS_READ(out), 1,
  126. "Extent region count should be one");
  127. expect_ptr_null(SLABCUR_READ(out),
  128. "Current slab must be null for large size classes");
  129. if (config_stats) {
  130. expect_zu_eq(BIN_NFREE_READ(out), 0,
  131. "Bin free count must be zero for "
  132. "large sizes");
  133. expect_zu_eq(BIN_NREGS_READ(out), 0,
  134. "Bin region count must be zero for "
  135. "large sizes");
  136. }
  137. }
  138. #undef BIN_NREGS_READ
  139. #undef BIN_NFREE_READ
  140. #undef SIZE_READ
  141. #undef NREGS_READ
  142. #undef NFREE_READ
  143. #undef COUNTS
  144. #undef SLABCUR_READ
  145. free(out_ref);
  146. free(out);
  147. free(p);
  148. }
  149. }
  150. TEST_END
  151. TEST_BEGIN(test_batch) {
  152. size_t sz;
  153. /*
  154. * Select some sizes that can span both small and large sizes, and are
  155. * numerically unrelated to any size boundaries.
  156. */
  157. for (sz = 17; sz <= TEST_MAX_SIZE && sz <= SC_LARGE_MAXCLASS;
  158. sz += (sz <= SC_SMALL_MAXCLASS ? 1019 : 99991)) {
  159. void *p = mallocx(sz, 0);
  160. void *q = mallocx(sz, 0);
  161. void *in[] = {p, q};
  162. size_t in_sz = sizeof(const void *) * 2;
  163. size_t out[] = {-1, -1, -1, -1, -1, -1};
  164. size_t out_sz = sizeof(size_t) * 6;
  165. size_t out_ref[] = {-1, -1, -1, -1, -1, -1};
  166. size_t out_sz_ref = out_sz;
  167. assert_ptr_not_null(p, "test pointer allocation failed");
  168. assert_ptr_not_null(q, "test pointer allocation failed");
  169. /* Test invalid argument(s) errors */
  170. TEST_UTIL_BATCH_EINVAL(NULL, &out_sz, in, in_sz,
  171. "old is NULL");
  172. TEST_UTIL_BATCH_EINVAL(out, NULL, in, in_sz,
  173. "oldlenp is NULL");
  174. TEST_UTIL_BATCH_EINVAL(out, &out_sz, NULL, in_sz,
  175. "newp is NULL");
  176. TEST_UTIL_BATCH_EINVAL(out, &out_sz, in, 0,
  177. "newlen is zero");
  178. in_sz -= 1;
  179. TEST_UTIL_BATCH_EINVAL(out, &out_sz, in, in_sz,
  180. "newlen is not an exact multiple");
  181. in_sz += 1;
  182. out_sz_ref = out_sz -= 2 * sizeof(size_t);
  183. TEST_UTIL_BATCH_EINVAL(out, &out_sz, in, in_sz,
  184. "*oldlenp is not an exact multiple");
  185. out_sz_ref = out_sz += 2 * sizeof(size_t);
  186. in_sz -= sizeof(const void *);
  187. TEST_UTIL_BATCH_EINVAL(out, &out_sz, in, in_sz,
  188. "*oldlenp and newlen do not match");
  189. in_sz += sizeof(const void *);
  190. /* Examine output for valid calls */
  191. #define TEST_EQUAL_REF(i, message) \
  192. assert_d_eq(memcmp(out + (i) * 3, out_ref + (i) * 3, 3), 0, message)
  193. #define NFREE_READ(out, i) out[(i) * 3]
  194. #define NREGS_READ(out, i) out[(i) * 3 + 1]
  195. #define SIZE_READ(out, i) out[(i) * 3 + 2]
  196. out_sz_ref = out_sz /= 2;
  197. in_sz /= 2;
  198. TEST_UTIL_BATCH_VALID;
  199. expect_zu_le(sz, SIZE_READ(out, 0),
  200. "Extent size should be at least allocation size");
  201. expect_zu_eq(SIZE_READ(out, 0) & (PAGE - 1), 0,
  202. "Extent size should be a multiple of page size");
  203. /*
  204. * See the corresponding comment in test_query; profiling breaks
  205. * our slab count expectations.
  206. */
  207. if (sz <= SC_SMALL_MAXCLASS && !opt_prof) {
  208. expect_zu_le(NFREE_READ(out, 0), NREGS_READ(out, 0),
  209. "Extent free count exceeded region count");
  210. expect_zu_le(NREGS_READ(out, 0), SIZE_READ(out, 0),
  211. "Extent region count exceeded size");
  212. expect_zu_ne(NREGS_READ(out, 0), 0,
  213. "Extent region count must be positive");
  214. } else if (sz > SC_SMALL_MAXCLASS) {
  215. expect_zu_eq(NFREE_READ(out, 0), 0,
  216. "Extent free count should be zero");
  217. expect_zu_eq(NREGS_READ(out, 0), 1,
  218. "Extent region count should be one");
  219. }
  220. TEST_EQUAL_REF(1,
  221. "Should not overwrite content beyond what's needed");
  222. in_sz *= 2;
  223. out_sz_ref = out_sz *= 2;
  224. memcpy(out_ref, out, 3 * sizeof(size_t));
  225. TEST_UTIL_BATCH_VALID;
  226. TEST_EQUAL_REF(0, "Statistics should be stable across calls");
  227. if (sz <= SC_SMALL_MAXCLASS) {
  228. expect_zu_le(NFREE_READ(out, 1), NREGS_READ(out, 1),
  229. "Extent free count exceeded region count");
  230. } else {
  231. expect_zu_eq(NFREE_READ(out, 0), 0,
  232. "Extent free count should be zero");
  233. }
  234. expect_zu_eq(NREGS_READ(out, 0), NREGS_READ(out, 1),
  235. "Extent region count should be same for same region size");
  236. expect_zu_eq(SIZE_READ(out, 0), SIZE_READ(out, 1),
  237. "Extent size should be same for same region size");
  238. #undef SIZE_READ
  239. #undef NREGS_READ
  240. #undef NFREE_READ
  241. #undef TEST_EQUAL_REF
  242. free(q);
  243. free(p);
  244. }
  245. }
  246. TEST_END
  247. int
  248. main(void) {
  249. assert_zu_lt(SC_SMALL_MAXCLASS + 100000, TEST_MAX_SIZE,
  250. "Test case cannot cover large classes");
  251. return test(test_query, test_batch);
  252. }