Skip to content

Commit 17ccae8

Browse files
sj-awstorvalds
authored andcommitted
mm/damon: add kunit tests
This commit adds kunit based unit tests for the core and the virtual address spaces monitoring primitives of DAMON. Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: SeongJae Park <[email protected]> Reviewed-by: Brendan Higgins <[email protected]> Cc: Alexander Shishkin <[email protected]> Cc: Amit Shah <[email protected]> Cc: Benjamin Herrenschmidt <[email protected]> Cc: David Hildenbrand <[email protected]> Cc: David Rientjes <[email protected]> Cc: David Woodhouse <[email protected]> Cc: Fan Du <[email protected]> Cc: Fernand Sieber <[email protected]> Cc: Greg Kroah-Hartman <[email protected]> Cc: Greg Thelen <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: Joe Perches <[email protected]> Cc: Jonathan Cameron <[email protected]> Cc: Jonathan Corbet <[email protected]> Cc: Leonard Foerster <[email protected]> Cc: Marco Elver <[email protected]> Cc: Markus Boehme <[email protected]> Cc: Maximilian Heyne <[email protected]> Cc: Mel Gorman <[email protected]> Cc: Minchan Kim <[email protected]> Cc: Namhyung Kim <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Rik van Riel <[email protected]> Cc: Shakeel Butt <[email protected]> Cc: Shuah Khan <[email protected]> Cc: Steven Rostedt (VMware) <[email protected]> Cc: Vladimir Davydov <[email protected]> Cc: Vlastimil Babka <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent c4ba601 commit 17ccae8

File tree

7 files changed

+760
-0
lines changed

7 files changed

+760
-0
lines changed

mm/damon/Kconfig

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,18 @@ config DAMON
1212
See https://damonitor.github.io/doc/html/latest-damon/index.html for
1313
more information.
1414

15+
config DAMON_KUNIT_TEST
16+
bool "Test for damon" if !KUNIT_ALL_TESTS
17+
depends on DAMON && KUNIT=y
18+
default KUNIT_ALL_TESTS
19+
help
20+
This builds the DAMON Kunit test suite.
21+
22+
For more information on KUnit and unit tests in general, please refer
23+
to the KUnit documentation.
24+
25+
If unsure, say N.
26+
1527
config DAMON_VADDR
1628
bool "Data access monitoring primitives for virtual address spaces"
1729
depends on DAMON && MMU
@@ -20,6 +32,18 @@ config DAMON_VADDR
2032
This builds the default data access monitoring primitives for DAMON
2133
that works for virtual address spaces.
2234

35+
config DAMON_VADDR_KUNIT_TEST
36+
bool "Test for DAMON primitives" if !KUNIT_ALL_TESTS
37+
depends on DAMON_VADDR && KUNIT=y
38+
default KUNIT_ALL_TESTS
39+
help
40+
This builds the DAMON virtual addresses primitives Kunit test suite.
41+
42+
For more information on KUnit and unit tests in general, please refer
43+
to the KUnit documentation.
44+
45+
If unsure, say N.
46+
2347
config DAMON_DBGFS
2448
bool "DAMON debugfs interface"
2549
depends on DAMON_VADDR && DEBUG_FS
@@ -29,4 +53,16 @@ config DAMON_DBGFS
2953

3054
If unsure, say N.
3155

56+
config DAMON_DBGFS_KUNIT_TEST
57+
bool "Test for damon debugfs interface" if !KUNIT_ALL_TESTS
58+
depends on DAMON_DBGFS && KUNIT=y
59+
default KUNIT_ALL_TESTS
60+
help
61+
This builds the DAMON debugfs interface Kunit test suite.
62+
63+
For more information on KUnit and unit tests in general, please refer
64+
to the KUnit documentation.
65+
66+
If unsure, say N.
67+
3268
endmenu

