Edata cache small: rewrite.
In previous designs, this was intended to be a sort of cache that couldn't fail. In the current design, we want to use it just as a contention reduction mechanism. Rewrite it with those goals in mind.
This commit is contained in:
committed by
David Goldblatt
parent
c9757d9e3b
commit
03a6047111
@@ -47,37 +47,198 @@ TEST_BEGIN(test_edata_cache) {
|
||||
}
|
||||
TEST_END
|
||||
|
||||
TEST_BEGIN(test_edata_cache_small) {
|
||||
TEST_BEGIN(test_edata_cache_small_simple) {
|
||||
edata_cache_t ec;
|
||||
edata_cache_small_t ecs;
|
||||
|
||||
test_edata_cache_init(&ec);
|
||||
edata_cache_small_init(&ecs, &ec);
|
||||
|
||||
bool err = edata_cache_small_prepare(TSDN_NULL, &ecs, 2);
|
||||
assert_false(err, "");
|
||||
assert_zu_eq(ecs.count, 2, "");
|
||||
assert_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, "");
|
||||
edata_t *ed1 = edata_cache_small_get(TSDN_NULL, &ecs);
|
||||
expect_ptr_not_null(ed1, "");
|
||||
expect_zu_eq(ecs.count, 0, "");
|
||||
expect_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, "");
|
||||
|
||||
edata_t *ed1 = edata_cache_small_get(&ecs);
|
||||
assert_zu_eq(ecs.count, 1, "");
|
||||
assert_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, "");
|
||||
edata_t *ed2 = edata_cache_small_get(TSDN_NULL, &ecs);
|
||||
expect_ptr_not_null(ed2, "");
|
||||
expect_zu_eq(ecs.count, 0, "");
|
||||
expect_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, "");
|
||||
|
||||
edata_t *ed2 = edata_cache_small_get(&ecs);
|
||||
assert_zu_eq(ecs.count, 0, "");
|
||||
assert_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, "");
|
||||
edata_cache_small_put(TSDN_NULL, &ecs, ed1);
|
||||
expect_zu_eq(ecs.count, 1, "");
|
||||
expect_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, "");
|
||||
|
||||
edata_cache_small_put(&ecs, ed1);
|
||||
assert_zu_eq(ecs.count, 1, "");
|
||||
assert_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, "");
|
||||
edata_cache_small_put(TSDN_NULL, &ecs, ed2);
|
||||
expect_zu_eq(ecs.count, 2, "");
|
||||
expect_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, "");
|
||||
|
||||
edata_cache_small_put(&ecs, ed2);
|
||||
assert_zu_eq(ecs.count, 2, "");
|
||||
assert_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, "");
|
||||
/* LIFO ordering. */
|
||||
expect_ptr_eq(ed2, edata_cache_small_get(TSDN_NULL, &ecs), "");
|
||||
expect_zu_eq(ecs.count, 1, "");
|
||||
expect_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, "");
|
||||
|
||||
edata_cache_small_finish(TSDN_NULL, &ecs, 1);
|
||||
assert_zu_eq(ecs.count, 1, "");
|
||||
assert_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 1, "");
|
||||
expect_ptr_eq(ed1, edata_cache_small_get(TSDN_NULL, &ecs), "");
|
||||
expect_zu_eq(ecs.count, 0, "");
|
||||
expect_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, "");
|
||||
|
||||
test_edata_cache_destroy(&ec);
|
||||
}
|
||||
TEST_END
|
||||
|
||||
TEST_BEGIN(test_edata_cache_fill) {
|
||||
edata_cache_t ec;
|
||||
edata_cache_small_t ecs;
|
||||
|
||||
test_edata_cache_init(&ec);
|
||||
edata_cache_small_init(&ecs, &ec);
|
||||
|
||||
edata_t *allocs[EDATA_CACHE_SMALL_FILL * 2];
|
||||
|
||||
/*
|
||||
* If the fallback cache can't satisfy the request, we shouldn't do
|
||||
* extra allocations until compelled to. Put half the fill goal in the
|
||||
* fallback.
|
||||
*/
|
||||
for (int i = 0; i < EDATA_CACHE_SMALL_FILL / 2; i++) {
|
||||
allocs[i] = edata_cache_get(TSDN_NULL, &ec);
|
||||
}
|
||||
for (int i = 0; i < EDATA_CACHE_SMALL_FILL / 2; i++) {
|
||||
edata_cache_put(TSDN_NULL, &ec, allocs[i]);
|
||||
}
|
||||
expect_zu_eq(EDATA_CACHE_SMALL_FILL / 2,
|
||||
atomic_load_zu(&ec.count, ATOMIC_RELAXED), "");
|
||||
|
||||
allocs[0] = edata_cache_small_get(TSDN_NULL, &ecs);
|
||||
expect_zu_eq(EDATA_CACHE_SMALL_FILL / 2 - 1, ecs.count,
|
||||
"Should have grabbed all edatas available but no more.");
|
||||
|
||||
for (int i = 1; i < EDATA_CACHE_SMALL_FILL / 2; i++) {
|
||||
allocs[i] = edata_cache_small_get(TSDN_NULL, &ecs);
|
||||
expect_ptr_not_null(allocs[i], "");
|
||||
}
|
||||
expect_zu_eq(0, ecs.count, "");
|
||||
|
||||
/* When forced, we should alloc from the base. */
|
||||
edata_t *edata = edata_cache_small_get(TSDN_NULL, &ecs);
|
||||
expect_ptr_not_null(edata, "");
|
||||
expect_zu_eq(0, ecs.count, "Allocated more than necessary");
|
||||
expect_zu_eq(0, atomic_load_zu(&ec.count, ATOMIC_RELAXED),
|
||||
"Allocated more than necessary");
|
||||
|
||||
/*
|
||||
* We should correctly fill in the common case where the fallback isn't
|
||||
* exhausted, too.
|
||||
*/
|
||||
for (int i = 0; i < EDATA_CACHE_SMALL_FILL * 2; i++) {
|
||||
allocs[i] = edata_cache_get(TSDN_NULL, &ec);
|
||||
expect_ptr_not_null(allocs[i], "");
|
||||
}
|
||||
for (int i = 0; i < EDATA_CACHE_SMALL_FILL * 2; i++) {
|
||||
edata_cache_put(TSDN_NULL, &ec, allocs[i]);
|
||||
}
|
||||
|
||||
allocs[0] = edata_cache_small_get(TSDN_NULL, &ecs);
|
||||
expect_zu_eq(EDATA_CACHE_SMALL_FILL - 1, ecs.count, "");
|
||||
expect_zu_eq(EDATA_CACHE_SMALL_FILL,
|
||||
atomic_load_zu(&ec.count, ATOMIC_RELAXED), "");
|
||||
for (int i = 1; i < EDATA_CACHE_SMALL_FILL; i++) {
|
||||
expect_zu_eq(EDATA_CACHE_SMALL_FILL - i, ecs.count, "");
|
||||
expect_zu_eq(EDATA_CACHE_SMALL_FILL,
|
||||
atomic_load_zu(&ec.count, ATOMIC_RELAXED), "");
|
||||
allocs[i] = edata_cache_small_get(TSDN_NULL, &ecs);
|
||||
expect_ptr_not_null(allocs[i], "");
|
||||
}
|
||||
expect_zu_eq(0, ecs.count, "");
|
||||
expect_zu_eq(EDATA_CACHE_SMALL_FILL,
|
||||
atomic_load_zu(&ec.count, ATOMIC_RELAXED), "");
|
||||
|
||||
allocs[0] = edata_cache_small_get(TSDN_NULL, &ecs);
|
||||
expect_zu_eq(EDATA_CACHE_SMALL_FILL - 1, ecs.count, "");
|
||||
expect_zu_eq(0, atomic_load_zu(&ec.count, ATOMIC_RELAXED), "");
|
||||
for (int i = 1; i < EDATA_CACHE_SMALL_FILL; i++) {
|
||||
expect_zu_eq(EDATA_CACHE_SMALL_FILL - i, ecs.count, "");
|
||||
expect_zu_eq(0, atomic_load_zu(&ec.count, ATOMIC_RELAXED), "");
|
||||
allocs[i] = edata_cache_small_get(TSDN_NULL, &ecs);
|
||||
expect_ptr_not_null(allocs[i], "");
|
||||
}
|
||||
expect_zu_eq(0, ecs.count, "");
|
||||
expect_zu_eq(0, atomic_load_zu(&ec.count, ATOMIC_RELAXED), "");
|
||||
|
||||
test_edata_cache_destroy(&ec);
|
||||
}
|
||||
TEST_END
|
||||
|
||||
TEST_BEGIN(test_edata_cache_flush) {
|
||||
edata_cache_t ec;
|
||||
edata_cache_small_t ecs;
|
||||
|
||||
test_edata_cache_init(&ec);
|
||||
edata_cache_small_init(&ecs, &ec);
|
||||
|
||||
edata_t *allocs[2 * EDATA_CACHE_SMALL_MAX + 2];
|
||||
for (int i = 0; i < 2 * EDATA_CACHE_SMALL_MAX + 2; i++) {
|
||||
allocs[i] = edata_cache_get(TSDN_NULL, &ec);
|
||||
expect_ptr_not_null(allocs[i], "");
|
||||
}
|
||||
for (int i = 0; i < EDATA_CACHE_SMALL_MAX; i++) {
|
||||
edata_cache_small_put(TSDN_NULL, &ecs, allocs[i]);
|
||||
expect_zu_eq(i + 1, ecs.count, "");
|
||||
expect_zu_eq(0, atomic_load_zu(&ec.count, ATOMIC_RELAXED), "");
|
||||
}
|
||||
edata_cache_small_put(TSDN_NULL, &ecs, allocs[EDATA_CACHE_SMALL_MAX]);
|
||||
expect_zu_eq(0, ecs.count, "");
|
||||
expect_zu_eq(EDATA_CACHE_SMALL_MAX + 1,
|
||||
atomic_load_zu(&ec.count, ATOMIC_RELAXED), "");
|
||||
|
||||
for (int i = EDATA_CACHE_SMALL_MAX + 1;
|
||||
i < 2 * EDATA_CACHE_SMALL_MAX + 1; i++) {
|
||||
edata_cache_small_put(TSDN_NULL, &ecs, allocs[i]);
|
||||
expect_zu_eq(i - EDATA_CACHE_SMALL_MAX, ecs.count, "");
|
||||
expect_zu_eq(EDATA_CACHE_SMALL_MAX + 1,
|
||||
atomic_load_zu(&ec.count, ATOMIC_RELAXED), "");
|
||||
}
|
||||
edata_cache_small_put(TSDN_NULL, &ecs, allocs[2 * EDATA_CACHE_SMALL_MAX + 1]);
|
||||
expect_zu_eq(0, ecs.count, "");
|
||||
expect_zu_eq(2 * EDATA_CACHE_SMALL_MAX + 2,
|
||||
atomic_load_zu(&ec.count, ATOMIC_RELAXED), "");
|
||||
|
||||
test_edata_cache_destroy(&ec);
|
||||
}
|
||||
TEST_END
|
||||
|
||||
TEST_BEGIN(test_edata_cache_disable) {
|
||||
edata_cache_t ec;
|
||||
edata_cache_small_t ecs;
|
||||
|
||||
test_edata_cache_init(&ec);
|
||||
edata_cache_small_init(&ecs, &ec);
|
||||
|
||||
for (int i = 0; i < EDATA_CACHE_SMALL_FILL; i++) {
|
||||
edata_t *edata = edata_cache_get(TSDN_NULL, &ec);
|
||||
expect_ptr_not_null(edata, "");
|
||||
edata_cache_small_put(TSDN_NULL, &ecs, edata);
|
||||
}
|
||||
|
||||
expect_zu_eq(EDATA_CACHE_SMALL_FILL, ecs.count, "");
|
||||
expect_zu_eq(0, atomic_load_zu(&ec.count, ATOMIC_RELAXED), "");
|
||||
|
||||
edata_cache_small_disable(TSDN_NULL, &ecs);
|
||||
|
||||
expect_zu_eq(0, ecs.count, "");
|
||||
expect_zu_eq(EDATA_CACHE_SMALL_FILL,
|
||||
atomic_load_zu(&ec.count, ATOMIC_RELAXED), "Disabling should flush");
|
||||
|
||||
edata_t *edata = edata_cache_small_get(TSDN_NULL, &ecs);
|
||||
expect_zu_eq(0, ecs.count, "");
|
||||
expect_zu_eq(EDATA_CACHE_SMALL_FILL - 1,
|
||||
atomic_load_zu(&ec.count, ATOMIC_RELAXED),
|
||||
"Disabled ecs should forward on get");
|
||||
|
||||
edata_cache_small_put(TSDN_NULL, &ecs, edata);
|
||||
expect_zu_eq(0, ecs.count, "");
|
||||
expect_zu_eq(EDATA_CACHE_SMALL_FILL,
|
||||
atomic_load_zu(&ec.count, ATOMIC_RELAXED),
|
||||
"Disabled ecs should forward on put");
|
||||
|
||||
test_edata_cache_destroy(&ec);
|
||||
}
|
||||
@@ -87,5 +248,8 @@ int
|
||||
main(void) {
|
||||
return test(
|
||||
test_edata_cache,
|
||||
test_edata_cache_small);
|
||||
test_edata_cache_small_simple,
|
||||
test_edata_cache_fill,
|
||||
test_edata_cache_flush,
|
||||
test_edata_cache_disable);
|
||||
}
|
||||
|
Reference in New Issue
Block a user