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