mm/damon/core-test.h

Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/*
3+
* Data Access Monitor Unit Tests
4+
*
5+
* Copyright 2019 Amazon.com, Inc. or its affiliates. All rights reserved.
6+
*
7+
* Author: SeongJae Park <[email protected]>
8+
*/
9+
10+
#ifdef CONFIG_DAMON_KUNIT_TEST
11+
12+
#ifndef _DAMON_CORE_TEST_H
13+
#define _DAMON_CORE_TEST_H
14+
15+
#include <kunit/test.h>
16+
17+
static void damon_test_regions(struct kunit *test)
18+
{
19+
struct damon_region *r;
20+
struct damon_target *t;
21+
22+
r = damon_new_region(1, 2);
23+
KUNIT_EXPECT_EQ(test, 1ul, r->ar.start);
24+
KUNIT_EXPECT_EQ(test, 2ul, r->ar.end);
25+
KUNIT_EXPECT_EQ(test, 0u, r->nr_accesses);
26+
27+
t = damon_new_target(42);
28+
KUNIT_EXPECT_EQ(test, 0u, damon_nr_regions(t));
29+
30+
damon_add_region(r, t);
31+
KUNIT_EXPECT_EQ(test, 1u, damon_nr_regions(t));
32+
33+
damon_del_region(r, t);
34+
KUNIT_EXPECT_EQ(test, 0u, damon_nr_regions(t));
35+
36+
damon_free_target(t);
37+
}
38+
39+
static unsigned int nr_damon_targets(struct damon_ctx *ctx)
40+
{
41+
struct damon_target *t;
42+
unsigned int nr_targets = 0;
43+
44+
damon_for_each_target(t, ctx)
45+
nr_targets++;
46+
47+
return nr_targets;
48+
}
49+
50+
static void damon_test_target(struct kunit *test)
51+
{
52+
struct damon_ctx *c = damon_new_ctx();
53+
struct damon_target *t;
54+
55+
t = damon_new_target(42);
56+
KUNIT_EXPECT_EQ(test, 42ul, t->id);
57+
KUNIT_EXPECT_EQ(test, 0u, nr_damon_targets(c));
58+
59+
damon_add_target(c, t);
60+
KUNIT_EXPECT_EQ(test, 1u, nr_damon_targets(c));
61+
62+
damon_destroy_target(t);
63+
KUNIT_EXPECT_EQ(test, 0u, nr_damon_targets(c));
64+
65+
damon_destroy_ctx(c);
66+
}
67+
68+
/*
69+
* Test kdamond_reset_aggregated()
70+
*
71+
* DAMON checks access to each region and aggregates this information as the
72+
* access frequency of each region. In detail, it increases '->nr_accesses' of
73+
* regions that an access has confirmed. 'kdamond_reset_aggregated()' flushes
74+
* the aggregated information ('->nr_accesses' of each regions) to the result
75+
* buffer. As a result of the flushing, the '->nr_accesses' of regions are
76+
* initialized to zero.
77+
*/
78+
static void damon_test_aggregate(struct kunit *test)
79+
{
80+
struct damon_ctx *ctx = damon_new_ctx();
81+
unsigned long target_ids[] = {1, 2, 3};
82+
unsigned long saddr[][3] = {{10, 20, 30}, {5, 42, 49}, {13, 33, 55} };
83+
unsigned long eaddr[][3] = {{15, 27, 40}, {31, 45, 55}, {23, 44, 66} };
84+
unsigned long accesses[][3] = {{42, 95, 84}, {10, 20, 30}, {0, 1, 2} };
85+
struct damon_target *t;
86+
struct damon_region *r;
87+
int it, ir;
88+
89+
damon_set_targets(ctx, target_ids, 3);
90+
91+
it = 0;
92+
damon_for_each_target(t, ctx) {
93+
for (ir = 0; ir < 3; ir++) {
94+
r = damon_new_region(saddr[it][ir], eaddr[it][ir]);
95+
r->nr_accesses = accesses[it][ir];
96+
damon_add_region(r, t);
97+
}
98+
it++;
99+
}
100+
kdamond_reset_aggregated(ctx);
101+
it = 0;
102+
damon_for_each_target(t, ctx) {
103+
ir = 0;
104+
/* '->nr_accesses' should be zeroed */
105+
damon_for_each_region(r, t) {
106+
KUNIT_EXPECT_EQ(test, 0u, r->nr_accesses);
107+
ir++;
108+
}
109+
/* regions should be preserved */
110+
KUNIT_EXPECT_EQ(test, 3, ir);
111+
it++;
112+
}
113+
/* targets also should be preserved */
114+
KUNIT_EXPECT_EQ(test, 3, it);
115+
116+
damon_destroy_ctx(ctx);
117+
}
118+
119+
static void damon_test_split_at(struct kunit *test)
120+
{
121+
struct damon_ctx *c = damon_new_ctx();
122+
struct damon_target *t;
123+
struct damon_region *r;
124+
125+
t = damon_new_target(42);
126+
r = damon_new_region(0, 100);
127+
damon_add_region(r, t);
128+
damon_split_region_at(c, t, r, 25);
129+
KUNIT_EXPECT_EQ(test, r->ar.start, 0ul);
130+
KUNIT_EXPECT_EQ(test, r->ar.end, 25ul);
131+
132+
r = damon_next_region(r);
133+
KUNIT_EXPECT_EQ(test, r->ar.start, 25ul);
134+
KUNIT_EXPECT_EQ(test, r->ar.end, 100ul);
135+
136+
damon_free_target(t);
137+
damon_destroy_ctx(c);
138+
}
139+
140+
static void damon_test_merge_two(struct kunit *test)
141+
{
142+
struct damon_target *t;
143+
struct damon_region *r, *r2, *r3;
144+
int i;
145+
146+
t = damon_new_target(42);
147+
r = damon_new_region(0, 100);
148+
r->nr_accesses = 10;
149+
damon_add_region(r, t);
150+
r2 = damon_new_region(100, 300);
151+
r2->nr_accesses = 20;
152+
damon_add_region(r2, t);
153+
154+
damon_merge_two_regions(t, r, r2);
155+
KUNIT_EXPECT_EQ(test, r->ar.start, 0ul);
156+
KUNIT_EXPECT_EQ(test, r->ar.end, 300ul);
157+
KUNIT_EXPECT_EQ(test, r->nr_accesses, 16u);
158+
159+
i = 0;
160+
damon_for_each_region(r3, t) {
161+
KUNIT_EXPECT_PTR_EQ(test, r, r3);
162+
i++;
163+
}
164+
KUNIT_EXPECT_EQ(test, i, 1);
165+
166+
damon_free_target(t);
167+
}
168+
169+
static struct damon_region *__nth_region_of(struct damon_target *t, int idx)
170+
{
171+
struct damon_region *r;
172+
unsigned int i = 0;
173+
174+
damon_for_each_region(r, t) {
175+
if (i++ == idx)
176+
return r;
177+
}
178+
179+
return NULL;
180+
}
181+
182+
static void damon_test_merge_regions_of(struct kunit *test)
183+
{
184+
struct damon_target *t;
185+
struct damon_region *r;
186+
unsigned long sa[] = {0, 100, 114, 122, 130, 156, 170, 184};
187+
unsigned long ea[] = {100, 112, 122, 130, 156, 170, 184, 230};
188+
unsigned int nrs[] = {0, 0, 10, 10, 20, 30, 1, 2};
189+
190+
unsigned long saddrs[] = {0, 114, 130, 156, 170};
191+
unsigned long eaddrs[] = {112, 130, 156, 170, 230};
192+
int i;
193+
194+
t = damon_new_target(42);
195+
for (i = 0; i < ARRAY_SIZE(sa); i++) {
196+
r = damon_new_region(sa[i], ea[i]);
197+
r->nr_accesses = nrs[i];
198+
damon_add_region(r, t);
199+
}
200+
201+
damon_merge_regions_of(t, 9, 9999);
202+
/* 0-112, 114-130, 130-156, 156-170 */
203+
KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 5u);
204+
for (i = 0; i < 5; i++) {
205+
r = __nth_region_of(t, i);
206+
KUNIT_EXPECT_EQ(test, r->ar.start, saddrs[i]);
207+
KUNIT_EXPECT_EQ(test, r->ar.end, eaddrs[i]);
208+
}
209+
damon_free_target(t);
210+
}
211+
212+
static void damon_test_split_regions_of(struct kunit *test)
213+
{
214+
struct damon_ctx *c = damon_new_ctx();
215+
struct damon_target *t;
216+
struct damon_region *r;
217+
218+
t = damon_new_target(42);
219+
r = damon_new_region(0, 22);
220+
damon_add_region(r, t);
221+
damon_split_regions_of(c, t, 2);
222+
KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 2u);
223+
damon_free_target(t);
224+
225+
t = damon_new_target(42);
226+
r = damon_new_region(0, 220);
227+
damon_add_region(r, t);
228+
damon_split_regions_of(c, t, 4);
229+
KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 4u);
230+
damon_free_target(t);
231+
damon_destroy_ctx(c);
232+
}
233+
234+
static struct kunit_case damon_test_cases[] = {
235+
KUNIT_CASE(damon_test_target),
236+
KUNIT_CASE(damon_test_regions),
237+
KUNIT_CASE(damon_test_aggregate),
238+
KUNIT_CASE(damon_test_split_at),
239+
KUNIT_CASE(damon_test_merge_two),
240+
KUNIT_CASE(damon_test_merge_regions_of),
241+
KUNIT_CASE(damon_test_split_regions_of),
242+
{},
243+
};
244+
245+
static struct kunit_suite damon_test_suite = {
246+
.name = "damon",
247+
.test_cases = damon_test_cases,
248+
};
249+
kunit_test_suite(damon_test_suite);
250+
251+
#endif /* _DAMON_CORE_TEST_H */
252+
253+
#endif /* CONFIG_DAMON_KUNIT_TEST */

mm/damon/core.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@
1616
#define CREATE_TRACE_POINTS
1717
#include <trace/events/damon.h>
1818

19+
#ifdef CONFIG_DAMON_KUNIT_TEST
20+
#undef DAMON_MIN_REGION
21+
#define DAMON_MIN_REGION 1
22+
#endif
23+
1924
/* Get a random number in [l, r) */
2025
#define damon_rand(l, r) (l + prandom_u32_max(r - l))
2126

@@ -711,3 +716,5 @@ static int kdamond_fn(void *data)
711716

712717
do_exit(0);
713718
}
719+
720+
#include "core-test.h"

0 commit comments

Comments
 (0)