Skip to content

Commit

Permalink
mm/damon: add kunit tests
Browse files Browse the repository at this point in the history
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/20210716081449.22187-12-sj38.park@gmail.com
Signed-off-by: SeongJae Park <sjpark@amazon.de>
Reviewed-by: Brendan Higgins <brendanhiggins@google.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Amit Shah <amit@kernel.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: David Hildenbrand <david@redhat.com>
Cc: David Rientjes <rientjes@google.com>
Cc: David Woodhouse <dwmw@amazon.com>
Cc: Fan Du <fan.du@intel.com>
Cc: Fernand Sieber <sieberf@amazon.com>
Cc: Greg Kroah-Hartman <greg@kroah.com>
Cc: Greg Thelen <gthelen@google.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Joe Perches <joe@perches.com>
Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Leonard Foerster <foersleo@amazon.de>
Cc: Marco Elver <elver@google.com>
Cc: Markus Boehme <markubo@amazon.de>
Cc: Maximilian Heyne <mheyne@amazon.de>
Cc: Mel Gorman <mgorman@suse.de>
Cc: Minchan Kim <minchan@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Rik van Riel <riel@surriel.com>
Cc: Shakeel Butt <shakeelb@google.com>
Cc: Shuah Khan <shuah@kernel.org>
Cc: Steven Rostedt (VMware) <rostedt@goodmis.org>
Cc: Vladimir Davydov <vdavydov.dev@gmail.com>
Cc: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
SeongJae Park authored and Linus Torvalds committed Sep 8, 2021
1 parent c4ba601 commit 17ccae8
Show file tree
Hide file tree
Showing 7 changed files with 760 additions and 0 deletions.
36 changes: 36 additions & 0 deletions mm/damon/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,18 @@ config DAMON
See https://damonitor.github.io/doc/html/latest-damon/index.html for
more information.

config DAMON_KUNIT_TEST
bool "Test for damon" if !KUNIT_ALL_TESTS
depends on DAMON && KUNIT=y
default KUNIT_ALL_TESTS
help
This builds the DAMON Kunit test suite.

For more information on KUnit and unit tests in general, please refer
to the KUnit documentation.

If unsure, say N.

config DAMON_VADDR
bool "Data access monitoring primitives for virtual address spaces"
depends on DAMON && MMU
Expand All @@ -20,6 +32,18 @@ config DAMON_VADDR
This builds the default data access monitoring primitives for DAMON
that works for virtual address spaces.

config DAMON_VADDR_KUNIT_TEST
bool "Test for DAMON primitives" if !KUNIT_ALL_TESTS
depends on DAMON_VADDR && KUNIT=y
default KUNIT_ALL_TESTS
help
This builds the DAMON virtual addresses primitives Kunit test suite.

For more information on KUnit and unit tests in general, please refer
to the KUnit documentation.

If unsure, say N.

config DAMON_DBGFS
bool "DAMON debugfs interface"
depends on DAMON_VADDR && DEBUG_FS
Expand All @@ -29,4 +53,16 @@ config DAMON_DBGFS

If unsure, say N.

config DAMON_DBGFS_KUNIT_TEST
bool "Test for damon debugfs interface" if !KUNIT_ALL_TESTS
depends on DAMON_DBGFS && KUNIT=y
default KUNIT_ALL_TESTS
help
This builds the DAMON debugfs interface Kunit test suite.

For more information on KUnit and unit tests in general, please refer
to the KUnit documentation.

If unsure, say N.

endmenu
253 changes: 253 additions & 0 deletions mm/damon/core-test.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Data Access Monitor Unit Tests
*
* Copyright 2019 Amazon.com, Inc. or its affiliates. All rights reserved.
*
* Author: SeongJae Park <sjpark@amazon.de>
*/

#ifdef CONFIG_DAMON_KUNIT_TEST

#ifndef _DAMON_CORE_TEST_H
#define _DAMON_CORE_TEST_H

#include <kunit/test.h>

