Improve memory utilization tests
Added tests for large size classes and expanded the tests to cover wider range of allocation sizes.
This commit is contained in:
parent
2d6d099fed
commit
4c63b0e76a
@ -3143,15 +3143,15 @@ label_return:
|
|||||||
* (f) total number of regions in the bin the extent belongs to.
|
* (f) total number of regions in the bin the extent belongs to.
|
||||||
*
|
*
|
||||||
* Note that "(e)" and "(f)" are only available when stats are enabled;
|
* Note that "(e)" and "(f)" are only available when stats are enabled;
|
||||||
* otherwise both are set zero.
|
* otherwise their values are undefined.
|
||||||
*
|
*
|
||||||
* This API is mainly intended for small class allocations, where extents are
|
* This API is mainly intended for small class allocations, where extents are
|
||||||
* used as slab.
|
* used as slab.
|
||||||
*
|
*
|
||||||
* In case of large class allocations, "(a)" will be NULL, and "(e)" and "(f)"
|
* In case of large class allocations, "(a)" will be NULL, and "(e)" and "(f)"
|
||||||
* will be zero. The other three fields will be properly set though the values
|
* will be zero (if stats are enabled; otherwise undefined). The other three
|
||||||
* are trivial: "(b)" will be 0, "(c)" will be 1, and "(d)" will be the usable
|
* fields will be properly set though the values are trivial: "(b)" will be 0,
|
||||||
* size.
|
* "(c)" will be 1, and "(d)" will be the usable size.
|
||||||
*
|
*
|
||||||
* The input pointer and size are respectively passed in by newp and newlen,
|
* The input pointer and size are respectively passed in by newp and newlen,
|
||||||
* and the output fields and size are respectively oldp and *oldlenp.
|
* and the output fields and size are respectively oldp and *oldlenp.
|
||||||
|
@ -25,18 +25,30 @@
|
|||||||
|
|
||||||
#define TEST_UTIL_BATCH_VALID TEST_UTIL_VALID("batch_query")
|
#define TEST_UTIL_BATCH_VALID TEST_UTIL_VALID("batch_query")
|
||||||
|
|
||||||
TEST_BEGIN(test_query) {
|
#define TEST_MAX_SIZE (1 << 20)
|
||||||
void *p = mallocx(1, 0);
|
|
||||||
void **in = &p;
|
|
||||||
size_t in_sz = sizeof(const void *);
|
|
||||||
size_t out_sz = sizeof(void *) + sizeof(size_t) * 5;
|
|
||||||
void *out = mallocx(out_sz, 0);
|
|
||||||
void *out_ref = mallocx(out_sz, 0);
|
|
||||||
size_t out_sz_ref = out_sz;
|
|
||||||
|
|
||||||
assert_ptr_not_null(p, "test pointer allocation failed");
|
TEST_BEGIN(test_query) {
|
||||||
assert_ptr_not_null(out, "test output allocation failed");
|
size_t sz;
|
||||||
assert_ptr_not_null(out_ref, "test reference output allocation failed");
|
/*
|
||||||
|
* Select some sizes that can span both small and large sizes, and are
|
||||||
|
* numerically unrelated to any size boundaries.
|
||||||
|
*/
|
||||||
|
for (sz = 7; sz <= TEST_MAX_SIZE && sz <= SC_LARGE_MAXCLASS;
|
||||||
|
sz += (sz <= SC_SMALL_MAXCLASS ? 1009 : 99989)) {
|
||||||
|
void *p = mallocx(sz, 0);
|
||||||
|
void **in = &p;
|
||||||
|
size_t in_sz = sizeof(const void *);
|
||||||
|
size_t out_sz = sizeof(void *) + sizeof(size_t) * 5;
|
||||||
|
void *out = mallocx(out_sz, 0);
|
||||||
|
void *out_ref = mallocx(out_sz, 0);
|
||||||
|
size_t out_sz_ref = out_sz;
|
||||||
|
|
||||||
|
assert_ptr_not_null(p,
|
||||||
|
"test pointer allocation failed");
|
||||||
|
assert_ptr_not_null(out,
|
||||||
|
"test output allocation failed");
|
||||||
|
assert_ptr_not_null(out_ref,
|
||||||
|
"test reference output allocation failed");
|
||||||
|
|
||||||
#define SLABCUR_READ(out) (*(void **)out)
|
#define SLABCUR_READ(out) (*(void **)out)
|
||||||
#define COUNTS(out) ((size_t *)((void **)out + 1))
|
#define COUNTS(out) ((size_t *)((void **)out + 1))
|
||||||
@ -46,55 +58,91 @@ TEST_BEGIN(test_query) {
|
|||||||
#define BIN_NFREE_READ(out) COUNTS(out)[3]
|
#define BIN_NFREE_READ(out) COUNTS(out)[3]
|
||||||
#define BIN_NREGS_READ(out) COUNTS(out)[4]
|
#define BIN_NREGS_READ(out) COUNTS(out)[4]
|
||||||
|
|
||||||
SLABCUR_READ(out) = NULL;
|
SLABCUR_READ(out) = NULL;
|
||||||
NFREE_READ(out) = NREGS_READ(out) = SIZE_READ(out) = -1;
|
NFREE_READ(out) = NREGS_READ(out) = SIZE_READ(out) = -1;
|
||||||
BIN_NFREE_READ(out) = BIN_NREGS_READ(out) = -1;
|
BIN_NFREE_READ(out) = BIN_NREGS_READ(out) = -1;
|
||||||
memcpy(out_ref, out, out_sz);
|
memcpy(out_ref, out, out_sz);
|
||||||
|
|
||||||
/* Test invalid argument(s) errors */
|
/* Test invalid argument(s) errors */
|
||||||
TEST_UTIL_QUERY_EINVAL(NULL, &out_sz, in, in_sz, "old is NULL");
|
TEST_UTIL_QUERY_EINVAL(NULL, &out_sz, in, in_sz,
|
||||||
TEST_UTIL_QUERY_EINVAL(out, NULL, in, in_sz, "oldlenp is NULL");
|
"old is NULL");
|
||||||
TEST_UTIL_QUERY_EINVAL(out, &out_sz, NULL, in_sz, "newp is NULL");
|
TEST_UTIL_QUERY_EINVAL(out, NULL, in, in_sz,
|
||||||
TEST_UTIL_QUERY_EINVAL(out, &out_sz, in, 0, "newlen is zero");
|
"oldlenp is NULL");
|
||||||
in_sz -= 1;
|
TEST_UTIL_QUERY_EINVAL(out, &out_sz, NULL, in_sz,
|
||||||
TEST_UTIL_QUERY_EINVAL(out, &out_sz, in, in_sz, "invalid newlen");
|
"newp is NULL");
|
||||||
in_sz += 1;
|
TEST_UTIL_QUERY_EINVAL(out, &out_sz, in, 0,
|
||||||
out_sz_ref = out_sz -= 2 * sizeof(size_t);
|
"newlen is zero");
|
||||||
TEST_UTIL_QUERY_EINVAL(out, &out_sz, in, in_sz, "invalid *oldlenp");
|
in_sz -= 1;
|
||||||
out_sz_ref = out_sz += 2 * sizeof(size_t);
|
TEST_UTIL_QUERY_EINVAL(out, &out_sz, in, in_sz,
|
||||||
|
"invalid newlen");
|
||||||
|
in_sz += 1;
|
||||||
|
out_sz_ref = out_sz -= 2 * sizeof(size_t);
|
||||||
|
TEST_UTIL_QUERY_EINVAL(out, &out_sz, in, in_sz,
|
||||||
|
"invalid *oldlenp");
|
||||||
|
out_sz_ref = out_sz += 2 * sizeof(size_t);
|
||||||
|
|
||||||
/* Examine output for valid call */
|
/* Examine output for valid call */
|
||||||
TEST_UTIL_VALID("query");
|
TEST_UTIL_VALID("query");
|
||||||
assert_zu_le(NFREE_READ(out), NREGS_READ(out),
|
assert_zu_le(sz, SIZE_READ(out),
|
||||||
"Extent free count exceeded region count");
|
"Extent size should be at least allocation size");
|
||||||
assert_zu_le(NREGS_READ(out), SIZE_READ(out),
|
assert_zu_eq(SIZE_READ(out) & (PAGE - 1), 0,
|
||||||
"Extent region count exceeded size");
|
"Extent size should be a multiple of page size");
|
||||||
assert_zu_ne(NREGS_READ(out), 0,
|
if (sz <= SC_SMALL_MAXCLASS) {
|
||||||
"Extent region count must be positive");
|
assert_zu_le(NFREE_READ(out), NREGS_READ(out),
|
||||||
assert_zu_ne(SIZE_READ(out), 0, "Extent size must be positive");
|
"Extent free count exceeded region count");
|
||||||
if (config_stats) {
|
assert_zu_le(NREGS_READ(out), SIZE_READ(out),
|
||||||
assert_zu_le(BIN_NFREE_READ(out), BIN_NREGS_READ(out),
|
"Extent region count exceeded size");
|
||||||
"Bin free count exceeded region count");
|
assert_zu_ne(NREGS_READ(out), 0,
|
||||||
assert_zu_ne(BIN_NREGS_READ(out), 0,
|
"Extent region count must be positive");
|
||||||
"Bin region count must be positive");
|
assert_ptr_not_null(SLABCUR_READ(out),
|
||||||
assert_zu_le(NFREE_READ(out), BIN_NFREE_READ(out),
|
"Current slab is null");
|
||||||
"Extent free count exceeded bin free count");
|
assert_true(NFREE_READ(out) == 0
|
||||||
assert_zu_le(NREGS_READ(out), BIN_NREGS_READ(out),
|
|| SLABCUR_READ(out) <= p,
|
||||||
"Extent region count exceeded bin region count");
|
"Allocation should follow first fit principle");
|
||||||
assert_zu_eq(BIN_NREGS_READ(out) % NREGS_READ(out), 0,
|
if (config_stats) {
|
||||||
"Bin region count isn't a multiple of extent region count");
|
assert_zu_le(BIN_NFREE_READ(out),
|
||||||
assert_zu_le(NREGS_READ(out) - NFREE_READ(out),
|
BIN_NREGS_READ(out),
|
||||||
BIN_NREGS_READ(out) - BIN_NFREE_READ(out),
|
"Bin free count exceeded region count");
|
||||||
"Extent utilized count exceeded bin utilized count");
|
assert_zu_ne(BIN_NREGS_READ(out), 0,
|
||||||
} else {
|
"Bin region count must be positive");
|
||||||
assert_zu_eq(BIN_NFREE_READ(out), 0,
|
assert_zu_le(NFREE_READ(out),
|
||||||
"Bin free count should be zero when stats are disabled");
|
BIN_NFREE_READ(out),
|
||||||
assert_zu_eq(BIN_NREGS_READ(out), 0,
|
"Extent free count exceeded bin free count");
|
||||||
"Bin region count should be zero when stats are disabled");
|
assert_zu_le(NREGS_READ(out),
|
||||||
}
|
BIN_NREGS_READ(out),
|
||||||
assert_ptr_not_null(SLABCUR_READ(out), "Current slab is null");
|
"Extent region count exceeded "
|
||||||
assert_true(NFREE_READ(out) == 0 || SLABCUR_READ(out) <= p,
|
"bin region count");
|
||||||
"Allocation should follow first fit principle");
|
assert_zu_eq(BIN_NREGS_READ(out)
|
||||||
|
% NREGS_READ(out), 0,
|
||||||
|
"Bin region count isn't a multiple of "
|
||||||
|
"extent region count");
|
||||||
|
assert_zu_le(
|
||||||
|
BIN_NFREE_READ(out) - NFREE_READ(out),
|
||||||
|
BIN_NREGS_READ(out) - NREGS_READ(out),
|
||||||
|
"Free count in other extents in the bin "
|
||||||
|
"exceeded region count in other extents "
|
||||||
|
"in the bin");
|
||||||
|
assert_zu_le(NREGS_READ(out) - NFREE_READ(out),
|
||||||
|
BIN_NREGS_READ(out) - BIN_NFREE_READ(out),
|
||||||
|
"Extent utilized count exceeded "
|
||||||
|
"bin utilized count");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert_zu_eq(NFREE_READ(out), 0,
|
||||||
|
"Extent free count should be zero");
|
||||||
|
assert_zu_eq(NREGS_READ(out), 1,
|
||||||
|
"Extent region count should be one");
|
||||||
|
assert_ptr_null(SLABCUR_READ(out),
|
||||||
|
"Current slab must be null for large size classes");
|
||||||
|
if (config_stats) {
|
||||||
|
assert_zu_eq(BIN_NFREE_READ(out), 0,
|
||||||
|
"Bin free count must be zero for "
|
||||||
|
"large sizes");
|
||||||
|
assert_zu_eq(BIN_NREGS_READ(out), 0,
|
||||||
|
"Bin region count must be zero for "
|
||||||
|
"large sizes");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#undef BIN_NREGS_READ
|
#undef BIN_NREGS_READ
|
||||||
#undef BIN_NFREE_READ
|
#undef BIN_NFREE_READ
|
||||||
@ -104,42 +152,54 @@ TEST_BEGIN(test_query) {
|
|||||||
#undef COUNTS
|
#undef COUNTS
|
||||||
#undef SLABCUR_READ
|
#undef SLABCUR_READ
|
||||||
|
|
||||||
free(out_ref);
|
free(out_ref);
|
||||||
free(out);
|
free(out);
|
||||||
free(p);
|
free(p);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
TEST_END
|
TEST_END
|
||||||
|
|
||||||
TEST_BEGIN(test_batch) {
|
TEST_BEGIN(test_batch) {
|
||||||
void *p = mallocx(1, 0);
|
size_t sz;
|
||||||
void *q = mallocx(1, 0);
|
/*
|
||||||
void *in[] = {p, q};
|
* Select some sizes that can span both small and large sizes, and are
|
||||||
size_t in_sz = sizeof(const void *) * 2;
|
* numerically unrelated to any size boundaries.
|
||||||
size_t out[] = {-1, -1, -1, -1, -1, -1};
|
*/
|
||||||
size_t out_sz = sizeof(size_t) * 6;
|
for (sz = 17; sz <= TEST_MAX_SIZE && sz <= SC_LARGE_MAXCLASS;
|
||||||
size_t out_ref[] = {-1, -1, -1, -1, -1, -1};
|
sz += (sz <= SC_SMALL_MAXCLASS ? 1019 : 99991)) {
|
||||||
size_t out_sz_ref = out_sz;
|
void *p = mallocx(sz, 0);
|
||||||
|
void *q = mallocx(sz, 0);
|
||||||
|
void *in[] = {p, q};
|
||||||
|
size_t in_sz = sizeof(const void *) * 2;
|
||||||
|
size_t out[] = {-1, -1, -1, -1, -1, -1};
|
||||||
|
size_t out_sz = sizeof(size_t) * 6;
|
||||||
|
size_t out_ref[] = {-1, -1, -1, -1, -1, -1};
|
||||||
|
size_t out_sz_ref = out_sz;
|
||||||
|
|
||||||
assert_ptr_not_null(p, "test pointer allocation failed");
|
assert_ptr_not_null(p, "test pointer allocation failed");
|
||||||
assert_ptr_not_null(q, "test pointer allocation failed");
|
assert_ptr_not_null(q, "test pointer allocation failed");
|
||||||
|
|
||||||
/* Test invalid argument(s) errors */
|
/* Test invalid argument(s) errors */
|
||||||
TEST_UTIL_BATCH_EINVAL(NULL, &out_sz, in, in_sz, "old is NULL");
|
TEST_UTIL_BATCH_EINVAL(NULL, &out_sz, in, in_sz,
|
||||||
TEST_UTIL_BATCH_EINVAL(out, NULL, in, in_sz, "oldlenp is NULL");
|
"old is NULL");
|
||||||
TEST_UTIL_BATCH_EINVAL(out, &out_sz, NULL, in_sz, "newp is NULL");
|
TEST_UTIL_BATCH_EINVAL(out, NULL, in, in_sz,
|
||||||
TEST_UTIL_BATCH_EINVAL(out, &out_sz, in, 0, "newlen is zero");
|
"oldlenp is NULL");
|
||||||
in_sz -= 1;
|
TEST_UTIL_BATCH_EINVAL(out, &out_sz, NULL, in_sz,
|
||||||
TEST_UTIL_BATCH_EINVAL(out, &out_sz, in, in_sz,
|
"newp is NULL");
|
||||||
"newlen is not an exact multiple");
|
TEST_UTIL_BATCH_EINVAL(out, &out_sz, in, 0,
|
||||||
in_sz += 1;
|
"newlen is zero");
|
||||||
out_sz_ref = out_sz -= 2 * sizeof(size_t);
|
in_sz -= 1;
|
||||||
TEST_UTIL_BATCH_EINVAL(out, &out_sz, in, in_sz,
|
TEST_UTIL_BATCH_EINVAL(out, &out_sz, in, in_sz,
|
||||||
"*oldlenp is not an exact multiple");
|
"newlen is not an exact multiple");
|
||||||
out_sz_ref = out_sz += 2 * sizeof(size_t);
|
in_sz += 1;
|
||||||
in_sz -= sizeof(const void *);
|
out_sz_ref = out_sz -= 2 * sizeof(size_t);
|
||||||
TEST_UTIL_BATCH_EINVAL(out, &out_sz, in, in_sz,
|
TEST_UTIL_BATCH_EINVAL(out, &out_sz, in, in_sz,
|
||||||
"*oldlenp and newlen do not match");
|
"*oldlenp is not an exact multiple");
|
||||||
in_sz += sizeof(const void *);
|
out_sz_ref = out_sz += 2 * sizeof(size_t);
|
||||||
|
in_sz -= sizeof(const void *);
|
||||||
|
TEST_UTIL_BATCH_EINVAL(out, &out_sz, in, in_sz,
|
||||||
|
"*oldlenp and newlen do not match");
|
||||||
|
in_sz += sizeof(const void *);
|
||||||
|
|
||||||
/* Examine output for valid calls */
|
/* Examine output for valid calls */
|
||||||
#define TEST_EQUAL_REF(i, message) \
|
#define TEST_EQUAL_REF(i, message) \
|
||||||
@ -149,29 +209,45 @@ TEST_BEGIN(test_batch) {
|
|||||||
#define NREGS_READ(out, i) out[(i) * 3 + 1]
|
#define NREGS_READ(out, i) out[(i) * 3 + 1]
|
||||||
#define SIZE_READ(out, i) out[(i) * 3 + 2]
|
#define SIZE_READ(out, i) out[(i) * 3 + 2]
|
||||||
|
|
||||||
out_sz_ref = out_sz /= 2;
|
out_sz_ref = out_sz /= 2;
|
||||||
in_sz /= 2;
|
in_sz /= 2;
|
||||||
TEST_UTIL_BATCH_VALID;
|
TEST_UTIL_BATCH_VALID;
|
||||||
assert_zu_le(NFREE_READ(out, 0), NREGS_READ(out, 0),
|
assert_zu_le(sz, SIZE_READ(out, 0),
|
||||||
"Extent free count exceeded region count");
|
"Extent size should be at least allocation size");
|
||||||
assert_zu_le(NREGS_READ(out, 0), SIZE_READ(out, 0),
|
assert_zu_eq(SIZE_READ(out, 0) & (PAGE - 1), 0,
|
||||||
"Extent region count exceeded size");
|
"Extent size should be a multiple of page size");
|
||||||
assert_zu_ne(NREGS_READ(out, 0), 0,
|
if (sz <= SC_SMALL_MAXCLASS) {
|
||||||
"Extent region count must be positive");
|
assert_zu_le(NFREE_READ(out, 0), NREGS_READ(out, 0),
|
||||||
assert_zu_ne(SIZE_READ(out, 0), 0, "Extent size must be positive");
|
"Extent free count exceeded region count");
|
||||||
TEST_EQUAL_REF(1, "Should not overwrite content beyond what's needed");
|
assert_zu_le(NREGS_READ(out, 0), SIZE_READ(out, 0),
|
||||||
in_sz *= 2;
|
"Extent region count exceeded size");
|
||||||
out_sz_ref = out_sz *= 2;
|
assert_zu_ne(NREGS_READ(out, 0), 0,
|
||||||
|
"Extent region count must be positive");
|
||||||
|
} else {
|
||||||
|
assert_zu_eq(NFREE_READ(out, 0), 0,
|
||||||
|
"Extent free count should be zero");
|
||||||
|
assert_zu_eq(NREGS_READ(out, 0), 1,
|
||||||
|
"Extent region count should be one");
|
||||||
|
}
|
||||||
|
TEST_EQUAL_REF(1,
|
||||||
|
"Should not overwrite content beyond what's needed");
|
||||||
|
in_sz *= 2;
|
||||||
|
out_sz_ref = out_sz *= 2;
|
||||||
|
|
||||||
memcpy(out_ref, out, 3 * sizeof(size_t));
|
memcpy(out_ref, out, 3 * sizeof(size_t));
|
||||||
TEST_UTIL_BATCH_VALID;
|
TEST_UTIL_BATCH_VALID;
|
||||||
TEST_EQUAL_REF(0, "Statistics should be stable across calls");
|
TEST_EQUAL_REF(0, "Statistics should be stable across calls");
|
||||||
assert_zu_le(NFREE_READ(out, 1), NREGS_READ(out, 1),
|
if (sz <= SC_SMALL_MAXCLASS) {
|
||||||
"Extent free count exceeded region count");
|
assert_zu_le(NFREE_READ(out, 1), NREGS_READ(out, 1),
|
||||||
assert_zu_eq(NREGS_READ(out, 0), NREGS_READ(out, 1),
|
"Extent free count exceeded region count");
|
||||||
"Extent region count should be same for same region size");
|
} else {
|
||||||
assert_zu_eq(SIZE_READ(out, 0), SIZE_READ(out, 1),
|
assert_zu_eq(NFREE_READ(out, 0), 0,
|
||||||
"Extent size should be same for same region size");
|
"Extent free count should be zero");
|
||||||
|
}
|
||||||
|
assert_zu_eq(NREGS_READ(out, 0), NREGS_READ(out, 1),
|
||||||
|
"Extent region count should be same for same region size");
|
||||||
|
assert_zu_eq(SIZE_READ(out, 0), SIZE_READ(out, 1),
|
||||||
|
"Extent size should be same for same region size");
|
||||||
|
|
||||||
#undef SIZE_READ
|
#undef SIZE_READ
|
||||||
#undef NREGS_READ
|
#undef NREGS_READ
|
||||||
@ -179,12 +255,15 @@ TEST_BEGIN(test_batch) {
|
|||||||
|
|
||||||
#undef TEST_EQUAL_REF
|
#undef TEST_EQUAL_REF
|
||||||
|
|
||||||
free(q);
|
free(q);
|
||||||
free(p);
|
free(p);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
TEST_END
|
TEST_END
|
||||||
|
|
||||||
int
|
int
|
||||||
main(void) {
|
main(void) {
|
||||||
|
assert_zu_lt(SC_SMALL_MAXCLASS, TEST_MAX_SIZE,
|
||||||
|
"Test case cannot cover large classes");
|
||||||
return test(test_query, test_batch);
|
return test(test_query, test_batch);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user