1*7bdf38e5Schristos #include "test/jemalloc_test.h" 2*7bdf38e5Schristos 3*7bdf38e5Schristos #include "jemalloc/internal/psset.h" 4*7bdf38e5Schristos 5*7bdf38e5Schristos #define PAGESLAB_ADDR ((void *)(1234 * HUGEPAGE)) 6*7bdf38e5Schristos #define PAGESLAB_AGE 5678 7*7bdf38e5Schristos 8*7bdf38e5Schristos #define ALLOC_ARENA_IND 111 9*7bdf38e5Schristos #define ALLOC_ESN 222 10*7bdf38e5Schristos 11*7bdf38e5Schristos static void 12*7bdf38e5Schristos edata_init_test(edata_t *edata) { 13*7bdf38e5Schristos memset(edata, 0, sizeof(*edata)); 14*7bdf38e5Schristos edata_arena_ind_set(edata, ALLOC_ARENA_IND); 15*7bdf38e5Schristos edata_esn_set(edata, ALLOC_ESN); 16*7bdf38e5Schristos } 17*7bdf38e5Schristos 18*7bdf38e5Schristos static void 19*7bdf38e5Schristos test_psset_fake_purge(hpdata_t *ps) { 20*7bdf38e5Schristos hpdata_purge_state_t purge_state; 21*7bdf38e5Schristos hpdata_alloc_allowed_set(ps, false); 22*7bdf38e5Schristos hpdata_purge_begin(ps, &purge_state); 23*7bdf38e5Schristos void *addr; 24*7bdf38e5Schristos size_t size; 25*7bdf38e5Schristos while (hpdata_purge_next(ps, &purge_state, &addr, &size)) { 26*7bdf38e5Schristos } 27*7bdf38e5Schristos hpdata_purge_end(ps, &purge_state); 28*7bdf38e5Schristos hpdata_alloc_allowed_set(ps, true); 29*7bdf38e5Schristos } 30*7bdf38e5Schristos 31*7bdf38e5Schristos static void 32*7bdf38e5Schristos test_psset_alloc_new(psset_t *psset, hpdata_t *ps, edata_t *r_edata, 33*7bdf38e5Schristos size_t size) { 34*7bdf38e5Schristos hpdata_assert_empty(ps); 35*7bdf38e5Schristos 36*7bdf38e5Schristos test_psset_fake_purge(ps); 37*7bdf38e5Schristos 38*7bdf38e5Schristos psset_insert(psset, ps); 39*7bdf38e5Schristos psset_update_begin(psset, ps); 40*7bdf38e5Schristos 41*7bdf38e5Schristos void *addr = hpdata_reserve_alloc(ps, size); 42*7bdf38e5Schristos edata_init(r_edata, edata_arena_ind_get(r_edata), addr, size, 43*7bdf38e5Schristos /* slab */ false, SC_NSIZES, /* sn */ 0, extent_state_active, 44*7bdf38e5Schristos /* zeroed */ false, /* committed */ true, EXTENT_PAI_HPA, 45*7bdf38e5Schristos EXTENT_NOT_HEAD); 46*7bdf38e5Schristos edata_ps_set(r_edata, ps); 47*7bdf38e5Schristos psset_update_end(psset, ps); 48*7bdf38e5Schristos } 49*7bdf38e5Schristos 50*7bdf38e5Schristos static bool 51*7bdf38e5Schristos test_psset_alloc_reuse(psset_t *psset, edata_t *r_edata, size_t size) { 52*7bdf38e5Schristos hpdata_t *ps = psset_pick_alloc(psset, size); 53*7bdf38e5Schristos if (ps == NULL) { 54*7bdf38e5Schristos return true; 55*7bdf38e5Schristos } 56*7bdf38e5Schristos psset_update_begin(psset, ps); 57*7bdf38e5Schristos void *addr = hpdata_reserve_alloc(ps, size); 58*7bdf38e5Schristos edata_init(r_edata, edata_arena_ind_get(r_edata), addr, size, 59*7bdf38e5Schristos /* slab */ false, SC_NSIZES, /* sn */ 0, extent_state_active, 60*7bdf38e5Schristos /* zeroed */ false, /* committed */ true, EXTENT_PAI_HPA, 61*7bdf38e5Schristos EXTENT_NOT_HEAD); 62*7bdf38e5Schristos edata_ps_set(r_edata, ps); 63*7bdf38e5Schristos psset_update_end(psset, ps); 64*7bdf38e5Schristos return false; 65*7bdf38e5Schristos } 66*7bdf38e5Schristos 67*7bdf38e5Schristos static hpdata_t * 68*7bdf38e5Schristos test_psset_dalloc(psset_t *psset, edata_t *edata) { 69*7bdf38e5Schristos hpdata_t *ps = edata_ps_get(edata); 70*7bdf38e5Schristos psset_update_begin(psset, ps); 71*7bdf38e5Schristos hpdata_unreserve(ps, edata_addr_get(edata), edata_size_get(edata)); 72*7bdf38e5Schristos psset_update_end(psset, ps); 73*7bdf38e5Schristos if (hpdata_empty(ps)) { 74*7bdf38e5Schristos psset_remove(psset, ps); 75*7bdf38e5Schristos return ps; 76*7bdf38e5Schristos } else { 77*7bdf38e5Schristos return NULL; 78*7bdf38e5Schristos } 79*7bdf38e5Schristos } 80*7bdf38e5Schristos 81*7bdf38e5Schristos static void 82*7bdf38e5Schristos edata_expect(edata_t *edata, size_t page_offset, size_t page_cnt) { 83*7bdf38e5Schristos /* 84*7bdf38e5Schristos * Note that allocations should get the arena ind of their home 85*7bdf38e5Schristos * arena, *not* the arena ind of the pageslab allocator. 86*7bdf38e5Schristos */ 87*7bdf38e5Schristos expect_u_eq(ALLOC_ARENA_IND, edata_arena_ind_get(edata), 88*7bdf38e5Schristos "Arena ind changed"); 89*7bdf38e5Schristos expect_ptr_eq( 90*7bdf38e5Schristos (void *)((uintptr_t)PAGESLAB_ADDR + (page_offset << LG_PAGE)), 91*7bdf38e5Schristos edata_addr_get(edata), "Didn't allocate in order"); 92*7bdf38e5Schristos expect_zu_eq(page_cnt << LG_PAGE, edata_size_get(edata), ""); 93*7bdf38e5Schristos expect_false(edata_slab_get(edata), ""); 94*7bdf38e5Schristos expect_u_eq(SC_NSIZES, edata_szind_get_maybe_invalid(edata), 95*7bdf38e5Schristos ""); 96*7bdf38e5Schristos expect_u64_eq(0, edata_sn_get(edata), ""); 97*7bdf38e5Schristos expect_d_eq(edata_state_get(edata), extent_state_active, ""); 98*7bdf38e5Schristos expect_false(edata_zeroed_get(edata), ""); 99*7bdf38e5Schristos expect_true(edata_committed_get(edata), ""); 100*7bdf38e5Schristos expect_d_eq(EXTENT_PAI_HPA, edata_pai_get(edata), ""); 101*7bdf38e5Schristos expect_false(edata_is_head_get(edata), ""); 102*7bdf38e5Schristos } 103*7bdf38e5Schristos 104*7bdf38e5Schristos TEST_BEGIN(test_empty) { 105*7bdf38e5Schristos bool err; 106*7bdf38e5Schristos hpdata_t pageslab; 107*7bdf38e5Schristos hpdata_init(&pageslab, PAGESLAB_ADDR, PAGESLAB_AGE); 108*7bdf38e5Schristos 109*7bdf38e5Schristos edata_t alloc; 110*7bdf38e5Schristos edata_init_test(&alloc); 111*7bdf38e5Schristos 112*7bdf38e5Schristos psset_t psset; 113*7bdf38e5Schristos psset_init(&psset); 114*7bdf38e5Schristos 115*7bdf38e5Schristos /* Empty psset should return fail allocations. */ 116*7bdf38e5Schristos err = test_psset_alloc_reuse(&psset, &alloc, PAGE); 117*7bdf38e5Schristos expect_true(err, "Empty psset succeeded in an allocation."); 118*7bdf38e5Schristos } 119*7bdf38e5Schristos TEST_END 120*7bdf38e5Schristos 121*7bdf38e5Schristos TEST_BEGIN(test_fill) { 122*7bdf38e5Schristos bool err; 123*7bdf38e5Schristos 124*7bdf38e5Schristos hpdata_t pageslab; 125*7bdf38e5Schristos hpdata_init(&pageslab, PAGESLAB_ADDR, PAGESLAB_AGE); 126*7bdf38e5Schristos 127*7bdf38e5Schristos edata_t alloc[HUGEPAGE_PAGES]; 128*7bdf38e5Schristos 129*7bdf38e5Schristos psset_t psset; 130*7bdf38e5Schristos psset_init(&psset); 131*7bdf38e5Schristos 132*7bdf38e5Schristos edata_init_test(&alloc[0]); 133*7bdf38e5Schristos test_psset_alloc_new(&psset, &pageslab, &alloc[0], PAGE); 134*7bdf38e5Schristos for (size_t i = 1; i < HUGEPAGE_PAGES; i++) { 135*7bdf38e5Schristos edata_init_test(&alloc[i]); 136*7bdf38e5Schristos err = test_psset_alloc_reuse(&psset, &alloc[i], PAGE); 137*7bdf38e5Schristos expect_false(err, "Nonempty psset failed page allocation."); 138*7bdf38e5Schristos } 139*7bdf38e5Schristos 140*7bdf38e5Schristos for (size_t i = 0; i < HUGEPAGE_PAGES; i++) { 141*7bdf38e5Schristos edata_t *edata = &alloc[i]; 142*7bdf38e5Schristos edata_expect(edata, i, 1); 143*7bdf38e5Schristos } 144*7bdf38e5Schristos 145*7bdf38e5Schristos /* The pageslab, and thus psset, should now have no allocations. */ 146*7bdf38e5Schristos edata_t extra_alloc; 147*7bdf38e5Schristos edata_init_test(&extra_alloc); 148*7bdf38e5Schristos err = test_psset_alloc_reuse(&psset, &extra_alloc, PAGE); 149*7bdf38e5Schristos expect_true(err, "Alloc succeeded even though psset should be empty"); 150*7bdf38e5Schristos } 151*7bdf38e5Schristos TEST_END 152*7bdf38e5Schristos 153*7bdf38e5Schristos TEST_BEGIN(test_reuse) { 154*7bdf38e5Schristos bool err; 155*7bdf38e5Schristos hpdata_t *ps; 156*7bdf38e5Schristos 157*7bdf38e5Schristos hpdata_t pageslab; 158*7bdf38e5Schristos hpdata_init(&pageslab, PAGESLAB_ADDR, PAGESLAB_AGE); 159*7bdf38e5Schristos 160*7bdf38e5Schristos edata_t alloc[HUGEPAGE_PAGES]; 161*7bdf38e5Schristos 162*7bdf38e5Schristos psset_t psset; 163*7bdf38e5Schristos psset_init(&psset); 164*7bdf38e5Schristos 165*7bdf38e5Schristos edata_init_test(&alloc[0]); 166*7bdf38e5Schristos test_psset_alloc_new(&psset, &pageslab, &alloc[0], PAGE); 167*7bdf38e5Schristos for (size_t i = 1; i < HUGEPAGE_PAGES; i++) { 168*7bdf38e5Schristos edata_init_test(&alloc[i]); 169*7bdf38e5Schristos err = test_psset_alloc_reuse(&psset, &alloc[i], PAGE); 170*7bdf38e5Schristos expect_false(err, "Nonempty psset failed page allocation."); 171*7bdf38e5Schristos } 172*7bdf38e5Schristos 173*7bdf38e5Schristos /* Free odd indices. */ 174*7bdf38e5Schristos for (size_t i = 0; i < HUGEPAGE_PAGES; i ++) { 175*7bdf38e5Schristos if (i % 2 == 0) { 176*7bdf38e5Schristos continue; 177*7bdf38e5Schristos } 178*7bdf38e5Schristos ps = test_psset_dalloc(&psset, &alloc[i]); 179*7bdf38e5Schristos expect_ptr_null(ps, "Nonempty pageslab evicted"); 180*7bdf38e5Schristos } 181*7bdf38e5Schristos /* Realloc into them. */ 182*7bdf38e5Schristos for (size_t i = 0; i < HUGEPAGE_PAGES; i++) { 183*7bdf38e5Schristos if (i % 2 == 0) { 184*7bdf38e5Schristos continue; 185*7bdf38e5Schristos } 186*7bdf38e5Schristos err = test_psset_alloc_reuse(&psset, &alloc[i], PAGE); 187*7bdf38e5Schristos expect_false(err, "Nonempty psset failed page allocation."); 188*7bdf38e5Schristos edata_expect(&alloc[i], i, 1); 189*7bdf38e5Schristos } 190*7bdf38e5Schristos /* Now, free the pages at indices 0 or 1 mod 2. */ 191*7bdf38e5Schristos for (size_t i = 0; i < HUGEPAGE_PAGES; i++) { 192*7bdf38e5Schristos if (i % 4 > 1) { 193*7bdf38e5Schristos continue; 194*7bdf38e5Schristos } 195*7bdf38e5Schristos ps = test_psset_dalloc(&psset, &alloc[i]); 196*7bdf38e5Schristos expect_ptr_null(ps, "Nonempty pageslab evicted"); 197*7bdf38e5Schristos } 198*7bdf38e5Schristos /* And realloc 2-page allocations into them. */ 199*7bdf38e5Schristos for (size_t i = 0; i < HUGEPAGE_PAGES; i++) { 200*7bdf38e5Schristos if (i % 4 != 0) { 201*7bdf38e5Schristos continue; 202*7bdf38e5Schristos } 203*7bdf38e5Schristos err = test_psset_alloc_reuse(&psset, &alloc[i], 2 * PAGE); 204*7bdf38e5Schristos expect_false(err, "Nonempty psset failed page allocation."); 205*7bdf38e5Schristos edata_expect(&alloc[i], i, 2); 206*7bdf38e5Schristos } 207*7bdf38e5Schristos /* Free all the 2-page allocations. */ 208*7bdf38e5Schristos for (size_t i = 0; i < HUGEPAGE_PAGES; i++) { 209*7bdf38e5Schristos if (i % 4 != 0) { 210*7bdf38e5Schristos continue; 211*7bdf38e5Schristos } 212*7bdf38e5Schristos ps = test_psset_dalloc(&psset, &alloc[i]); 213*7bdf38e5Schristos expect_ptr_null(ps, "Nonempty pageslab evicted"); 214*7bdf38e5Schristos } 215*7bdf38e5Schristos /* 216*7bdf38e5Schristos * Free up a 1-page hole next to a 2-page hole, but somewhere in the 217*7bdf38e5Schristos * middle of the pageslab. Index 11 should be right before such a hole 218*7bdf38e5Schristos * (since 12 % 4 == 0). 219*7bdf38e5Schristos */ 220*7bdf38e5Schristos size_t index_of_3 = 11; 221*7bdf38e5Schristos ps = test_psset_dalloc(&psset, &alloc[index_of_3]); 222*7bdf38e5Schristos expect_ptr_null(ps, "Nonempty pageslab evicted"); 223*7bdf38e5Schristos err = test_psset_alloc_reuse(&psset, &alloc[index_of_3], 3 * PAGE); 224*7bdf38e5Schristos expect_false(err, "Should have been able to find alloc."); 225*7bdf38e5Schristos edata_expect(&alloc[index_of_3], index_of_3, 3); 226*7bdf38e5Schristos 227*7bdf38e5Schristos /* 228*7bdf38e5Schristos * Free up a 4-page hole at the end. Recall that the pages at offsets 0 229*7bdf38e5Schristos * and 1 mod 4 were freed above, so we just have to free the last 230*7bdf38e5Schristos * allocations. 231*7bdf38e5Schristos */ 232*7bdf38e5Schristos ps = test_psset_dalloc(&psset, &alloc[HUGEPAGE_PAGES - 1]); 233*7bdf38e5Schristos expect_ptr_null(ps, "Nonempty pageslab evicted"); 234*7bdf38e5Schristos ps = test_psset_dalloc(&psset, &alloc[HUGEPAGE_PAGES - 2]); 235*7bdf38e5Schristos expect_ptr_null(ps, "Nonempty pageslab evicted"); 236*7bdf38e5Schristos 237*7bdf38e5Schristos /* Make sure we can satisfy an allocation at the very end of a slab. */ 238*7bdf38e5Schristos size_t index_of_4 = HUGEPAGE_PAGES - 4; 239*7bdf38e5Schristos err = test_psset_alloc_reuse(&psset, &alloc[index_of_4], 4 * PAGE); 240*7bdf38e5Schristos expect_false(err, "Should have been able to find alloc."); 241*7bdf38e5Schristos edata_expect(&alloc[index_of_4], index_of_4, 4); 242*7bdf38e5Schristos } 243*7bdf38e5Schristos TEST_END 244*7bdf38e5Schristos 245*7bdf38e5Schristos TEST_BEGIN(test_evict) { 246*7bdf38e5Schristos bool err; 247*7bdf38e5Schristos hpdata_t *ps; 248*7bdf38e5Schristos 249*7bdf38e5Schristos hpdata_t pageslab; 250*7bdf38e5Schristos hpdata_init(&pageslab, PAGESLAB_ADDR, PAGESLAB_AGE); 251*7bdf38e5Schristos 252*7bdf38e5Schristos edata_t alloc[HUGEPAGE_PAGES]; 253*7bdf38e5Schristos 254*7bdf38e5Schristos psset_t psset; 255*7bdf38e5Schristos psset_init(&psset); 256*7bdf38e5Schristos 257*7bdf38e5Schristos /* Alloc the whole slab. */ 258*7bdf38e5Schristos edata_init_test(&alloc[0]); 259*7bdf38e5Schristos test_psset_alloc_new(&psset, &pageslab, &alloc[0], PAGE); 260*7bdf38e5Schristos for (size_t i = 1; i < HUGEPAGE_PAGES; i++) { 261*7bdf38e5Schristos edata_init_test(&alloc[i]); 262*7bdf38e5Schristos err = test_psset_alloc_reuse(&psset, &alloc[i], PAGE); 263*7bdf38e5Schristos expect_false(err, "Unxpected allocation failure"); 264*7bdf38e5Schristos } 265*7bdf38e5Schristos 266*7bdf38e5Schristos /* Dealloc the whole slab, going forwards. */ 267*7bdf38e5Schristos for (size_t i = 0; i < HUGEPAGE_PAGES - 1; i++) { 268*7bdf38e5Schristos ps = test_psset_dalloc(&psset, &alloc[i]); 269*7bdf38e5Schristos expect_ptr_null(ps, "Nonempty pageslab evicted"); 270*7bdf38e5Schristos } 271*7bdf38e5Schristos ps = test_psset_dalloc(&psset, &alloc[HUGEPAGE_PAGES - 1]); 272*7bdf38e5Schristos expect_ptr_eq(&pageslab, ps, "Empty pageslab not evicted."); 273*7bdf38e5Schristos 274*7bdf38e5Schristos err = test_psset_alloc_reuse(&psset, &alloc[0], PAGE); 275*7bdf38e5Schristos expect_true(err, "psset should be empty."); 276*7bdf38e5Schristos } 277*7bdf38e5Schristos TEST_END 278*7bdf38e5Schristos 279*7bdf38e5Schristos TEST_BEGIN(test_multi_pageslab) { 280*7bdf38e5Schristos bool err; 281*7bdf38e5Schristos hpdata_t *ps; 282*7bdf38e5Schristos 283*7bdf38e5Schristos hpdata_t pageslab[2]; 284*7bdf38e5Schristos hpdata_init(&pageslab[0], PAGESLAB_ADDR, PAGESLAB_AGE); 285*7bdf38e5Schristos hpdata_init(&pageslab[1], 286*7bdf38e5Schristos (void *)((uintptr_t)PAGESLAB_ADDR + HUGEPAGE), 287*7bdf38e5Schristos PAGESLAB_AGE + 1); 288*7bdf38e5Schristos 289*7bdf38e5Schristos edata_t alloc[2][HUGEPAGE_PAGES]; 290*7bdf38e5Schristos 291*7bdf38e5Schristos psset_t psset; 292*7bdf38e5Schristos psset_init(&psset); 293*7bdf38e5Schristos 294*7bdf38e5Schristos /* Insert both slabs. */ 295*7bdf38e5Schristos edata_init_test(&alloc[0][0]); 296*7bdf38e5Schristos test_psset_alloc_new(&psset, &pageslab[0], &alloc[0][0], PAGE); 297*7bdf38e5Schristos edata_init_test(&alloc[1][0]); 298*7bdf38e5Schristos test_psset_alloc_new(&psset, &pageslab[1], &alloc[1][0], PAGE); 299*7bdf38e5Schristos 300*7bdf38e5Schristos /* Fill them both up; make sure we do so in first-fit order. */ 301*7bdf38e5Schristos for (size_t i = 0; i < 2; i++) { 302*7bdf38e5Schristos for (size_t j = 1; j < HUGEPAGE_PAGES; j++) { 303*7bdf38e5Schristos edata_init_test(&alloc[i][j]); 304*7bdf38e5Schristos err = test_psset_alloc_reuse(&psset, &alloc[i][j], PAGE); 305*7bdf38e5Schristos expect_false(err, 306*7bdf38e5Schristos "Nonempty psset failed page allocation."); 307*7bdf38e5Schristos assert_ptr_eq(&pageslab[i], edata_ps_get(&alloc[i][j]), 308*7bdf38e5Schristos "Didn't pick pageslabs in first-fit"); 309*7bdf38e5Schristos } 310*7bdf38e5Schristos } 311*7bdf38e5Schristos 312*7bdf38e5Schristos /* 313*7bdf38e5Schristos * Free up a 2-page hole in the earlier slab, and a 1-page one in the 314*7bdf38e5Schristos * later one. We should still pick the later one. 315*7bdf38e5Schristos */ 316*7bdf38e5Schristos ps = test_psset_dalloc(&psset, &alloc[0][0]); 317*7bdf38e5Schristos expect_ptr_null(ps, "Unexpected eviction"); 318*7bdf38e5Schristos ps = test_psset_dalloc(&psset, &alloc[0][1]); 319*7bdf38e5Schristos expect_ptr_null(ps, "Unexpected eviction"); 320*7bdf38e5Schristos ps = test_psset_dalloc(&psset, &alloc[1][0]); 321*7bdf38e5Schristos expect_ptr_null(ps, "Unexpected eviction"); 322*7bdf38e5Schristos err = test_psset_alloc_reuse(&psset, &alloc[0][0], PAGE); 323*7bdf38e5Schristos expect_ptr_eq(&pageslab[1], edata_ps_get(&alloc[0][0]), 324*7bdf38e5Schristos "Should have picked the fuller pageslab"); 325*7bdf38e5Schristos 326*7bdf38e5Schristos /* 327*7bdf38e5Schristos * Now both slabs have 1-page holes. Free up a second one in the later 328*7bdf38e5Schristos * slab. 329*7bdf38e5Schristos */ 330*7bdf38e5Schristos ps = test_psset_dalloc(&psset, &alloc[1][1]); 331*7bdf38e5Schristos expect_ptr_null(ps, "Unexpected eviction"); 332*7bdf38e5Schristos 333*7bdf38e5Schristos /* 334*7bdf38e5Schristos * We should be able to allocate a 2-page object, even though an earlier 335*7bdf38e5Schristos * size class is nonempty. 336*7bdf38e5Schristos */ 337*7bdf38e5Schristos err = test_psset_alloc_reuse(&psset, &alloc[1][0], 2 * PAGE); 338*7bdf38e5Schristos expect_false(err, "Allocation should have succeeded"); 339*7bdf38e5Schristos } 340*7bdf38e5Schristos TEST_END 341*7bdf38e5Schristos 342*7bdf38e5Schristos static void 343*7bdf38e5Schristos stats_expect_empty(psset_bin_stats_t *stats) { 344*7bdf38e5Schristos assert_zu_eq(0, stats->npageslabs, 345*7bdf38e5Schristos "Supposedly empty bin had positive npageslabs"); 346*7bdf38e5Schristos expect_zu_eq(0, stats->nactive, "Unexpected nonempty bin" 347*7bdf38e5Schristos "Supposedly empty bin had positive nactive"); 348*7bdf38e5Schristos } 349*7bdf38e5Schristos 350*7bdf38e5Schristos static void 351*7bdf38e5Schristos stats_expect(psset_t *psset, size_t nactive) { 352*7bdf38e5Schristos if (nactive == HUGEPAGE_PAGES) { 353*7bdf38e5Schristos expect_zu_eq(1, psset->stats.full_slabs[0].npageslabs, 354*7bdf38e5Schristos "Expected a full slab"); 355*7bdf38e5Schristos expect_zu_eq(HUGEPAGE_PAGES, 356*7bdf38e5Schristos psset->stats.full_slabs[0].nactive, 357*7bdf38e5Schristos "Should have exactly filled the bin"); 358*7bdf38e5Schristos } else { 359*7bdf38e5Schristos stats_expect_empty(&psset->stats.full_slabs[0]); 360*7bdf38e5Schristos } 361*7bdf38e5Schristos size_t ninactive = HUGEPAGE_PAGES - nactive; 362*7bdf38e5Schristos pszind_t nonempty_pind = PSSET_NPSIZES; 363*7bdf38e5Schristos if (ninactive != 0 && ninactive < HUGEPAGE_PAGES) { 364*7bdf38e5Schristos nonempty_pind = sz_psz2ind(sz_psz_quantize_floor( 365*7bdf38e5Schristos ninactive << LG_PAGE)); 366*7bdf38e5Schristos } 367*7bdf38e5Schristos for (pszind_t i = 0; i < PSSET_NPSIZES; i++) { 368*7bdf38e5Schristos if (i == nonempty_pind) { 369*7bdf38e5Schristos assert_zu_eq(1, 370*7bdf38e5Schristos psset->stats.nonfull_slabs[i][0].npageslabs, 371*7bdf38e5Schristos "Should have found a slab"); 372*7bdf38e5Schristos expect_zu_eq(nactive, 373*7bdf38e5Schristos psset->stats.nonfull_slabs[i][0].nactive, 374*7bdf38e5Schristos "Mismatch in active pages"); 375*7bdf38e5Schristos } else { 376*7bdf38e5Schristos stats_expect_empty(&psset->stats.nonfull_slabs[i][0]); 377*7bdf38e5Schristos } 378*7bdf38e5Schristos } 379*7bdf38e5Schristos expect_zu_eq(nactive, psset_nactive(psset), ""); 380*7bdf38e5Schristos } 381*7bdf38e5Schristos 382*7bdf38e5Schristos TEST_BEGIN(test_stats) { 383*7bdf38e5Schristos bool err; 384*7bdf38e5Schristos 385*7bdf38e5Schristos hpdata_t pageslab; 386*7bdf38e5Schristos hpdata_init(&pageslab, PAGESLAB_ADDR, PAGESLAB_AGE); 387*7bdf38e5Schristos 388*7bdf38e5Schristos edata_t alloc[HUGEPAGE_PAGES]; 389*7bdf38e5Schristos 390*7bdf38e5Schristos psset_t psset; 391*7bdf38e5Schristos psset_init(&psset); 392*7bdf38e5Schristos stats_expect(&psset, 0); 393*7bdf38e5Schristos 394*7bdf38e5Schristos edata_init_test(&alloc[0]); 395*7bdf38e5Schristos test_psset_alloc_new(&psset, &pageslab, &alloc[0], PAGE); 396*7bdf38e5Schristos for (size_t i = 1; i < HUGEPAGE_PAGES; i++) { 397*7bdf38e5Schristos stats_expect(&psset, i); 398*7bdf38e5Schristos edata_init_test(&alloc[i]); 399*7bdf38e5Schristos err = test_psset_alloc_reuse(&psset, &alloc[i], PAGE); 400*7bdf38e5Schristos expect_false(err, "Nonempty psset failed page allocation."); 401*7bdf38e5Schristos } 402*7bdf38e5Schristos stats_expect(&psset, HUGEPAGE_PAGES); 403*7bdf38e5Schristos hpdata_t *ps; 404*7bdf38e5Schristos for (ssize_t i = HUGEPAGE_PAGES - 1; i >= 0; i--) { 405*7bdf38e5Schristos ps = test_psset_dalloc(&psset, &alloc[i]); 406*7bdf38e5Schristos expect_true((ps == NULL) == (i != 0), 407*7bdf38e5Schristos "test_psset_dalloc should only evict a slab on the last " 408*7bdf38e5Schristos "free"); 409*7bdf38e5Schristos stats_expect(&psset, i); 410*7bdf38e5Schristos } 411*7bdf38e5Schristos 412*7bdf38e5Schristos test_psset_alloc_new(&psset, &pageslab, &alloc[0], PAGE); 413*7bdf38e5Schristos stats_expect(&psset, 1); 414*7bdf38e5Schristos psset_update_begin(&psset, &pageslab); 415*7bdf38e5Schristos stats_expect(&psset, 0); 416*7bdf38e5Schristos psset_update_end(&psset, &pageslab); 417*7bdf38e5Schristos stats_expect(&psset, 1); 418*7bdf38e5Schristos } 419*7bdf38e5Schristos TEST_END 420*7bdf38e5Schristos 421*7bdf38e5Schristos /* 422*7bdf38e5Schristos * Fills in and inserts two pageslabs, with the first better than the second, 423*7bdf38e5Schristos * and each fully allocated (into the allocations in allocs and worse_allocs, 424*7bdf38e5Schristos * each of which should be HUGEPAGE_PAGES long), except for a single free page 425*7bdf38e5Schristos * at the end. 426*7bdf38e5Schristos * 427*7bdf38e5Schristos * (There's nothing magic about these numbers; it's just useful to share the 428*7bdf38e5Schristos * setup between the oldest fit and the insert/remove test). 429*7bdf38e5Schristos */ 430*7bdf38e5Schristos static void 431*7bdf38e5Schristos init_test_pageslabs(psset_t *psset, hpdata_t *pageslab, 432*7bdf38e5Schristos hpdata_t *worse_pageslab, edata_t *alloc, edata_t *worse_alloc) { 433*7bdf38e5Schristos bool err; 434*7bdf38e5Schristos 435*7bdf38e5Schristos hpdata_init(pageslab, (void *)(10 * HUGEPAGE), PAGESLAB_AGE); 436*7bdf38e5Schristos /* 437*7bdf38e5Schristos * This pageslab would be better from an address-first-fit POV, but 438*7bdf38e5Schristos * worse from an age POV. 439*7bdf38e5Schristos */ 440*7bdf38e5Schristos hpdata_init(worse_pageslab, (void *)(9 * HUGEPAGE), PAGESLAB_AGE + 1); 441*7bdf38e5Schristos 442*7bdf38e5Schristos psset_init(psset); 443*7bdf38e5Schristos 444*7bdf38e5Schristos edata_init_test(&alloc[0]); 445*7bdf38e5Schristos test_psset_alloc_new(psset, pageslab, &alloc[0], PAGE); 446*7bdf38e5Schristos for (size_t i = 1; i < HUGEPAGE_PAGES; i++) { 447*7bdf38e5Schristos edata_init_test(&alloc[i]); 448*7bdf38e5Schristos err = test_psset_alloc_reuse(psset, &alloc[i], PAGE); 449*7bdf38e5Schristos expect_false(err, "Nonempty psset failed page allocation."); 450*7bdf38e5Schristos expect_ptr_eq(pageslab, edata_ps_get(&alloc[i]), 451*7bdf38e5Schristos "Allocated from the wrong pageslab"); 452*7bdf38e5Schristos } 453*7bdf38e5Schristos 454*7bdf38e5Schristos edata_init_test(&worse_alloc[0]); 455*7bdf38e5Schristos test_psset_alloc_new(psset, worse_pageslab, &worse_alloc[0], PAGE); 456*7bdf38e5Schristos expect_ptr_eq(worse_pageslab, edata_ps_get(&worse_alloc[0]), 457*7bdf38e5Schristos "Allocated from the wrong pageslab"); 458*7bdf38e5Schristos /* 459*7bdf38e5Schristos * Make the two pssets otherwise indistinguishable; all full except for 460*7bdf38e5Schristos * a single page. 461*7bdf38e5Schristos */ 462*7bdf38e5Schristos for (size_t i = 1; i < HUGEPAGE_PAGES - 1; i++) { 463*7bdf38e5Schristos edata_init_test(&worse_alloc[i]); 464*7bdf38e5Schristos err = test_psset_alloc_reuse(psset, &alloc[i], PAGE); 465*7bdf38e5Schristos expect_false(err, "Nonempty psset failed page allocation."); 466*7bdf38e5Schristos expect_ptr_eq(worse_pageslab, edata_ps_get(&alloc[i]), 467*7bdf38e5Schristos "Allocated from the wrong pageslab"); 468*7bdf38e5Schristos } 469*7bdf38e5Schristos 470*7bdf38e5Schristos /* Deallocate the last page from the older pageslab. */ 471*7bdf38e5Schristos hpdata_t *evicted = test_psset_dalloc(psset, 472*7bdf38e5Schristos &alloc[HUGEPAGE_PAGES - 1]); 473*7bdf38e5Schristos expect_ptr_null(evicted, "Unexpected eviction"); 474*7bdf38e5Schristos } 475*7bdf38e5Schristos 476*7bdf38e5Schristos TEST_BEGIN(test_oldest_fit) { 477*7bdf38e5Schristos bool err; 478*7bdf38e5Schristos edata_t alloc[HUGEPAGE_PAGES]; 479*7bdf38e5Schristos edata_t worse_alloc[HUGEPAGE_PAGES]; 480*7bdf38e5Schristos 481*7bdf38e5Schristos hpdata_t pageslab; 482*7bdf38e5Schristos hpdata_t worse_pageslab; 483*7bdf38e5Schristos 484*7bdf38e5Schristos psset_t psset; 485*7bdf38e5Schristos 486*7bdf38e5Schristos init_test_pageslabs(&psset, &pageslab, &worse_pageslab, alloc, 487*7bdf38e5Schristos worse_alloc); 488*7bdf38e5Schristos 489*7bdf38e5Schristos /* The edata should come from the better pageslab. */ 490*7bdf38e5Schristos edata_t test_edata; 491*7bdf38e5Schristos edata_init_test(&test_edata); 492*7bdf38e5Schristos err = test_psset_alloc_reuse(&psset, &test_edata, PAGE); 493*7bdf38e5Schristos expect_false(err, "Nonempty psset failed page allocation"); 494*7bdf38e5Schristos expect_ptr_eq(&pageslab, edata_ps_get(&test_edata), 495*7bdf38e5Schristos "Allocated from the wrong pageslab"); 496*7bdf38e5Schristos } 497*7bdf38e5Schristos TEST_END 498*7bdf38e5Schristos 499*7bdf38e5Schristos TEST_BEGIN(test_insert_remove) { 500*7bdf38e5Schristos bool err; 501*7bdf38e5Schristos hpdata_t *ps; 502*7bdf38e5Schristos edata_t alloc[HUGEPAGE_PAGES]; 503*7bdf38e5Schristos edata_t worse_alloc[HUGEPAGE_PAGES]; 504*7bdf38e5Schristos 505*7bdf38e5Schristos hpdata_t pageslab; 506*7bdf38e5Schristos hpdata_t worse_pageslab; 507*7bdf38e5Schristos 508*7bdf38e5Schristos psset_t psset; 509*7bdf38e5Schristos 510*7bdf38e5Schristos init_test_pageslabs(&psset, &pageslab, &worse_pageslab, alloc, 511*7bdf38e5Schristos worse_alloc); 512*7bdf38e5Schristos 513*7bdf38e5Schristos /* Remove better; should still be able to alloc from worse. */ 514*7bdf38e5Schristos psset_update_begin(&psset, &pageslab); 515*7bdf38e5Schristos err = test_psset_alloc_reuse(&psset, &worse_alloc[HUGEPAGE_PAGES - 1], 516*7bdf38e5Schristos PAGE); 517*7bdf38e5Schristos expect_false(err, "Removal should still leave an empty page"); 518*7bdf38e5Schristos expect_ptr_eq(&worse_pageslab, 519*7bdf38e5Schristos edata_ps_get(&worse_alloc[HUGEPAGE_PAGES - 1]), 520*7bdf38e5Schristos "Allocated out of wrong ps"); 521*7bdf38e5Schristos 522*7bdf38e5Schristos /* 523*7bdf38e5Schristos * After deallocating the previous alloc and reinserting better, it 524*7bdf38e5Schristos * should be preferred for future allocations. 525*7bdf38e5Schristos */ 526*7bdf38e5Schristos ps = test_psset_dalloc(&psset, &worse_alloc[HUGEPAGE_PAGES - 1]); 527*7bdf38e5Schristos expect_ptr_null(ps, "Incorrect eviction of nonempty pageslab"); 528*7bdf38e5Schristos psset_update_end(&psset, &pageslab); 529*7bdf38e5Schristos err = test_psset_alloc_reuse(&psset, &alloc[HUGEPAGE_PAGES - 1], PAGE); 530*7bdf38e5Schristos expect_false(err, "psset should be nonempty"); 531*7bdf38e5Schristos expect_ptr_eq(&pageslab, edata_ps_get(&alloc[HUGEPAGE_PAGES - 1]), 532*7bdf38e5Schristos "Removal/reinsertion shouldn't change ordering"); 533*7bdf38e5Schristos /* 534*7bdf38e5Schristos * After deallocating and removing both, allocations should fail. 535*7bdf38e5Schristos */ 536*7bdf38e5Schristos ps = test_psset_dalloc(&psset, &alloc[HUGEPAGE_PAGES - 1]); 537*7bdf38e5Schristos expect_ptr_null(ps, "Incorrect eviction"); 538*7bdf38e5Schristos psset_update_begin(&psset, &pageslab); 539*7bdf38e5Schristos psset_update_begin(&psset, &worse_pageslab); 540*7bdf38e5Schristos err = test_psset_alloc_reuse(&psset, &alloc[HUGEPAGE_PAGES - 1], PAGE); 541*7bdf38e5Schristos expect_true(err, "psset should be empty, but an alloc succeeded"); 542*7bdf38e5Schristos } 543*7bdf38e5Schristos TEST_END 544*7bdf38e5Schristos 545*7bdf38e5Schristos TEST_BEGIN(test_purge_prefers_nonhuge) { 546*7bdf38e5Schristos /* 547*7bdf38e5Schristos * All else being equal, we should prefer purging non-huge pages over 548*7bdf38e5Schristos * huge ones for non-empty extents. 549*7bdf38e5Schristos */ 550*7bdf38e5Schristos 551*7bdf38e5Schristos /* Nothing magic about this constant. */ 552*7bdf38e5Schristos enum { 553*7bdf38e5Schristos NHP = 23, 554*7bdf38e5Schristos }; 555*7bdf38e5Schristos hpdata_t *hpdata; 556*7bdf38e5Schristos 557*7bdf38e5Schristos psset_t psset; 558*7bdf38e5Schristos psset_init(&psset); 559*7bdf38e5Schristos 560*7bdf38e5Schristos hpdata_t hpdata_huge[NHP]; 561*7bdf38e5Schristos uintptr_t huge_begin = (uintptr_t)&hpdata_huge[0]; 562*7bdf38e5Schristos uintptr_t huge_end = (uintptr_t)&hpdata_huge[NHP]; 563*7bdf38e5Schristos hpdata_t hpdata_nonhuge[NHP]; 564*7bdf38e5Schristos uintptr_t nonhuge_begin = (uintptr_t)&hpdata_nonhuge[0]; 565*7bdf38e5Schristos uintptr_t nonhuge_end = (uintptr_t)&hpdata_nonhuge[NHP]; 566*7bdf38e5Schristos 567*7bdf38e5Schristos for (size_t i = 0; i < NHP; i++) { 568*7bdf38e5Schristos hpdata_init(&hpdata_huge[i], (void *)((10 + i) * HUGEPAGE), 569*7bdf38e5Schristos 123 + i); 570*7bdf38e5Schristos psset_insert(&psset, &hpdata_huge[i]); 571*7bdf38e5Schristos 572*7bdf38e5Schristos hpdata_init(&hpdata_nonhuge[i], 573*7bdf38e5Schristos (void *)((10 + NHP + i) * HUGEPAGE), 574*7bdf38e5Schristos 456 + i); 575*7bdf38e5Schristos psset_insert(&psset, &hpdata_nonhuge[i]); 576*7bdf38e5Schristos 577*7bdf38e5Schristos } 578*7bdf38e5Schristos for (int i = 0; i < 2 * NHP; i++) { 579*7bdf38e5Schristos hpdata = psset_pick_alloc(&psset, HUGEPAGE * 3 / 4); 580*7bdf38e5Schristos psset_update_begin(&psset, hpdata); 581*7bdf38e5Schristos void *ptr; 582*7bdf38e5Schristos ptr = hpdata_reserve_alloc(hpdata, HUGEPAGE * 3 / 4); 583*7bdf38e5Schristos /* Ignore the first alloc, which will stick around. */ 584*7bdf38e5Schristos (void)ptr; 585*7bdf38e5Schristos /* 586*7bdf38e5Schristos * The second alloc is to dirty the pages; free it immediately 587*7bdf38e5Schristos * after allocating. 588*7bdf38e5Schristos */ 589*7bdf38e5Schristos ptr = hpdata_reserve_alloc(hpdata, HUGEPAGE / 4); 590*7bdf38e5Schristos hpdata_unreserve(hpdata, ptr, HUGEPAGE / 4); 591*7bdf38e5Schristos 592*7bdf38e5Schristos if (huge_begin <= (uintptr_t)hpdata 593*7bdf38e5Schristos && (uintptr_t)hpdata < huge_end) { 594*7bdf38e5Schristos hpdata_hugify(hpdata); 595*7bdf38e5Schristos } 596*7bdf38e5Schristos 597*7bdf38e5Schristos hpdata_purge_allowed_set(hpdata, true); 598*7bdf38e5Schristos psset_update_end(&psset, hpdata); 599*7bdf38e5Schristos } 600*7bdf38e5Schristos 601*7bdf38e5Schristos /* 602*7bdf38e5Schristos * We've got a bunch of 1/8th dirty hpdatas. It should give us all the 603*7bdf38e5Schristos * non-huge ones to purge, then all the huge ones, then refuse to purge 604*7bdf38e5Schristos * further. 605*7bdf38e5Schristos */ 606*7bdf38e5Schristos for (int i = 0; i < NHP; i++) { 607*7bdf38e5Schristos hpdata = psset_pick_purge(&psset); 608*7bdf38e5Schristos assert_true(nonhuge_begin <= (uintptr_t)hpdata 609*7bdf38e5Schristos && (uintptr_t)hpdata < nonhuge_end, ""); 610*7bdf38e5Schristos psset_update_begin(&psset, hpdata); 611*7bdf38e5Schristos test_psset_fake_purge(hpdata); 612*7bdf38e5Schristos hpdata_purge_allowed_set(hpdata, false); 613*7bdf38e5Schristos psset_update_end(&psset, hpdata); 614*7bdf38e5Schristos } 615*7bdf38e5Schristos for (int i = 0; i < NHP; i++) { 616*7bdf38e5Schristos hpdata = psset_pick_purge(&psset); 617*7bdf38e5Schristos expect_true(huge_begin <= (uintptr_t)hpdata 618*7bdf38e5Schristos && (uintptr_t)hpdata < huge_end, ""); 619*7bdf38e5Schristos psset_update_begin(&psset, hpdata); 620*7bdf38e5Schristos hpdata_dehugify(hpdata); 621*7bdf38e5Schristos test_psset_fake_purge(hpdata); 622*7bdf38e5Schristos hpdata_purge_allowed_set(hpdata, false); 623*7bdf38e5Schristos psset_update_end(&psset, hpdata); 624*7bdf38e5Schristos } 625*7bdf38e5Schristos } 626*7bdf38e5Schristos TEST_END 627*7bdf38e5Schristos 628*7bdf38e5Schristos TEST_BEGIN(test_purge_prefers_empty) { 629*7bdf38e5Schristos void *ptr; 630*7bdf38e5Schristos 631*7bdf38e5Schristos psset_t psset; 632*7bdf38e5Schristos psset_init(&psset); 633*7bdf38e5Schristos 634*7bdf38e5Schristos hpdata_t hpdata_empty; 635*7bdf38e5Schristos hpdata_t hpdata_nonempty; 636*7bdf38e5Schristos hpdata_init(&hpdata_empty, (void *)(10 * HUGEPAGE), 123); 637*7bdf38e5Schristos psset_insert(&psset, &hpdata_empty); 638*7bdf38e5Schristos hpdata_init(&hpdata_nonempty, (void *)(11 * HUGEPAGE), 456); 639*7bdf38e5Schristos psset_insert(&psset, &hpdata_nonempty); 640*7bdf38e5Schristos 641*7bdf38e5Schristos psset_update_begin(&psset, &hpdata_empty); 642*7bdf38e5Schristos ptr = hpdata_reserve_alloc(&hpdata_empty, PAGE); 643*7bdf38e5Schristos expect_ptr_eq(hpdata_addr_get(&hpdata_empty), ptr, ""); 644*7bdf38e5Schristos hpdata_unreserve(&hpdata_empty, ptr, PAGE); 645*7bdf38e5Schristos hpdata_purge_allowed_set(&hpdata_empty, true); 646*7bdf38e5Schristos psset_update_end(&psset, &hpdata_empty); 647*7bdf38e5Schristos 648*7bdf38e5Schristos psset_update_begin(&psset, &hpdata_nonempty); 649*7bdf38e5Schristos ptr = hpdata_reserve_alloc(&hpdata_nonempty, 10 * PAGE); 650*7bdf38e5Schristos expect_ptr_eq(hpdata_addr_get(&hpdata_nonempty), ptr, ""); 651*7bdf38e5Schristos hpdata_unreserve(&hpdata_nonempty, ptr, 9 * PAGE); 652*7bdf38e5Schristos hpdata_purge_allowed_set(&hpdata_nonempty, true); 653*7bdf38e5Schristos psset_update_end(&psset, &hpdata_nonempty); 654*7bdf38e5Schristos 655*7bdf38e5Schristos /* 656*7bdf38e5Schristos * The nonempty slab has 9 dirty pages, while the empty one has only 1. 657*7bdf38e5Schristos * We should still pick the empty one for purging. 658*7bdf38e5Schristos */ 659*7bdf38e5Schristos hpdata_t *to_purge = psset_pick_purge(&psset); 660*7bdf38e5Schristos expect_ptr_eq(&hpdata_empty, to_purge, ""); 661*7bdf38e5Schristos } 662*7bdf38e5Schristos TEST_END 663*7bdf38e5Schristos 664*7bdf38e5Schristos TEST_BEGIN(test_purge_prefers_empty_huge) { 665*7bdf38e5Schristos void *ptr; 666*7bdf38e5Schristos 667*7bdf38e5Schristos psset_t psset; 668*7bdf38e5Schristos psset_init(&psset); 669*7bdf38e5Schristos 670*7bdf38e5Schristos enum {NHP = 10 }; 671*7bdf38e5Schristos 672*7bdf38e5Schristos hpdata_t hpdata_huge[NHP]; 673*7bdf38e5Schristos hpdata_t hpdata_nonhuge[NHP]; 674*7bdf38e5Schristos 675*7bdf38e5Schristos uintptr_t cur_addr = 100 * HUGEPAGE; 676*7bdf38e5Schristos uint64_t cur_age = 123; 677*7bdf38e5Schristos for (int i = 0; i < NHP; i++) { 678*7bdf38e5Schristos hpdata_init(&hpdata_huge[i], (void *)cur_addr, cur_age); 679*7bdf38e5Schristos cur_addr += HUGEPAGE; 680*7bdf38e5Schristos cur_age++; 681*7bdf38e5Schristos psset_insert(&psset, &hpdata_huge[i]); 682*7bdf38e5Schristos 683*7bdf38e5Schristos hpdata_init(&hpdata_nonhuge[i], (void *)cur_addr, cur_age); 684*7bdf38e5Schristos cur_addr += HUGEPAGE; 685*7bdf38e5Schristos cur_age++; 686*7bdf38e5Schristos psset_insert(&psset, &hpdata_nonhuge[i]); 687*7bdf38e5Schristos 688*7bdf38e5Schristos /* 689*7bdf38e5Schristos * Make the hpdata_huge[i] fully dirty, empty, purgable, and 690*7bdf38e5Schristos * huge. 691*7bdf38e5Schristos */ 692*7bdf38e5Schristos psset_update_begin(&psset, &hpdata_huge[i]); 693*7bdf38e5Schristos ptr = hpdata_reserve_alloc(&hpdata_huge[i], HUGEPAGE); 694*7bdf38e5Schristos expect_ptr_eq(hpdata_addr_get(&hpdata_huge[i]), ptr, ""); 695*7bdf38e5Schristos hpdata_hugify(&hpdata_huge[i]); 696*7bdf38e5Schristos hpdata_unreserve(&hpdata_huge[i], ptr, HUGEPAGE); 697*7bdf38e5Schristos hpdata_purge_allowed_set(&hpdata_huge[i], true); 698*7bdf38e5Schristos psset_update_end(&psset, &hpdata_huge[i]); 699*7bdf38e5Schristos 700*7bdf38e5Schristos /* 701*7bdf38e5Schristos * Make hpdata_nonhuge[i] fully dirty, empty, purgable, and 702*7bdf38e5Schristos * non-huge. 703*7bdf38e5Schristos */ 704*7bdf38e5Schristos psset_update_begin(&psset, &hpdata_nonhuge[i]); 705*7bdf38e5Schristos ptr = hpdata_reserve_alloc(&hpdata_nonhuge[i], HUGEPAGE); 706*7bdf38e5Schristos expect_ptr_eq(hpdata_addr_get(&hpdata_nonhuge[i]), ptr, ""); 707*7bdf38e5Schristos hpdata_unreserve(&hpdata_nonhuge[i], ptr, HUGEPAGE); 708*7bdf38e5Schristos hpdata_purge_allowed_set(&hpdata_nonhuge[i], true); 709*7bdf38e5Schristos psset_update_end(&psset, &hpdata_nonhuge[i]); 710*7bdf38e5Schristos } 711*7bdf38e5Schristos 712*7bdf38e5Schristos /* 713*7bdf38e5Schristos * We have a bunch of empty slabs, half huge, half nonhuge, inserted in 714*7bdf38e5Schristos * alternating order. We should pop all the huge ones before popping 715*7bdf38e5Schristos * any of the non-huge ones for purging. 716*7bdf38e5Schristos */ 717*7bdf38e5Schristos for (int i = 0; i < NHP; i++) { 718*7bdf38e5Schristos hpdata_t *to_purge = psset_pick_purge(&psset); 719*7bdf38e5Schristos expect_ptr_eq(&hpdata_huge[i], to_purge, ""); 720*7bdf38e5Schristos psset_update_begin(&psset, to_purge); 721*7bdf38e5Schristos hpdata_purge_allowed_set(to_purge, false); 722*7bdf38e5Schristos psset_update_end(&psset, to_purge); 723*7bdf38e5Schristos } 724*7bdf38e5Schristos for (int i = 0; i < NHP; i++) { 725*7bdf38e5Schristos hpdata_t *to_purge = psset_pick_purge(&psset); 726*7bdf38e5Schristos expect_ptr_eq(&hpdata_nonhuge[i], to_purge, ""); 727*7bdf38e5Schristos psset_update_begin(&psset, to_purge); 728*7bdf38e5Schristos hpdata_purge_allowed_set(to_purge, false); 729*7bdf38e5Schristos psset_update_end(&psset, to_purge); 730*7bdf38e5Schristos } 731*7bdf38e5Schristos } 732*7bdf38e5Schristos TEST_END 733*7bdf38e5Schristos 734*7bdf38e5Schristos int 735*7bdf38e5Schristos main(void) { 736*7bdf38e5Schristos return test_no_reentrancy( 737*7bdf38e5Schristos test_empty, 738*7bdf38e5Schristos test_fill, 739*7bdf38e5Schristos test_reuse, 740*7bdf38e5Schristos test_evict, 741*7bdf38e5Schristos test_multi_pageslab, 742*7bdf38e5Schristos test_stats, 743*7bdf38e5Schristos test_oldest_fit, 744*7bdf38e5Schristos test_insert_remove, 745*7bdf38e5Schristos test_purge_prefers_nonhuge, 746*7bdf38e5Schristos test_purge_prefers_empty, 747*7bdf38e5Schristos test_purge_prefers_empty_huge); 748*7bdf38e5Schristos } 749