static void damon_test_regions(struct kunit *test)
{
struct damon_region *r;
struct damon_target *t;

r = damon_new_region(1, 2);
KUNIT_EXPECT_EQ(test, 1ul, r->ar.start);
KUNIT_EXPECT_EQ(test, 2ul, r->ar.end);
KUNIT_EXPECT_EQ(test, 0u, r->nr_accesses);

t = damon_new_target(42);
KUNIT_EXPECT_EQ(test, 0u, damon_nr_regions(t));

damon_add_region(r, t);
KUNIT_EXPECT_EQ(test, 1u, damon_nr_regions(t));

damon_del_region(r, t);
KUNIT_EXPECT_EQ(test, 0u, damon_nr_regions(t));

damon_free_target(t);
}

static unsigned int nr_damon_targets(struct damon_ctx *ctx)
{
struct damon_target *t;
unsigned int nr_targets = 0;

damon_for_each_target(t, ctx)
nr_targets++;

return nr_targets;
}

static void damon_test_target(struct kunit *test)
{
struct damon_ctx *c = damon_new_ctx();
struct damon_target *t;

t = damon_new_target(42);
KUNIT_EXPECT_EQ(test, 42ul, t->id);
KUNIT_EXPECT_EQ(test, 0u, nr_damon_targets(c));

damon_add_target(c, t);
KUNIT_EXPECT_EQ(test, 1u, nr_damon_targets(c));

damon_destroy_target(t);
KUNIT_EXPECT_EQ(test, 0u, nr_damon_targets(c));

damon_destroy_ctx(c);
}

/*
* Test kdamond_reset_aggregated()
*
* DAMON checks access to each region and aggregates this information as the
* access frequency of each region. In detail, it increases '->nr_accesses' of
* regions that an access has confirmed. 'kdamond_reset_aggregated()' flushes
* the aggregated information ('->nr_accesses' of each regions) to the result
* buffer. As a result of the flushing, the '->nr_accesses' of regions are
* initialized to zero.
*/
static void damon_test_aggregate(struct kunit *test)
{
struct damon_ctx *ctx = damon_new_ctx();
unsigned long target_ids[] = {1, 2, 3};
unsigned long saddr[][3] = {{10, 20, 30}, {5, 42, 49}, {13, 33, 55} };
unsigned long eaddr[][3] = {{15, 27, 40}, {31, 45, 55}, {23, 44, 66} };
unsigned long accesses[][3] = {{42, 95, 84}, {10, 20, 30}, {0, 1, 2} };
struct damon_target *t;
struct damon_region *r;
int it, ir;

damon_set_targets(ctx, target_ids, 3);

it = 0;
damon_for_each_target(t, ctx) {
for (ir = 0; ir < 3; ir++) {
r = damon_new_region(saddr[it][ir], eaddr[it][ir]);
r->nr_accesses = accesses[it][ir];
damon_add_region(r, t);
}
it++;
}
kdamond_reset_aggregated(ctx);
it = 0;
damon_for_each_target(t, ctx) {
ir = 0;
/* '->nr_accesses' should be zeroed */
damon_for_each_region(r, t) {
KUNIT_EXPECT_EQ(test, 0u, r->nr_accesses);
ir++;
}
/* regions should be preserved */
KUNIT_EXPECT_EQ(test, 3, ir);
it++;
}
/* targets also should be preserved */
KUNIT_EXPECT_EQ(test, 3, it);

damon_destroy_ctx(ctx);
}

static void damon_test_split_at(struct kunit *test)
{
struct damon_ctx *c = damon_new_ctx();
struct damon_target *t;
struct damon_region *r;

t = damon_new_target(42);
r = damon_new_region(0, 100);
damon_add_region(r, t);
damon_split_region_at(c, t, r, 25);
KUNIT_EXPECT_EQ(test, r->ar.start, 0ul);
KUNIT_EXPECT_EQ(test, r->ar.end, 25ul);

r = damon_next_region(r);
KUNIT_EXPECT_EQ(test, r->ar.start, 25ul);
KUNIT_EXPECT_EQ(test, r->ar.end, 100ul);

damon_free_target(t);
damon_destroy_ctx(c);
}

