mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
mm/damon/tests/core-kunit: test the size charged for a filter-trimmed region
damos_test_filter_out() checks that an address range filter splits a region at the filter boundary, and stops there. Nothing checks what damos_apply_scheme() then charges to the quota and reports as tried. damos_test_apply_scheme_filtered_sz() covers the two ways such a filter trims a region: one that starts before the filter's range, and one that starts inside it. damos_test_apply_scheme_filter_sz_unchanged() and damos_test_apply_scheme_quota_sz() cover the cases whose accounting must not change: a region wholly inside a reject range, one wholly inside an allow range, two filters trimming in a single call, a filter type that never splits, no filter at all, a region the quota trims, and a quota remainder too small for one region. Link: https://lore.kernel.org/20260921152443.80132-3-sj@kernel.org Signed-off-by: Donggeun Yoo <donggeunyoo.kernel@gmail.com> Signed-off-by: SJ Park <sj@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Reviewed-by: SJ Park <sj@kernel.org> Cc: Brendan Higgins <brendan.higgins@linux.dev> Cc: David Gow <david@davidgow.net> Cc: <stable@vger.kernel.org>
This commit is contained in:
parent
4ff3b4a54a
commit
1c33522820
|
|
@ -1706,6 +1706,319 @@ static void damos_test_filter_out(struct kunit *test)
|
|||
damos_free_filter(f);
|
||||
}
|
||||
|
||||
static unsigned long damos_test_apply_scheme_stub(struct damon_ctx *c,
|
||||
struct damon_target *t, struct damon_region *r,
|
||||
struct damos *s, unsigned long *sz_filter_passed)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void damos_test_apply_scheme_filtered_sz(struct kunit *test)
|
||||
{
|
||||
struct damos_access_pattern pattern = {
|
||||
.min_sz_region = 0,
|
||||
.max_sz_region = ULONG_MAX,
|
||||
.min_nr_accesses = 0,
|
||||
.max_nr_accesses = UINT_MAX,
|
||||
.min_age_region = 0,
|
||||
.max_age_region = UINT_MAX,
|
||||
};
|
||||
unsigned long min_sz = DAMON_MIN_REGION_SZ;
|
||||
struct damos_watermarks wmarks = {};
|
||||
struct damos_quota quota = {};
|
||||
struct damon_ctx *c;
|
||||
struct damon_target *t;
|
||||
struct damon_region *r;
|
||||
struct damos_filter *f;
|
||||
struct damos *s;
|
||||
|
||||
c = damon_new_ctx();
|
||||
if (!c)
|
||||
kunit_skip(test, "ctx alloc fail");
|
||||
c->ops.apply_scheme = damos_test_apply_scheme_stub;
|
||||
|
||||
s = damon_new_scheme(&pattern, DAMOS_STAT, 0, "a, &wmarks,
|
||||
NUMA_NO_NODE);
|
||||
if (!s) {
|
||||
damon_destroy_ctx(c);
|
||||
kunit_skip(test, "scheme alloc fail");
|
||||
}
|
||||
damon_add_scheme(c, s);
|
||||
|
||||
t = damon_new_target();
|
||||
if (!t) {
|
||||
damon_destroy_ctx(c);
|
||||
kunit_skip(test, "target alloc fail");
|
||||
}
|
||||
damon_add_target(c, t);
|
||||
|
||||
f = damos_new_filter(DAMOS_FILTER_TYPE_ADDR, true, false);
|
||||
if (!f) {
|
||||
damon_destroy_ctx(c);
|
||||
kunit_skip(test, "filter alloc fail");
|
||||
}
|
||||
f->addr_range = (struct damon_addr_range){
|
||||
.start = 2 * min_sz,
|
||||
.end = 8 * min_sz
|
||||
};
|
||||
damos_add_filter(s, f);
|
||||
damos_set_filters_default_reject(s);
|
||||
|
||||
/* reject filter, region starting before the range */
|
||||
r = damon_new_region(0, 4 * min_sz);
|
||||
if (!r) {
|
||||
damon_destroy_ctx(c);
|
||||
kunit_skip(test, "region alloc fail");
|
||||
}
|
||||
damon_add_region(r, t);
|
||||
|
||||
damos_apply_scheme(c, t, r, s);
|
||||
KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 2);
|
||||
KUNIT_EXPECT_EQ(test, r->ar.end, 2 * min_sz);
|
||||
KUNIT_EXPECT_EQ(test, s->stat.sz_tried, 2 * min_sz);
|
||||
|
||||
if (damon_nr_regions(t) != 2)
|
||||
goto out;
|
||||
damon_destroy_region(damon_next_region(r), t);
|
||||
damon_destroy_region(r, t);
|
||||
s->stat = (struct damos_stat){};
|
||||
|
||||
/* allow filter, region starting inside the range */
|
||||
f->allow = true;
|
||||
damos_set_filters_default_reject(s);
|
||||
r = damon_new_region(2 * min_sz, 10 * min_sz);
|
||||
if (!r) {
|
||||
damon_destroy_ctx(c);
|
||||
kunit_skip(test, "region alloc fail");
|
||||
}
|
||||
damon_add_region(r, t);
|
||||
|
||||
damos_apply_scheme(c, t, r, s);
|
||||
KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 2);
|
||||
KUNIT_EXPECT_EQ(test, r->ar.end, 8 * min_sz);
|
||||
KUNIT_EXPECT_EQ(test, s->stat.sz_tried, 6 * min_sz);
|
||||
|
||||
out:
|
||||
damon_destroy_ctx(c);
|
||||
}
|
||||
|
||||
static void damos_test_apply_scheme_filter_sz_unchanged(struct kunit *test)
|
||||
{
|
||||
struct damos_access_pattern pattern = {
|
||||
.min_sz_region = 0,
|
||||
.max_sz_region = ULONG_MAX,
|
||||
.min_nr_accesses = 0,
|
||||
.max_nr_accesses = UINT_MAX,
|
||||
.min_age_region = 0,
|
||||
.max_age_region = UINT_MAX,
|
||||
};
|
||||
unsigned long min_sz = DAMON_MIN_REGION_SZ;
|
||||
struct damos_watermarks wmarks = {};
|
||||
struct damos_quota quota = {};
|
||||
struct damos_filter *f, *f2;
|
||||
struct damon_ctx *c;
|
||||
struct damon_target *t;
|
||||
struct damon_region *r;
|
||||
struct damos *s;
|
||||
|
||||
c = damon_new_ctx();
|
||||
if (!c)
|
||||
kunit_skip(test, "ctx alloc fail");
|
||||
c->ops.apply_scheme = damos_test_apply_scheme_stub;
|
||||
|
||||
s = damon_new_scheme(&pattern, DAMOS_STAT, 0, "a, &wmarks,
|
||||
NUMA_NO_NODE);
|
||||
if (!s) {
|
||||
damon_destroy_ctx(c);
|
||||
kunit_skip(test, "scheme alloc fail");
|
||||
}
|
||||
damon_add_scheme(c, s);
|
||||
|
||||
t = damon_new_target();
|
||||
if (!t) {
|
||||
damon_destroy_ctx(c);
|
||||
kunit_skip(test, "target alloc fail");
|
||||
}
|
||||
damon_add_target(c, t);
|
||||
|
||||
f = damos_new_filter(DAMOS_FILTER_TYPE_ADDR, true, false);
|
||||
if (!f) {
|
||||
damon_destroy_ctx(c);
|
||||
kunit_skip(test, "filter alloc fail");
|
||||
}
|
||||
f->addr_range = (struct damon_addr_range){
|
||||
.start = 2 * min_sz, .end = 8 * min_sz};
|
||||
damos_add_filter(s, f);
|
||||
damos_set_filters_default_reject(s);
|
||||
|
||||
/* wholly inside a reject range: not counted at all */
|
||||
r = damon_new_region(4 * min_sz, 6 * min_sz);
|
||||
if (!r) {
|
||||
damon_destroy_ctx(c);
|
||||
kunit_skip(test, "region alloc fail");
|
||||
}
|
||||
damon_add_region(r, t);
|
||||
|
||||
damos_apply_scheme(c, t, r, s);
|
||||
KUNIT_EXPECT_EQ(test, s->stat.nr_tried, 0);
|
||||
KUNIT_EXPECT_EQ(test, s->stat.sz_tried, 0);
|
||||
KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 1);
|
||||
|
||||
/* wholly inside an allow range: counted whole, not split */
|
||||
f->allow = true;
|
||||
damos_set_filters_default_reject(s);
|
||||
|
||||
damos_apply_scheme(c, t, r, s);
|
||||
KUNIT_EXPECT_EQ(test, s->stat.sz_tried, 2 * min_sz);
|
||||
KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 1);
|
||||
|
||||
/* two filters, each trimming: the size left after both is counted */
|
||||
damon_destroy_region(r, t);
|
||||
s->stat = (struct damos_stat){};
|
||||
f->allow = false;
|
||||
f->addr_range = (struct damon_addr_range){
|
||||
.start = 4 * min_sz, .end = 12 * min_sz};
|
||||
f2 = damos_new_filter(DAMOS_FILTER_TYPE_ADDR, true, false);
|
||||
if (!f2) {
|
||||
damon_destroy_ctx(c);
|
||||
kunit_skip(test, "filter alloc fail");
|
||||
}
|
||||
f2->addr_range = (struct damon_addr_range){
|
||||
.start = 2 * min_sz, .end = 3 * min_sz};
|
||||
damos_add_filter(s, f2);
|
||||
damos_set_filters_default_reject(s);
|
||||
|
||||
r = damon_new_region(0, 8 * min_sz);
|
||||
if (!r) {
|
||||
damon_destroy_ctx(c);
|
||||
kunit_skip(test, "region alloc fail");
|
||||
}
|
||||
damon_add_region(r, t);
|
||||
|
||||
damos_apply_scheme(c, t, r, s);
|
||||
KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 3);
|
||||
KUNIT_EXPECT_EQ(test, r->ar.end, 2 * min_sz);
|
||||
KUNIT_EXPECT_EQ(test, s->stat.sz_tried, 2 * min_sz);
|
||||
|
||||
/* a core filter that never splits: counted whole */
|
||||
damos_destroy_filter(f2);
|
||||
damos_destroy_filter(f);
|
||||
f = damos_new_filter(DAMOS_FILTER_TYPE_TARGET, true, true);
|
||||
if (!f) {
|
||||
damon_destroy_ctx(c);
|
||||
kunit_skip(test, "filter alloc fail");
|
||||
}
|
||||
f->target_idx = 0;
|
||||
damos_add_filter(s, f);
|
||||
damos_set_filters_default_reject(s);
|
||||
s->stat = (struct damos_stat){};
|
||||
|
||||
damos_apply_scheme(c, t, r, s);
|
||||
KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 3);
|
||||
KUNIT_EXPECT_EQ(test, r->ar.end, 2 * min_sz);
|
||||
KUNIT_EXPECT_EQ(test, s->stat.sz_tried, 2 * min_sz);
|
||||
|
||||
damon_destroy_ctx(c);
|
||||
}
|
||||
|
||||
static void damos_test_apply_scheme_quota_sz(struct kunit *test)
|
||||
{
|
||||
struct damos_access_pattern pattern = {
|
||||
.min_sz_region = 0,
|
||||
.max_sz_region = ULONG_MAX,
|
||||
.min_nr_accesses = 0,
|
||||
.max_nr_accesses = UINT_MAX,
|
||||
.min_age_region = 0,
|
||||
.max_age_region = UINT_MAX,
|
||||
};
|
||||
unsigned long min_sz = DAMON_MIN_REGION_SZ;
|
||||
struct damos_watermarks wmarks = {};
|
||||
struct damos_quota quota = {};
|
||||
struct damon_region *r, *next;
|
||||
struct damon_ctx *c;
|
||||
struct damon_target *t;
|
||||
struct damos *s;
|
||||
|
||||
c = damon_new_ctx();
|
||||
if (!c)
|
||||
kunit_skip(test, "ctx alloc fail");
|
||||
|
||||
s = damon_new_scheme(&pattern, DAMOS_STAT, 0, "a, &wmarks,
|
||||
NUMA_NO_NODE);
|
||||
if (!s) {
|
||||
damon_destroy_ctx(c);
|
||||
kunit_skip(test, "scheme alloc fail");
|
||||
}
|
||||
damon_add_scheme(c, s);
|
||||
damos_set_filters_default_reject(s);
|
||||
|
||||
t = damon_new_target();
|
||||
if (!t) {
|
||||
damon_destroy_ctx(c);
|
||||
kunit_skip(test, "target alloc fail");
|
||||
}
|
||||
damon_add_target(c, t);
|
||||
|
||||
/* no apply_scheme operation: the whole region is counted */
|
||||
r = damon_new_region(0, 4 * min_sz);
|
||||
if (!r) {
|
||||
damon_destroy_ctx(c);
|
||||
kunit_skip(test, "region alloc fail");
|
||||
}
|
||||
damon_add_region(r, t);
|
||||
|
||||
damos_apply_scheme(c, t, r, s);
|
||||
KUNIT_EXPECT_EQ(test, s->stat.sz_tried, 4 * min_sz);
|
||||
KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 1);
|
||||
|
||||
/* no filter and no quota: the whole region is counted */
|
||||
c->ops.apply_scheme = damos_test_apply_scheme_stub;
|
||||
s->stat = (struct damos_stat){};
|
||||
|
||||
damos_apply_scheme(c, t, r, s);
|
||||
KUNIT_EXPECT_EQ(test, s->stat.sz_tried, 4 * min_sz);
|
||||
KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 1);
|
||||
|
||||
/* the quota trims the region: the trimmed size is counted */
|
||||
damon_for_each_region_safe(r, next, t)
|
||||
damon_destroy_region(r, t);
|
||||
s->stat = (struct damos_stat){};
|
||||
s->quota.esz = 2 * min_sz;
|
||||
s->quota.charged_sz = 0;
|
||||
|
||||
r = damon_new_region(0, 8 * min_sz);
|
||||
if (!r) {
|
||||
damon_destroy_ctx(c);
|
||||
kunit_skip(test, "region alloc fail");
|
||||
}
|
||||
damon_add_region(r, t);
|
||||
|
||||
damos_apply_scheme(c, t, r, s);
|
||||
KUNIT_EXPECT_EQ(test, r->ar.end, 2 * min_sz);
|
||||
KUNIT_EXPECT_EQ(test, s->stat.sz_tried, 2 * min_sz);
|
||||
|
||||
/* quota remainder below one region: tried, but nothing counted */
|
||||
damon_for_each_region_safe(r, next, t)
|
||||
damon_destroy_region(r, t);
|
||||
s->stat = (struct damos_stat){};
|
||||
s->quota.esz = 1;
|
||||
s->quota.charged_sz = 0;
|
||||
|
||||
r = damon_new_region(0, 4 * min_sz);
|
||||
if (!r) {
|
||||
damon_destroy_ctx(c);
|
||||
kunit_skip(test, "region alloc fail");
|
||||
}
|
||||
damon_add_region(r, t);
|
||||
|
||||
damos_apply_scheme(c, t, r, s);
|
||||
KUNIT_EXPECT_EQ(test, s->stat.nr_tried, 1);
|
||||
KUNIT_EXPECT_EQ(test, s->stat.sz_tried, 0);
|
||||
KUNIT_EXPECT_EQ(test, r->ar.end, 4 * min_sz);
|
||||
|
||||
damon_destroy_ctx(c);
|
||||
}
|
||||
|
||||
static void damon_test_feed_loop_next_input(struct kunit *test)
|
||||
{
|
||||
unsigned long last_input = 900000, current_score = 200;
|
||||
|
|
@ -1959,6 +2272,9 @@ static struct kunit_case damon_test_cases[] = {
|
|||
KUNIT_CASE(damon_test_commit_ctx),
|
||||
KUNIT_CASE(damon_test_valid_probe_params),
|
||||
KUNIT_CASE(damos_test_filter_out),
|
||||
KUNIT_CASE(damos_test_apply_scheme_filtered_sz),
|
||||
KUNIT_CASE(damos_test_apply_scheme_filter_sz_unchanged),
|
||||
KUNIT_CASE(damos_test_apply_scheme_quota_sz),
|
||||
KUNIT_CASE(damon_test_feed_loop_next_input),
|
||||
KUNIT_CASE(damon_test_set_filters_default_reject),
|
||||
KUNIT_CASE(damon_test_apply_min_nr_regions),
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user