117ccae8bSSeongJae Park /* SPDX-License-Identifier: GPL-2.0 */ 217ccae8bSSeongJae Park /* 317ccae8bSSeongJae Park * Data Access Monitor Unit Tests 417ccae8bSSeongJae Park * 517ccae8bSSeongJae Park * Copyright 2019 Amazon.com, Inc. or its affiliates. All rights reserved. 617ccae8bSSeongJae Park * 717ccae8bSSeongJae Park * Author: SeongJae Park <sjpark@amazon.de> 817ccae8bSSeongJae Park */ 917ccae8bSSeongJae Park 1017ccae8bSSeongJae Park #ifdef CONFIG_DAMON_VADDR_KUNIT_TEST 1117ccae8bSSeongJae Park 1217ccae8bSSeongJae Park #ifndef _DAMON_VADDR_TEST_H 1317ccae8bSSeongJae Park #define _DAMON_VADDR_TEST_H 1417ccae8bSSeongJae Park 1517ccae8bSSeongJae Park #include <kunit/test.h> 1617ccae8bSSeongJae Park 1734403fa5SLiam R. Howlett static int __link_vmas(struct maple_tree *mt, struct vm_area_struct *vmas, 18d0cf3dd4SLiam R. Howlett ssize_t nr_vmas) 1917ccae8bSSeongJae Park { 2034403fa5SLiam R. Howlett int i, ret = -ENOMEM; 21d0cf3dd4SLiam R. Howlett MA_STATE(mas, mt, 0, 0); 2217ccae8bSSeongJae Park 2317ccae8bSSeongJae Park if (!nr_vmas) 2434403fa5SLiam R. Howlett return 0; 2517ccae8bSSeongJae Park 26d0cf3dd4SLiam R. Howlett mas_lock(&mas); 2734403fa5SLiam R. Howlett for (i = 0; i < nr_vmas; i++) { 2834403fa5SLiam R. Howlett mas_set_range(&mas, vmas[i].vm_start, vmas[i].vm_end - 1); 2934403fa5SLiam R. Howlett if (mas_store_gfp(&mas, &vmas[i], GFP_KERNEL)) 3034403fa5SLiam R. Howlett goto failed; 3134403fa5SLiam R. Howlett } 3234403fa5SLiam R. Howlett 3334403fa5SLiam R. Howlett ret = 0; 3434403fa5SLiam R. Howlett failed: 35d0cf3dd4SLiam R. Howlett mas_unlock(&mas); 3634403fa5SLiam R. Howlett return ret; 3717ccae8bSSeongJae Park } 3817ccae8bSSeongJae Park 3917ccae8bSSeongJae Park /* 4017ccae8bSSeongJae Park * Test __damon_va_three_regions() function 4117ccae8bSSeongJae Park * 4217ccae8bSSeongJae Park * In case of virtual memory address spaces monitoring, DAMON converts the 4317ccae8bSSeongJae Park * complex and dynamic memory mappings of each target task to three 4417ccae8bSSeongJae Park * discontiguous regions which cover every mapped areas. However, the three 4517ccae8bSSeongJae Park * regions should not include the two biggest unmapped areas in the original 4617ccae8bSSeongJae Park * mapping, because the two biggest areas are normally the areas between 1) 4717ccae8bSSeongJae Park * heap and the mmap()-ed regions, and 2) the mmap()-ed regions and stack. 4817ccae8bSSeongJae Park * Because these two unmapped areas are very huge but obviously never accessed, 4917ccae8bSSeongJae Park * covering the region is just a waste. 5017ccae8bSSeongJae Park * 5117ccae8bSSeongJae Park * '__damon_va_three_regions() receives an address space of a process. It 5217ccae8bSSeongJae Park * first identifies the start of mappings, end of mappings, and the two biggest 5317ccae8bSSeongJae Park * unmapped areas. After that, based on the information, it constructs the 5417ccae8bSSeongJae Park * three regions and returns. For more detail, refer to the comment of 5517ccae8bSSeongJae Park * 'damon_init_regions_of()' function definition in 'mm/damon.c' file. 5617ccae8bSSeongJae Park * 5717ccae8bSSeongJae Park * For example, suppose virtual address ranges of 10-20, 20-25, 200-210, 5817ccae8bSSeongJae Park * 210-220, 300-305, and 307-330 (Other comments represent this mappings in 5917ccae8bSSeongJae Park * more short form: 10-20-25, 200-210-220, 300-305, 307-330) of a process are 6017ccae8bSSeongJae Park * mapped. To cover every mappings, the three regions should start with 10, 6117ccae8bSSeongJae Park * and end with 305. The process also has three unmapped areas, 25-200, 6217ccae8bSSeongJae Park * 220-300, and 305-307. Among those, 25-200 and 220-300 are the biggest two 6317ccae8bSSeongJae Park * unmapped areas, and thus it should be converted to three regions of 10-25, 6417ccae8bSSeongJae Park * 200-220, and 300-330. 6517ccae8bSSeongJae Park */ 6617ccae8bSSeongJae Park static void damon_test_three_regions_in_vmas(struct kunit *test) 6717ccae8bSSeongJae Park { 68d0cf3dd4SLiam R. Howlett static struct mm_struct mm; 6917ccae8bSSeongJae Park struct damon_addr_range regions[3] = {0,}; 7017ccae8bSSeongJae Park /* 10-20-25, 200-210-220, 300-305, 307-330 */ 7117ccae8bSSeongJae Park struct vm_area_struct vmas[] = { 7217ccae8bSSeongJae Park (struct vm_area_struct) {.vm_start = 10, .vm_end = 20}, 7317ccae8bSSeongJae Park (struct vm_area_struct) {.vm_start = 20, .vm_end = 25}, 7417ccae8bSSeongJae Park (struct vm_area_struct) {.vm_start = 200, .vm_end = 210}, 7517ccae8bSSeongJae Park (struct vm_area_struct) {.vm_start = 210, .vm_end = 220}, 7617ccae8bSSeongJae Park (struct vm_area_struct) {.vm_start = 300, .vm_end = 305}, 7717ccae8bSSeongJae Park (struct vm_area_struct) {.vm_start = 307, .vm_end = 330}, 7817ccae8bSSeongJae Park }; 7917ccae8bSSeongJae Park 80d0cf3dd4SLiam R. Howlett mt_init_flags(&mm.mm_mt, MM_MT_FLAGS); 8134403fa5SLiam R. Howlett if (__link_vmas(&mm.mm_mt, vmas, ARRAY_SIZE(vmas))) 8234403fa5SLiam R. Howlett kunit_skip(test, "Failed to create VMA tree"); 8317ccae8bSSeongJae Park 84d0cf3dd4SLiam R. Howlett __damon_va_three_regions(&mm, regions); 8517ccae8bSSeongJae Park 8617ccae8bSSeongJae Park KUNIT_EXPECT_EQ(test, 10ul, regions[0].start); 8717ccae8bSSeongJae Park KUNIT_EXPECT_EQ(test, 25ul, regions[0].end); 8817ccae8bSSeongJae Park KUNIT_EXPECT_EQ(test, 200ul, regions[1].start); 8917ccae8bSSeongJae Park KUNIT_EXPECT_EQ(test, 220ul, regions[1].end); 9017ccae8bSSeongJae Park KUNIT_EXPECT_EQ(test, 300ul, regions[2].start); 9117ccae8bSSeongJae Park KUNIT_EXPECT_EQ(test, 330ul, regions[2].end); 9217ccae8bSSeongJae Park } 9317ccae8bSSeongJae Park 9417ccae8bSSeongJae Park static struct damon_region *__nth_region_of(struct damon_target *t, int idx) 9517ccae8bSSeongJae Park { 9617ccae8bSSeongJae Park struct damon_region *r; 9717ccae8bSSeongJae Park unsigned int i = 0; 9817ccae8bSSeongJae Park 9917ccae8bSSeongJae Park damon_for_each_region(r, t) { 10017ccae8bSSeongJae Park if (i++ == idx) 10117ccae8bSSeongJae Park return r; 10217ccae8bSSeongJae Park } 10317ccae8bSSeongJae Park 10417ccae8bSSeongJae Park return NULL; 10517ccae8bSSeongJae Park } 10617ccae8bSSeongJae Park 10717ccae8bSSeongJae Park /* 108dae0087aSSeongJae Park * Test 'damon_set_regions()' 10917ccae8bSSeongJae Park * 11017ccae8bSSeongJae Park * test kunit object 11117ccae8bSSeongJae Park * regions an array containing start/end addresses of current 11217ccae8bSSeongJae Park * monitoring target regions 11317ccae8bSSeongJae Park * nr_regions the number of the addresses in 'regions' 11417ccae8bSSeongJae Park * three_regions The three regions that need to be applied now 11517ccae8bSSeongJae Park * expected start/end addresses of monitoring target regions that 11617ccae8bSSeongJae Park * 'three_regions' are applied 11717ccae8bSSeongJae Park * nr_expected the number of addresses in 'expected' 11817ccae8bSSeongJae Park * 11917ccae8bSSeongJae Park * The memory mapping of the target processes changes dynamically. To follow 12017ccae8bSSeongJae Park * the change, DAMON periodically reads the mappings, simplifies it to the 12117ccae8bSSeongJae Park * three regions, and updates the monitoring target regions to fit in the three 12217ccae8bSSeongJae Park * regions. The update of current target regions is the role of 123dae0087aSSeongJae Park * 'damon_set_regions()'. 12417ccae8bSSeongJae Park * 12517ccae8bSSeongJae Park * This test passes the given target regions and the new three regions that 12617ccae8bSSeongJae Park * need to be applied to the function and check whether it updates the regions 12717ccae8bSSeongJae Park * as expected. 12817ccae8bSSeongJae Park */ 12917ccae8bSSeongJae Park static void damon_do_test_apply_three_regions(struct kunit *test, 13017ccae8bSSeongJae Park unsigned long *regions, int nr_regions, 13117ccae8bSSeongJae Park struct damon_addr_range *three_regions, 13217ccae8bSSeongJae Park unsigned long *expected, int nr_expected) 13317ccae8bSSeongJae Park { 13417ccae8bSSeongJae Park struct damon_target *t; 13517ccae8bSSeongJae Park struct damon_region *r; 13617ccae8bSSeongJae Park int i; 13717ccae8bSSeongJae Park 1381971bd63SSeongJae Park t = damon_new_target(); 13917ccae8bSSeongJae Park for (i = 0; i < nr_regions / 2; i++) { 14017ccae8bSSeongJae Park r = damon_new_region(regions[i * 2], regions[i * 2 + 1]); 14117ccae8bSSeongJae Park damon_add_region(r, t); 14217ccae8bSSeongJae Park } 14317ccae8bSSeongJae Park 144dae0087aSSeongJae Park damon_set_regions(t, three_regions, 3); 14517ccae8bSSeongJae Park 14617ccae8bSSeongJae Park for (i = 0; i < nr_expected / 2; i++) { 14717ccae8bSSeongJae Park r = __nth_region_of(t, i); 14817ccae8bSSeongJae Park KUNIT_EXPECT_EQ(test, r->ar.start, expected[i * 2]); 14917ccae8bSSeongJae Park KUNIT_EXPECT_EQ(test, r->ar.end, expected[i * 2 + 1]); 15017ccae8bSSeongJae Park } 151*45120b15SJinjie Ruan 152*45120b15SJinjie Ruan damon_destroy_target(t); 15317ccae8bSSeongJae Park } 15417ccae8bSSeongJae Park 15517ccae8bSSeongJae Park /* 15617ccae8bSSeongJae Park * This function test most common case where the three big regions are only 15717ccae8bSSeongJae Park * slightly changed. Target regions should adjust their boundary (10-20-30, 15817ccae8bSSeongJae Park * 50-55, 70-80, 90-100) to fit with the new big regions or remove target 15917ccae8bSSeongJae Park * regions (57-79) that now out of the three regions. 16017ccae8bSSeongJae Park */ 16117ccae8bSSeongJae Park static void damon_test_apply_three_regions1(struct kunit *test) 16217ccae8bSSeongJae Park { 16317ccae8bSSeongJae Park /* 10-20-30, 50-55-57-59, 70-80-90-100 */ 16417ccae8bSSeongJae Park unsigned long regions[] = {10, 20, 20, 30, 50, 55, 55, 57, 57, 59, 16517ccae8bSSeongJae Park 70, 80, 80, 90, 90, 100}; 16617ccae8bSSeongJae Park /* 5-27, 45-55, 73-104 */ 16717ccae8bSSeongJae Park struct damon_addr_range new_three_regions[3] = { 16817ccae8bSSeongJae Park (struct damon_addr_range){.start = 5, .end = 27}, 16917ccae8bSSeongJae Park (struct damon_addr_range){.start = 45, .end = 55}, 17017ccae8bSSeongJae Park (struct damon_addr_range){.start = 73, .end = 104} }; 17117ccae8bSSeongJae Park /* 5-20-27, 45-55, 73-80-90-104 */ 17217ccae8bSSeongJae Park unsigned long expected[] = {5, 20, 20, 27, 45, 55, 17317ccae8bSSeongJae Park 73, 80, 80, 90, 90, 104}; 17417ccae8bSSeongJae Park 17517ccae8bSSeongJae Park damon_do_test_apply_three_regions(test, regions, ARRAY_SIZE(regions), 17617ccae8bSSeongJae Park new_three_regions, expected, ARRAY_SIZE(expected)); 17717ccae8bSSeongJae Park } 17817ccae8bSSeongJae Park 17917ccae8bSSeongJae Park /* 18017ccae8bSSeongJae Park * Test slightly bigger change. Similar to above, but the second big region 18117ccae8bSSeongJae Park * now require two target regions (50-55, 57-59) to be removed. 18217ccae8bSSeongJae Park */ 18317ccae8bSSeongJae Park static void damon_test_apply_three_regions2(struct kunit *test) 18417ccae8bSSeongJae Park { 18517ccae8bSSeongJae Park /* 10-20-30, 50-55-57-59, 70-80-90-100 */ 18617ccae8bSSeongJae Park unsigned long regions[] = {10, 20, 20, 30, 50, 55, 55, 57, 57, 59, 18717ccae8bSSeongJae Park 70, 80, 80, 90, 90, 100}; 18817ccae8bSSeongJae Park /* 5-27, 56-57, 65-104 */ 18917ccae8bSSeongJae Park struct damon_addr_range new_three_regions[3] = { 19017ccae8bSSeongJae Park (struct damon_addr_range){.start = 5, .end = 27}, 19117ccae8bSSeongJae Park (struct damon_addr_range){.start = 56, .end = 57}, 19217ccae8bSSeongJae Park (struct damon_addr_range){.start = 65, .end = 104} }; 19317ccae8bSSeongJae Park /* 5-20-27, 56-57, 65-80-90-104 */ 19417ccae8bSSeongJae Park unsigned long expected[] = {5, 20, 20, 27, 56, 57, 19517ccae8bSSeongJae Park 65, 80, 80, 90, 90, 104}; 19617ccae8bSSeongJae Park 19717ccae8bSSeongJae Park damon_do_test_apply_three_regions(test, regions, ARRAY_SIZE(regions), 19817ccae8bSSeongJae Park new_three_regions, expected, ARRAY_SIZE(expected)); 19917ccae8bSSeongJae Park } 20017ccae8bSSeongJae Park 20117ccae8bSSeongJae Park /* 20217ccae8bSSeongJae Park * Test a big change. The second big region has totally freed and mapped to 20317ccae8bSSeongJae Park * different area (50-59 -> 61-63). The target regions which were in the old 20417ccae8bSSeongJae Park * second big region (50-55-57-59) should be removed and new target region 20517ccae8bSSeongJae Park * covering the second big region (61-63) should be created. 20617ccae8bSSeongJae Park */ 20717ccae8bSSeongJae Park static void damon_test_apply_three_regions3(struct kunit *test) 20817ccae8bSSeongJae Park { 20917ccae8bSSeongJae Park /* 10-20-30, 50-55-57-59, 70-80-90-100 */ 21017ccae8bSSeongJae Park unsigned long regions[] = {10, 20, 20, 30, 50, 55, 55, 57, 57, 59, 21117ccae8bSSeongJae Park 70, 80, 80, 90, 90, 100}; 21217ccae8bSSeongJae Park /* 5-27, 61-63, 65-104 */ 21317ccae8bSSeongJae Park struct damon_addr_range new_three_regions[3] = { 21417ccae8bSSeongJae Park (struct damon_addr_range){.start = 5, .end = 27}, 21517ccae8bSSeongJae Park (struct damon_addr_range){.start = 61, .end = 63}, 21617ccae8bSSeongJae Park (struct damon_addr_range){.start = 65, .end = 104} }; 21717ccae8bSSeongJae Park /* 5-20-27, 61-63, 65-80-90-104 */ 21817ccae8bSSeongJae Park unsigned long expected[] = {5, 20, 20, 27, 61, 63, 21917ccae8bSSeongJae Park 65, 80, 80, 90, 90, 104}; 22017ccae8bSSeongJae Park 22117ccae8bSSeongJae Park damon_do_test_apply_three_regions(test, regions, ARRAY_SIZE(regions), 22217ccae8bSSeongJae Park new_three_regions, expected, ARRAY_SIZE(expected)); 22317ccae8bSSeongJae Park } 22417ccae8bSSeongJae Park 22517ccae8bSSeongJae Park /* 22617ccae8bSSeongJae Park * Test another big change. Both of the second and third big regions (50-59 22717ccae8bSSeongJae Park * and 70-100) has totally freed and mapped to different area (30-32 and 22817ccae8bSSeongJae Park * 65-68). The target regions which were in the old second and third big 22917ccae8bSSeongJae Park * regions should now be removed and new target regions covering the new second 23001078655SColin Ian King * and third big regions should be created. 23117ccae8bSSeongJae Park */ 23217ccae8bSSeongJae Park static void damon_test_apply_three_regions4(struct kunit *test) 23317ccae8bSSeongJae Park { 23417ccae8bSSeongJae Park /* 10-20-30, 50-55-57-59, 70-80-90-100 */ 23517ccae8bSSeongJae Park unsigned long regions[] = {10, 20, 20, 30, 50, 55, 55, 57, 57, 59, 23617ccae8bSSeongJae Park 70, 80, 80, 90, 90, 100}; 23717ccae8bSSeongJae Park /* 5-7, 30-32, 65-68 */ 23817ccae8bSSeongJae Park struct damon_addr_range new_three_regions[3] = { 23917ccae8bSSeongJae Park (struct damon_addr_range){.start = 5, .end = 7}, 24017ccae8bSSeongJae Park (struct damon_addr_range){.start = 30, .end = 32}, 24117ccae8bSSeongJae Park (struct damon_addr_range){.start = 65, .end = 68} }; 24217ccae8bSSeongJae Park /* expect 5-7, 30-32, 65-68 */ 24317ccae8bSSeongJae Park unsigned long expected[] = {5, 7, 30, 32, 65, 68}; 24417ccae8bSSeongJae Park 24517ccae8bSSeongJae Park damon_do_test_apply_three_regions(test, regions, ARRAY_SIZE(regions), 24617ccae8bSSeongJae Park new_three_regions, expected, ARRAY_SIZE(expected)); 24717ccae8bSSeongJae Park } 24817ccae8bSSeongJae Park 249044cd975SSeongJae Park static void damon_test_split_evenly_fail(struct kunit *test, 250044cd975SSeongJae Park unsigned long start, unsigned long end, unsigned int nr_pieces) 251044cd975SSeongJae Park { 2521971bd63SSeongJae Park struct damon_target *t = damon_new_target(); 253044cd975SSeongJae Park struct damon_region *r = damon_new_region(start, end); 254044cd975SSeongJae Park 255044cd975SSeongJae Park damon_add_region(r, t); 256044cd975SSeongJae Park KUNIT_EXPECT_EQ(test, 257044cd975SSeongJae Park damon_va_evenly_split_region(t, r, nr_pieces), -EINVAL); 258044cd975SSeongJae Park KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 1u); 259044cd975SSeongJae Park 260044cd975SSeongJae Park damon_for_each_region(r, t) { 261044cd975SSeongJae Park KUNIT_EXPECT_EQ(test, r->ar.start, start); 262044cd975SSeongJae Park KUNIT_EXPECT_EQ(test, r->ar.end, end); 263044cd975SSeongJae Park } 264044cd975SSeongJae Park 265044cd975SSeongJae Park damon_free_target(t); 266044cd975SSeongJae Park } 267044cd975SSeongJae Park 268044cd975SSeongJae Park static void damon_test_split_evenly_succ(struct kunit *test, 269044cd975SSeongJae Park unsigned long start, unsigned long end, unsigned int nr_pieces) 270044cd975SSeongJae Park { 2711971bd63SSeongJae Park struct damon_target *t = damon_new_target(); 272044cd975SSeongJae Park struct damon_region *r = damon_new_region(start, end); 273044cd975SSeongJae Park unsigned long expected_width = (end - start) / nr_pieces; 274044cd975SSeongJae Park unsigned long i = 0; 275044cd975SSeongJae Park 276044cd975SSeongJae Park damon_add_region(r, t); 277044cd975SSeongJae Park KUNIT_EXPECT_EQ(test, 278044cd975SSeongJae Park damon_va_evenly_split_region(t, r, nr_pieces), 0); 279044cd975SSeongJae Park KUNIT_EXPECT_EQ(test, damon_nr_regions(t), nr_pieces); 280044cd975SSeongJae Park 281044cd975SSeongJae Park damon_for_each_region(r, t) { 2821f4910b3SXiaomeng Tong if (i == nr_pieces - 1) { 2831f4910b3SXiaomeng Tong KUNIT_EXPECT_EQ(test, 2841f4910b3SXiaomeng Tong r->ar.start, start + i * expected_width); 2851f4910b3SXiaomeng Tong KUNIT_EXPECT_EQ(test, r->ar.end, end); 286044cd975SSeongJae Park break; 2871f4910b3SXiaomeng Tong } 288044cd975SSeongJae Park KUNIT_EXPECT_EQ(test, 289044cd975SSeongJae Park r->ar.start, start + i++ * expected_width); 290044cd975SSeongJae Park KUNIT_EXPECT_EQ(test, r->ar.end, start + i * expected_width); 291044cd975SSeongJae Park } 292044cd975SSeongJae Park damon_free_target(t); 293044cd975SSeongJae Park } 294044cd975SSeongJae Park 29517ccae8bSSeongJae Park static void damon_test_split_evenly(struct kunit *test) 29617ccae8bSSeongJae Park { 29717ccae8bSSeongJae Park KUNIT_EXPECT_EQ(test, damon_va_evenly_split_region(NULL, NULL, 5), 29817ccae8bSSeongJae Park -EINVAL); 29917ccae8bSSeongJae Park 300044cd975SSeongJae Park damon_test_split_evenly_fail(test, 0, 100, 0); 301044cd975SSeongJae Park damon_test_split_evenly_succ(test, 0, 100, 10); 302044cd975SSeongJae Park damon_test_split_evenly_succ(test, 5, 59, 5); 303044cd975SSeongJae Park damon_test_split_evenly_fail(test, 5, 6, 2); 30417ccae8bSSeongJae Park } 30517ccae8bSSeongJae Park 30617ccae8bSSeongJae Park static struct kunit_case damon_test_cases[] = { 30717ccae8bSSeongJae Park KUNIT_CASE(damon_test_three_regions_in_vmas), 30817ccae8bSSeongJae Park KUNIT_CASE(damon_test_apply_three_regions1), 30917ccae8bSSeongJae Park KUNIT_CASE(damon_test_apply_three_regions2), 31017ccae8bSSeongJae Park KUNIT_CASE(damon_test_apply_three_regions3), 31117ccae8bSSeongJae Park KUNIT_CASE(damon_test_apply_three_regions4), 31217ccae8bSSeongJae Park KUNIT_CASE(damon_test_split_evenly), 31317ccae8bSSeongJae Park {}, 31417ccae8bSSeongJae Park }; 31517ccae8bSSeongJae Park 31617ccae8bSSeongJae Park static struct kunit_suite damon_test_suite = { 317f7d911c3SSeongJae Park .name = "damon-operations", 31817ccae8bSSeongJae Park .test_cases = damon_test_cases, 31917ccae8bSSeongJae Park }; 32017ccae8bSSeongJae Park kunit_test_suite(damon_test_suite); 32117ccae8bSSeongJae Park 32217ccae8bSSeongJae Park #endif /* _DAMON_VADDR_TEST_H */ 32317ccae8bSSeongJae Park 32417ccae8bSSeongJae Park #endif /* CONFIG_DAMON_VADDR_KUNIT_TEST */ 325