Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 /*
0003  * Data Access Monitor Unit Tests
0004  *
0005  * Copyright 2019 Amazon.com, Inc. or its affiliates.  All rights reserved.
0006  *
0007  * Author: SeongJae Park <sjpark@amazon.de>
0008  */
0009 
0010 #ifdef CONFIG_DAMON_VADDR_KUNIT_TEST
0011 
0012 #ifndef _DAMON_VADDR_TEST_H
0013 #define _DAMON_VADDR_TEST_H
0014 
0015 #include <kunit/test.h>
0016 
0017 static void __link_vmas(struct vm_area_struct *vmas, ssize_t nr_vmas)
0018 {
0019     int i, j;
0020     unsigned long largest_gap, gap;
0021 
0022     if (!nr_vmas)
0023         return;
0024 
0025     for (i = 0; i < nr_vmas - 1; i++) {
0026         vmas[i].vm_next = &vmas[i + 1];
0027 
0028         vmas[i].vm_rb.rb_left = NULL;
0029         vmas[i].vm_rb.rb_right = &vmas[i + 1].vm_rb;
0030 
0031         largest_gap = 0;
0032         for (j = i; j < nr_vmas; j++) {
0033             if (j == 0)
0034                 continue;
0035             gap = vmas[j].vm_start - vmas[j - 1].vm_end;
0036             if (gap > largest_gap)
0037                 largest_gap = gap;
0038         }
0039         vmas[i].rb_subtree_gap = largest_gap;
0040     }
0041     vmas[i].vm_next = NULL;
0042     vmas[i].vm_rb.rb_right = NULL;
0043     vmas[i].rb_subtree_gap = 0;
0044 }
0045 
0046 /*
0047  * Test __damon_va_three_regions() function
0048  *
0049  * In case of virtual memory address spaces monitoring, DAMON converts the
0050  * complex and dynamic memory mappings of each target task to three
0051  * discontiguous regions which cover every mapped areas.  However, the three
0052  * regions should not include the two biggest unmapped areas in the original
0053  * mapping, because the two biggest areas are normally the areas between 1)
0054  * heap and the mmap()-ed regions, and 2) the mmap()-ed regions and stack.
0055  * Because these two unmapped areas are very huge but obviously never accessed,
0056  * covering the region is just a waste.
0057  *
0058  * '__damon_va_three_regions() receives an address space of a process.  It
0059  * first identifies the start of mappings, end of mappings, and the two biggest
0060  * unmapped areas.  After that, based on the information, it constructs the
0061  * three regions and returns.  For more detail, refer to the comment of
0062  * 'damon_init_regions_of()' function definition in 'mm/damon.c' file.
0063  *
0064  * For example, suppose virtual address ranges of 10-20, 20-25, 200-210,
0065  * 210-220, 300-305, and 307-330 (Other comments represent this mappings in
0066  * more short form: 10-20-25, 200-210-220, 300-305, 307-330) of a process are
0067  * mapped.  To cover every mappings, the three regions should start with 10,
0068  * and end with 305.  The process also has three unmapped areas, 25-200,
0069  * 220-300, and 305-307.  Among those, 25-200 and 220-300 are the biggest two
0070  * unmapped areas, and thus it should be converted to three regions of 10-25,
0071  * 200-220, and 300-330.
0072  */
0073 static void damon_test_three_regions_in_vmas(struct kunit *test)
0074 {
0075     struct damon_addr_range regions[3] = {0,};
0076     /* 10-20-25, 200-210-220, 300-305, 307-330 */
0077     struct vm_area_struct vmas[] = {
0078         (struct vm_area_struct) {.vm_start = 10, .vm_end = 20},
0079         (struct vm_area_struct) {.vm_start = 20, .vm_end = 25},
0080         (struct vm_area_struct) {.vm_start = 200, .vm_end = 210},
0081         (struct vm_area_struct) {.vm_start = 210, .vm_end = 220},
0082         (struct vm_area_struct) {.vm_start = 300, .vm_end = 305},
0083         (struct vm_area_struct) {.vm_start = 307, .vm_end = 330},
0084     };
0085 
0086     __link_vmas(vmas, 6);
0087 
0088     __damon_va_three_regions(&vmas[0], regions);
0089 
0090     KUNIT_EXPECT_EQ(test, 10ul, regions[0].start);
0091     KUNIT_EXPECT_EQ(test, 25ul, regions[0].end);
0092     KUNIT_EXPECT_EQ(test, 200ul, regions[1].start);
0093     KUNIT_EXPECT_EQ(test, 220ul, regions[1].end);
0094     KUNIT_EXPECT_EQ(test, 300ul, regions[2].start);
0095     KUNIT_EXPECT_EQ(test, 330ul, regions[2].end);
0096 }
0097 
0098 static struct damon_region *__nth_region_of(struct damon_target *t, int idx)
0099 {
0100     struct damon_region *r;
0101     unsigned int i = 0;
0102 
0103     damon_for_each_region(r, t) {
0104         if (i++ == idx)
0105             return r;
0106     }
0107 
0108     return NULL;
0109 }
0110 
0111 /*
0112  * Test 'damon_set_regions()'
0113  *
0114  * test         kunit object
0115  * regions      an array containing start/end addresses of current
0116  *          monitoring target regions
0117  * nr_regions       the number of the addresses in 'regions'
0118  * three_regions    The three regions that need to be applied now
0119  * expected     start/end addresses of monitoring target regions that
0120  *          'three_regions' are applied
0121  * nr_expected      the number of addresses in 'expected'
0122  *
0123  * The memory mapping of the target processes changes dynamically.  To follow
0124  * the change, DAMON periodically reads the mappings, simplifies it to the
0125  * three regions, and updates the monitoring target regions to fit in the three
0126  * regions.  The update of current target regions is the role of
0127  * 'damon_set_regions()'.
0128  *
0129  * This test passes the given target regions and the new three regions that
0130  * need to be applied to the function and check whether it updates the regions
0131  * as expected.
0132  */
0133 static void damon_do_test_apply_three_regions(struct kunit *test,
0134                 unsigned long *regions, int nr_regions,
0135                 struct damon_addr_range *three_regions,
0136                 unsigned long *expected, int nr_expected)
0137 {
0138     struct damon_target *t;
0139     struct damon_region *r;
0140     int i;
0141 
0142     t = damon_new_target();
0143     for (i = 0; i < nr_regions / 2; i++) {
0144         r = damon_new_region(regions[i * 2], regions[i * 2 + 1]);
0145         damon_add_region(r, t);
0146     }
0147 
0148     damon_set_regions(t, three_regions, 3);
0149 
0150     for (i = 0; i < nr_expected / 2; i++) {
0151         r = __nth_region_of(t, i);
0152         KUNIT_EXPECT_EQ(test, r->ar.start, expected[i * 2]);
0153         KUNIT_EXPECT_EQ(test, r->ar.end, expected[i * 2 + 1]);
0154     }
0155 }
0156 
0157 /*
0158  * This function test most common case where the three big regions are only
0159  * slightly changed.  Target regions should adjust their boundary (10-20-30,
0160  * 50-55, 70-80, 90-100) to fit with the new big regions or remove target
0161  * regions (57-79) that now out of the three regions.
0162  */
0163 static void damon_test_apply_three_regions1(struct kunit *test)
0164 {
0165     /* 10-20-30, 50-55-57-59, 70-80-90-100 */
0166     unsigned long regions[] = {10, 20, 20, 30, 50, 55, 55, 57, 57, 59,
0167                 70, 80, 80, 90, 90, 100};
0168     /* 5-27, 45-55, 73-104 */
0169     struct damon_addr_range new_three_regions[3] = {
0170         (struct damon_addr_range){.start = 5, .end = 27},
0171         (struct damon_addr_range){.start = 45, .end = 55},
0172         (struct damon_addr_range){.start = 73, .end = 104} };
0173     /* 5-20-27, 45-55, 73-80-90-104 */
0174     unsigned long expected[] = {5, 20, 20, 27, 45, 55,
0175                 73, 80, 80, 90, 90, 104};
0176 
0177     damon_do_test_apply_three_regions(test, regions, ARRAY_SIZE(regions),
0178             new_three_regions, expected, ARRAY_SIZE(expected));
0179 }
0180 
0181 /*
0182  * Test slightly bigger change.  Similar to above, but the second big region
0183  * now require two target regions (50-55, 57-59) to be removed.
0184  */
0185 static void damon_test_apply_three_regions2(struct kunit *test)
0186 {
0187     /* 10-20-30, 50-55-57-59, 70-80-90-100 */
0188     unsigned long regions[] = {10, 20, 20, 30, 50, 55, 55, 57, 57, 59,
0189                 70, 80, 80, 90, 90, 100};
0190     /* 5-27, 56-57, 65-104 */
0191     struct damon_addr_range new_three_regions[3] = {
0192         (struct damon_addr_range){.start = 5, .end = 27},
0193         (struct damon_addr_range){.start = 56, .end = 57},
0194         (struct damon_addr_range){.start = 65, .end = 104} };
0195     /* 5-20-27, 56-57, 65-80-90-104 */
0196     unsigned long expected[] = {5, 20, 20, 27, 56, 57,
0197                 65, 80, 80, 90, 90, 104};
0198 
0199     damon_do_test_apply_three_regions(test, regions, ARRAY_SIZE(regions),
0200             new_three_regions, expected, ARRAY_SIZE(expected));
0201 }
0202 
0203 /*
0204  * Test a big change.  The second big region has totally freed and mapped to
0205  * different area (50-59 -> 61-63).  The target regions which were in the old
0206  * second big region (50-55-57-59) should be removed and new target region
0207  * covering the second big region (61-63) should be created.
0208  */
0209 static void damon_test_apply_three_regions3(struct kunit *test)
0210 {
0211     /* 10-20-30, 50-55-57-59, 70-80-90-100 */
0212     unsigned long regions[] = {10, 20, 20, 30, 50, 55, 55, 57, 57, 59,
0213                 70, 80, 80, 90, 90, 100};
0214     /* 5-27, 61-63, 65-104 */
0215     struct damon_addr_range new_three_regions[3] = {
0216         (struct damon_addr_range){.start = 5, .end = 27},
0217         (struct damon_addr_range){.start = 61, .end = 63},
0218         (struct damon_addr_range){.start = 65, .end = 104} };
0219     /* 5-20-27, 61-63, 65-80-90-104 */
0220     unsigned long expected[] = {5, 20, 20, 27, 61, 63,
0221                 65, 80, 80, 90, 90, 104};
0222 
0223     damon_do_test_apply_three_regions(test, regions, ARRAY_SIZE(regions),
0224             new_three_regions, expected, ARRAY_SIZE(expected));
0225 }
0226 
0227 /*
0228  * Test another big change.  Both of the second and third big regions (50-59
0229  * and 70-100) has totally freed and mapped to different area (30-32 and
0230  * 65-68).  The target regions which were in the old second and third big
0231  * regions should now be removed and new target regions covering the new second
0232  * and third big regions should be created.
0233  */
0234 static void damon_test_apply_three_regions4(struct kunit *test)
0235 {
0236     /* 10-20-30, 50-55-57-59, 70-80-90-100 */
0237     unsigned long regions[] = {10, 20, 20, 30, 50, 55, 55, 57, 57, 59,
0238                 70, 80, 80, 90, 90, 100};
0239     /* 5-7, 30-32, 65-68 */
0240     struct damon_addr_range new_three_regions[3] = {
0241         (struct damon_addr_range){.start = 5, .end = 7},
0242         (struct damon_addr_range){.start = 30, .end = 32},
0243         (struct damon_addr_range){.start = 65, .end = 68} };
0244     /* expect 5-7, 30-32, 65-68 */
0245     unsigned long expected[] = {5, 7, 30, 32, 65, 68};
0246 
0247     damon_do_test_apply_three_regions(test, regions, ARRAY_SIZE(regions),
0248             new_three_regions, expected, ARRAY_SIZE(expected));
0249 }
0250 
0251 static void damon_test_split_evenly_fail(struct kunit *test,
0252         unsigned long start, unsigned long end, unsigned int nr_pieces)
0253 {
0254     struct damon_target *t = damon_new_target();
0255     struct damon_region *r = damon_new_region(start, end);
0256 
0257     damon_add_region(r, t);
0258     KUNIT_EXPECT_EQ(test,
0259             damon_va_evenly_split_region(t, r, nr_pieces), -EINVAL);
0260     KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 1u);
0261 
0262     damon_for_each_region(r, t) {
0263         KUNIT_EXPECT_EQ(test, r->ar.start, start);
0264         KUNIT_EXPECT_EQ(test, r->ar.end, end);
0265     }
0266 
0267     damon_free_target(t);
0268 }
0269 
0270 static void damon_test_split_evenly_succ(struct kunit *test,
0271     unsigned long start, unsigned long end, unsigned int nr_pieces)
0272 {
0273     struct damon_target *t = damon_new_target();
0274     struct damon_region *r = damon_new_region(start, end);
0275     unsigned long expected_width = (end - start) / nr_pieces;
0276     unsigned long i = 0;
0277 
0278     damon_add_region(r, t);
0279     KUNIT_EXPECT_EQ(test,
0280             damon_va_evenly_split_region(t, r, nr_pieces), 0);
0281     KUNIT_EXPECT_EQ(test, damon_nr_regions(t), nr_pieces);
0282 
0283     damon_for_each_region(r, t) {
0284         if (i == nr_pieces - 1) {
0285             KUNIT_EXPECT_EQ(test,
0286                 r->ar.start, start + i * expected_width);
0287             KUNIT_EXPECT_EQ(test, r->ar.end, end);
0288             break;
0289         }
0290         KUNIT_EXPECT_EQ(test,
0291                 r->ar.start, start + i++ * expected_width);
0292         KUNIT_EXPECT_EQ(test, r->ar.end, start + i * expected_width);
0293     }
0294     damon_free_target(t);
0295 }
0296 
0297 static void damon_test_split_evenly(struct kunit *test)
0298 {
0299     KUNIT_EXPECT_EQ(test, damon_va_evenly_split_region(NULL, NULL, 5),
0300             -EINVAL);
0301 
0302     damon_test_split_evenly_fail(test, 0, 100, 0);
0303     damon_test_split_evenly_succ(test, 0, 100, 10);
0304     damon_test_split_evenly_succ(test, 5, 59, 5);
0305     damon_test_split_evenly_fail(test, 5, 6, 2);
0306 }
0307 
0308 static struct kunit_case damon_test_cases[] = {
0309     KUNIT_CASE(damon_test_three_regions_in_vmas),
0310     KUNIT_CASE(damon_test_apply_three_regions1),
0311     KUNIT_CASE(damon_test_apply_three_regions2),
0312     KUNIT_CASE(damon_test_apply_three_regions3),
0313     KUNIT_CASE(damon_test_apply_three_regions4),
0314     KUNIT_CASE(damon_test_split_evenly),
0315     {},
0316 };
0317 
0318 static struct kunit_suite damon_test_suite = {
0319     .name = "damon-operations",
0320     .test_cases = damon_test_cases,
0321 };
0322 kunit_test_suite(damon_test_suite);
0323 
0324 #endif /* _DAMON_VADDR_TEST_H */
0325 
0326 #endif  /* CONFIG_DAMON_VADDR_KUNIT_TEST */