edata_cache.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. #include "test/jemalloc_test.h"
  2. #include "jemalloc/internal/edata_cache.h"
  3. static void
  4. test_edata_cache_init(edata_cache_t *edata_cache) {
  5. base_t *base = base_new(TSDN_NULL, /* ind */ 1,
  6. &ehooks_default_extent_hooks, /* metadata_use_hooks */ true);
  7. assert_ptr_not_null(base, "");
  8. bool err = edata_cache_init(edata_cache, base);
  9. assert_false(err, "");
  10. }
  11. static void
  12. test_edata_cache_destroy(edata_cache_t *edata_cache) {
  13. base_delete(TSDN_NULL, edata_cache->base);
  14. }
  15. TEST_BEGIN(test_edata_cache) {
  16. edata_cache_t ec;
  17. test_edata_cache_init(&ec);
  18. /* Get one */
  19. edata_t *ed1 = edata_cache_get(TSDN_NULL, &ec);
  20. assert_ptr_not_null(ed1, "");
  21. /* Cache should be empty */
  22. assert_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, "");
  23. /* Get another */
  24. edata_t *ed2 = edata_cache_get(TSDN_NULL, &ec);
  25. assert_ptr_not_null(ed2, "");
  26. /* Still empty */
  27. assert_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, "");
  28. /* Put one back, and the cache should now have one item */
  29. edata_cache_put(TSDN_NULL, &ec, ed1);
  30. assert_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 1, "");
  31. /* Reallocating should reuse the item, and leave an empty cache. */
  32. edata_t *ed1_again = edata_cache_get(TSDN_NULL, &ec);
  33. assert_ptr_eq(ed1, ed1_again, "");
  34. assert_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, "");
  35. test_edata_cache_destroy(&ec);
  36. }
  37. TEST_END
  38. static size_t
  39. ecf_count(edata_cache_fast_t *ecf) {
  40. size_t count = 0;
  41. edata_t *cur;
  42. ql_foreach(cur, &ecf->list.head, ql_link_inactive) {
  43. count++;
  44. }
  45. return count;
  46. }
  47. TEST_BEGIN(test_edata_cache_fast_simple) {
  48. edata_cache_t ec;
  49. edata_cache_fast_t ecf;
  50. test_edata_cache_init(&ec);
  51. edata_cache_fast_init(&ecf, &ec);
  52. edata_t *ed1 = edata_cache_fast_get(TSDN_NULL, &ecf);
  53. expect_ptr_not_null(ed1, "");
  54. expect_zu_eq(ecf_count(&ecf), 0, "");
  55. expect_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, "");
  56. edata_t *ed2 = edata_cache_fast_get(TSDN_NULL, &ecf);
  57. expect_ptr_not_null(ed2, "");
  58. expect_zu_eq(ecf_count(&ecf), 0, "");
  59. expect_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, "");
  60. edata_cache_fast_put(TSDN_NULL, &ecf, ed1);
  61. expect_zu_eq(ecf_count(&ecf), 1, "");
  62. expect_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, "");
  63. edata_cache_fast_put(TSDN_NULL, &ecf, ed2);
  64. expect_zu_eq(ecf_count(&ecf), 2, "");
  65. expect_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, "");
  66. /* LIFO ordering. */
  67. expect_ptr_eq(ed2, edata_cache_fast_get(TSDN_NULL, &ecf), "");
  68. expect_zu_eq(ecf_count(&ecf), 1, "");
  69. expect_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, "");
  70. expect_ptr_eq(ed1, edata_cache_fast_get(TSDN_NULL, &ecf), "");
  71. expect_zu_eq(ecf_count(&ecf), 0, "");
  72. expect_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, "");
  73. test_edata_cache_destroy(&ec);
  74. }
  75. TEST_END
  76. TEST_BEGIN(test_edata_cache_fill) {
  77. edata_cache_t ec;
  78. edata_cache_fast_t ecf;
  79. test_edata_cache_init(&ec);
  80. edata_cache_fast_init(&ecf, &ec);
  81. edata_t *allocs[EDATA_CACHE_FAST_FILL * 2];
  82. /*
  83. * If the fallback cache can't satisfy the request, we shouldn't do
  84. * extra allocations until compelled to. Put half the fill goal in the
  85. * fallback.
  86. */
  87. for (int i = 0; i < EDATA_CACHE_FAST_FILL / 2; i++) {
  88. allocs[i] = edata_cache_get(TSDN_NULL, &ec);
  89. }
  90. for (int i = 0; i < EDATA_CACHE_FAST_FILL / 2; i++) {
  91. edata_cache_put(TSDN_NULL, &ec, allocs[i]);
  92. }
  93. expect_zu_eq(EDATA_CACHE_FAST_FILL / 2,
  94. atomic_load_zu(&ec.count, ATOMIC_RELAXED), "");
  95. allocs[0] = edata_cache_fast_get(TSDN_NULL, &ecf);
  96. expect_zu_eq(EDATA_CACHE_FAST_FILL / 2 - 1, ecf_count(&ecf),
  97. "Should have grabbed all edatas available but no more.");
  98. for (int i = 1; i < EDATA_CACHE_FAST_FILL / 2; i++) {
  99. allocs[i] = edata_cache_fast_get(TSDN_NULL, &ecf);
  100. expect_ptr_not_null(allocs[i], "");
  101. }
  102. expect_zu_eq(0, ecf_count(&ecf), "");
  103. /* When forced, we should alloc from the base. */
  104. edata_t *edata = edata_cache_fast_get(TSDN_NULL, &ecf);
  105. expect_ptr_not_null(edata, "");
  106. expect_zu_eq(0, ecf_count(&ecf), "Allocated more than necessary");
  107. expect_zu_eq(0, atomic_load_zu(&ec.count, ATOMIC_RELAXED),
  108. "Allocated more than necessary");
  109. /*
  110. * We should correctly fill in the common case where the fallback isn't
  111. * exhausted, too.
  112. */
  113. for (int i = 0; i < EDATA_CACHE_FAST_FILL * 2; i++) {
  114. allocs[i] = edata_cache_get(TSDN_NULL, &ec);
  115. expect_ptr_not_null(allocs[i], "");
  116. }
  117. for (int i = 0; i < EDATA_CACHE_FAST_FILL * 2; i++) {
  118. edata_cache_put(TSDN_NULL, &ec, allocs[i]);
  119. }
  120. allocs[0] = edata_cache_fast_get(TSDN_NULL, &ecf);
  121. expect_zu_eq(EDATA_CACHE_FAST_FILL - 1, ecf_count(&ecf), "");
  122. expect_zu_eq(EDATA_CACHE_FAST_FILL,
  123. atomic_load_zu(&ec.count, ATOMIC_RELAXED), "");
  124. for (int i = 1; i < EDATA_CACHE_FAST_FILL; i++) {
  125. expect_zu_eq(EDATA_CACHE_FAST_FILL - i, ecf_count(&ecf), "");
  126. expect_zu_eq(EDATA_CACHE_FAST_FILL,
  127. atomic_load_zu(&ec.count, ATOMIC_RELAXED), "");
  128. allocs[i] = edata_cache_fast_get(TSDN_NULL, &ecf);
  129. expect_ptr_not_null(allocs[i], "");
  130. }
  131. expect_zu_eq(0, ecf_count(&ecf), "");
  132. expect_zu_eq(EDATA_CACHE_FAST_FILL,
  133. atomic_load_zu(&ec.count, ATOMIC_RELAXED), "");
  134. allocs[0] = edata_cache_fast_get(TSDN_NULL, &ecf);
  135. expect_zu_eq(EDATA_CACHE_FAST_FILL - 1, ecf_count(&ecf), "");
  136. expect_zu_eq(0, atomic_load_zu(&ec.count, ATOMIC_RELAXED), "");
  137. for (int i = 1; i < EDATA_CACHE_FAST_FILL; i++) {
  138. expect_zu_eq(EDATA_CACHE_FAST_FILL - i, ecf_count(&ecf), "");
  139. expect_zu_eq(0, atomic_load_zu(&ec.count, ATOMIC_RELAXED), "");
  140. allocs[i] = edata_cache_fast_get(TSDN_NULL, &ecf);
  141. expect_ptr_not_null(allocs[i], "");
  142. }
  143. expect_zu_eq(0, ecf_count(&ecf), "");
  144. expect_zu_eq(0, atomic_load_zu(&ec.count, ATOMIC_RELAXED), "");
  145. test_edata_cache_destroy(&ec);
  146. }
  147. TEST_END
  148. TEST_BEGIN(test_edata_cache_disable) {
  149. edata_cache_t ec;
  150. edata_cache_fast_t ecf;
  151. test_edata_cache_init(&ec);
  152. edata_cache_fast_init(&ecf, &ec);
  153. for (int i = 0; i < EDATA_CACHE_FAST_FILL; i++) {
  154. edata_t *edata = edata_cache_get(TSDN_NULL, &ec);
  155. expect_ptr_not_null(edata, "");
  156. edata_cache_fast_put(TSDN_NULL, &ecf, edata);
  157. }
  158. expect_zu_eq(EDATA_CACHE_FAST_FILL, ecf_count(&ecf), "");
  159. expect_zu_eq(0, atomic_load_zu(&ec.count, ATOMIC_RELAXED), "");
  160. edata_cache_fast_disable(TSDN_NULL, &ecf);
  161. expect_zu_eq(0, ecf_count(&ecf), "");
  162. expect_zu_eq(EDATA_CACHE_FAST_FILL,
  163. atomic_load_zu(&ec.count, ATOMIC_RELAXED), "Disabling should flush");
  164. edata_t *edata = edata_cache_fast_get(TSDN_NULL, &ecf);
  165. expect_zu_eq(0, ecf_count(&ecf), "");
  166. expect_zu_eq(EDATA_CACHE_FAST_FILL - 1,
  167. atomic_load_zu(&ec.count, ATOMIC_RELAXED),
  168. "Disabled ecf should forward on get");
  169. edata_cache_fast_put(TSDN_NULL, &ecf, edata);
  170. expect_zu_eq(0, ecf_count(&ecf), "");
  171. expect_zu_eq(EDATA_CACHE_FAST_FILL,
  172. atomic_load_zu(&ec.count, ATOMIC_RELAXED),
  173. "Disabled ecf should forward on put");
  174. test_edata_cache_destroy(&ec);
  175. }
  176. TEST_END
  177. int
  178. main(void) {
  179. return test(
  180. test_edata_cache,
  181. test_edata_cache_fast_simple,
  182. test_edata_cache_fill,
  183. test_edata_cache_disable);
  184. }