static void damon_test_merge_two(struct kunit *test)
{
struct damon_target *t;
struct damon_region *r, *r2, *r3;
int i;

t = damon_new_target(42);
r = damon_new_region(0, 100);
r->nr_accesses = 10;
damon_add_region(r, t);
r2 = damon_new_region(100, 300);
r2->nr_accesses = 20;
damon_add_region(r2, t);

damon_merge_two_regions(t, r, r2);
KUNIT_EXPECT_EQ(test, r->ar.start, 0ul);
KUNIT_EXPECT_EQ(test, r->ar.end, 300ul);
KUNIT_EXPECT_EQ(test, r->nr_accesses, 16u);

i = 0;
damon_for_each_region(r3, t) {
KUNIT_EXPECT_PTR_EQ(test, r, r3);
i++;
}
KUNIT_EXPECT_EQ(test, i, 1);

damon_free_target(t);
}

static struct damon_region *__nth_region_of(struct damon_target *t, int idx)
{
struct damon_region *r;
unsigned int i = 0;

damon_for_each_region(r, t) {
if (i++ == idx)
return r;
}

return NULL;
}

static void damon_test_merge_regions_of(struct kunit *test)
{
struct damon_target *t;
struct damon_region *r;
unsigned long sa[] = {0, 100, 114, 122, 130, 156, 170, 184};
unsigned long ea[] = {100, 112, 122, 130, 156, 170, 184, 230};
unsigned int nrs[] = {0, 0, 10, 10, 20, 30, 1, 2};

unsigned long saddrs[] = {0, 114, 130, 156, 170};
unsigned long eaddrs[] = {112, 130, 156, 170, 230};
int i;

t = damon_new_target(42);
for (i = 0; i < ARRAY_SIZE(sa); i++) {
r = damon_new_region(sa[i], ea[i]);
r->nr_accesses = nrs[i];
damon_add_region(r, t);
}

damon_merge_regions_of(t, 9, 9999);
/* 0-112, 114-130, 130-156, 156-170 */
KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 5u);
for (i = 0; i < 5; i++) {
r = __nth_region_of(t, i);
KUNIT_EXPECT_EQ(test, r->ar.start, saddrs[i]);
KUNIT_EXPECT_EQ(test, r->ar.end, eaddrs[i]);
}
damon_free_target(t);
}

static void damon_test_split_regions_of(struct kunit *test)
{
struct damon_ctx *c = damon_new_ctx();
struct damon_target *t;
struct damon_region *r;

t = damon_new_target(42);
r = damon_new_region(0, 22);
damon_add_region(r, t);
damon_split_regions_of(c, t, 2);
KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 2u);
damon_free_target(t);

t = damon_new_target(42);
r = damon_new_region(0, 220);
damon_add_region(r, t);
damon_split_regions_of(c, t, 4);
KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 4u);
damon_free_target(t);
damon_destroy_ctx(c);
}

static struct kunit_case damon_test_cases[] = {
KUNIT_CASE(damon_test_target),
KUNIT_CASE(damon_test_regions),
KUNIT_CASE(damon_test_aggregate),
KUNIT_CASE(damon_test_split_at),
KUNIT_CASE(damon_test_merge_two),
KUNIT_CASE(damon_test_merge_regions_of),
KUNIT_CASE(damon_test_split_regions_of),
{},
};

static struct kunit_suite damon_test_suite = {
.name = "damon",
.test_cases = damon_test_cases,
};
kunit_test_suite(damon_test_suite);

#endif /* _DAMON_CORE_TEST_H */

#endif /* CONFIG_DAMON_KUNIT_TEST */
7 changes: 7 additions & 0 deletions mm/damon/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
#define CREATE_TRACE_POINTS
#include <trace/events/damon.h>

#ifdef CONFIG_DAMON_KUNIT_TEST
#undef DAMON_MIN_REGION
#define DAMON_MIN_REGION 1
#endif

/* Get a random number in [l, r) */
#define damon_rand(l, r) (l + prandom_u32_max(r - l))

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

do_exit(0);
}

#include "core-test.h"
Loading

0 comments on commit 17ccae8

Please sign in to comment.