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 <sj@kernel.org> 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 if (!r) 24 kunit_skip(test, "region alloc fail"); 25 KUNIT_EXPECT_EQ(test, 1ul, r->ar.start); 26 KUNIT_EXPECT_EQ(test, 2ul, r->ar.end); 27 KUNIT_EXPECT_EQ(test, 0u, r->nr_accesses); 28 29 t = damon_new_target(); 30 if (!t) { 31 damon_free_region(r); 32 kunit_skip(test, "target alloc fail"); 33 } 34 KUNIT_EXPECT_EQ(test, 0u, damon_nr_regions(t)); 35 36 damon_add_region(r, t); 37 KUNIT_EXPECT_EQ(test, 1u, damon_nr_regions(t)); 38 39 damon_destroy_region(r, t); 40 KUNIT_EXPECT_EQ(test, 0u, damon_nr_regions(t)); 41 42 damon_free_target(t); 43 } 44 45 static unsigned int nr_damon_targets(struct damon_ctx *ctx) 46 { 47 struct damon_target *t; 48 unsigned int nr_targets = 0; 49 50 damon_for_each_target(t, ctx) 51 nr_targets++; 52 53 return nr_targets; 54 } 55 56 static void damon_test_target(struct kunit *test) 57 { 58 struct damon_ctx *c = damon_new_ctx(); 59 struct damon_target *t; 60 61 if (!c) 62 kunit_skip(test, "ctx alloc fail"); 63 64 t = damon_new_target(); 65 if (!t) { 66 damon_destroy_ctx(c); 67 kunit_skip(test, "target alloc fail"); 68 } 69 KUNIT_EXPECT_EQ(test, 0u, nr_damon_targets(c)); 70 71 damon_add_target(c, t); 72 KUNIT_EXPECT_EQ(test, 1u, nr_damon_targets(c)); 73 74 damon_destroy_target(t, c); 75 KUNIT_EXPECT_EQ(test, 0u, nr_damon_targets(c)); 76 77 damon_destroy_ctx(c); 78 } 79 80 /* 81 * Test kdamond_reset_aggregated() 82 * 83 * DAMON checks access to each region and aggregates this information as the 84 * access frequency of each region. In detail, it increases '->nr_accesses' of 85 * regions that an access has confirmed. 'kdamond_reset_aggregated()' flushes 86 * the aggregated information ('->nr_accesses' of each regions) to the result 87 * buffer. As a result of the flushing, the '->nr_accesses' of regions are 88 * initialized to zero. 89 */ 90 static void damon_test_aggregate(struct kunit *test) 91 { 92 struct damon_ctx *ctx = damon_new_ctx(); 93 unsigned long saddr[][3] = {{10, 20, 30}, {5, 42, 49}, {13, 33, 55} }; 94 unsigned long eaddr[][3] = {{15, 27, 40}, {31, 45, 55}, {23, 44, 66} }; 95 unsigned long accesses[][3] = {{42, 95, 84}, {10, 20, 30}, {0, 1, 2} }; 96 struct damon_target *t; 97 struct damon_region *r; 98 int it, ir; 99 100 if (!ctx) 101 kunit_skip(test, "ctx alloc fail"); 102 103 for (it = 0; it < 3; it++) { 104 t = damon_new_target(); 105 if (!t) { 106 damon_destroy_ctx(ctx); 107 kunit_skip(test, "target alloc fail"); 108 } 109 damon_add_target(ctx, t); 110 } 111 112 it = 0; 113 damon_for_each_target(t, ctx) { 114 for (ir = 0; ir < 3; ir++) { 115 r = damon_new_region(saddr[it][ir], eaddr[it][ir]); 116 if (!r) { 117 damon_destroy_ctx(ctx); 118 kunit_skip(test, "region alloc fail"); 119 } 120 r->nr_accesses = accesses[it][ir]; 121 r->nr_accesses_bp = accesses[it][ir] * 10000; 122 damon_add_region(r, t); 123 } 124 it++; 125 } 126 kdamond_reset_aggregated(ctx); 127 it = 0; 128 damon_for_each_target(t, ctx) { 129 ir = 0; 130 /* '->nr_accesses' should be zeroed */ 131 damon_for_each_region(r, t) { 132 KUNIT_EXPECT_EQ(test, 0u, r->nr_accesses); 133 ir++; 134 } 135 /* regions should be preserved */ 136 KUNIT_EXPECT_EQ(test, 3, ir); 137 it++; 138 } 139 /* targets also should be preserved */ 140 KUNIT_EXPECT_EQ(test, 3, it); 141 142 damon_destroy_ctx(ctx); 143 } 144 145 static void damon_test_split_at(struct kunit *test) 146 { 147 struct damon_target *t; 148 struct damon_region *r, *r_new; 149 150 t = damon_new_target(); 151 if (!t) 152 kunit_skip(test, "target alloc fail"); 153 r = damon_new_region(0, 100); 154 if (!r) { 155 damon_free_target(t); 156 kunit_skip(test, "region alloc fail"); 157 } 158 r->nr_accesses_bp = 420000; 159 r->nr_accesses = 42; 160 r->last_nr_accesses = 15; 161 r->age = 10; 162 damon_add_region(r, t); 163 damon_split_region_at(t, r, 25); 164 KUNIT_EXPECT_EQ(test, r->ar.start, 0ul); 165 KUNIT_EXPECT_EQ(test, r->ar.end, 25ul); 166 167 r_new = damon_next_region(r); 168 KUNIT_EXPECT_EQ(test, r_new->ar.start, 25ul); 169 KUNIT_EXPECT_EQ(test, r_new->ar.end, 100ul); 170 171 KUNIT_EXPECT_EQ(test, r->nr_accesses_bp, r_new->nr_accesses_bp); 172 KUNIT_EXPECT_EQ(test, r->nr_accesses, r_new->nr_accesses); 173 KUNIT_EXPECT_EQ(test, r->last_nr_accesses, r_new->last_nr_accesses); 174 KUNIT_EXPECT_EQ(test, r->age, r_new->age); 175 176 damon_free_target(t); 177 } 178 179 static void damon_test_merge_two(struct kunit *test) 180 { 181 struct damon_target *t; 182 struct damon_region *r, *r2, *r3; 183 int i; 184 185 t = damon_new_target(); 186 if (!t) 187 kunit_skip(test, "target alloc fail"); 188 r = damon_new_region(0, 100); 189 if (!r) { 190 damon_free_target(t); 191 kunit_skip(test, "region alloc fail"); 192 } 193 r->nr_accesses = 10; 194 r->nr_accesses_bp = 100000; 195 r->age = 9; 196 damon_add_region(r, t); 197 r2 = damon_new_region(100, 300); 198 if (!r2) { 199 damon_free_target(t); 200 kunit_skip(test, "second region alloc fail"); 201 } 202 r2->nr_accesses = 20; 203 r2->nr_accesses_bp = 200000; 204 r2->age = 21; 205 damon_add_region(r2, t); 206 207 damon_merge_two_regions(t, r, r2); 208 KUNIT_EXPECT_EQ(test, r->ar.start, 0ul); 209 KUNIT_EXPECT_EQ(test, r->ar.end, 300ul); 210 KUNIT_EXPECT_EQ(test, r->nr_accesses, 16u); 211 KUNIT_EXPECT_EQ(test, r->nr_accesses_bp, 160000u); 212 KUNIT_EXPECT_EQ(test, r->age, 17u); 213 214 i = 0; 215 damon_for_each_region(r3, t) { 216 KUNIT_EXPECT_PTR_EQ(test, r, r3); 217 i++; 218 } 219 KUNIT_EXPECT_EQ(test, i, 1); 220 221 damon_free_target(t); 222 } 223 224 static struct damon_region *__nth_region_of(struct damon_target *t, int idx) 225 { 226 struct damon_region *r; 227 unsigned int i = 0; 228 229 damon_for_each_region(r, t) { 230 if (i++ == idx) 231 return r; 232 } 233 234 return NULL; 235 } 236 237 static void damon_test_merge_regions_of(struct kunit *test) 238 { 239 struct damon_target *t; 240 struct damon_region *r; 241 unsigned long sa[] = {0, 100, 114, 122, 130, 156, 170, 184, 230}; 242 unsigned long ea[] = {100, 112, 122, 130, 156, 170, 184, 230, 10170}; 243 unsigned int nrs[] = {0, 0, 10, 10, 20, 30, 1, 2, 5}; 244 245 unsigned long saddrs[] = {0, 114, 130, 156, 170, 230}; 246 unsigned long eaddrs[] = {112, 130, 156, 170, 230, 10170}; 247 int i; 248 249 t = damon_new_target(); 250 if (!t) 251 kunit_skip(test, "target alloc fail"); 252 for (i = 0; i < ARRAY_SIZE(sa); i++) { 253 r = damon_new_region(sa[i], ea[i]); 254 if (!r) { 255 damon_free_target(t); 256 kunit_skip(test, "region alloc fail"); 257 } 258 r->nr_accesses = nrs[i]; 259 r->nr_accesses_bp = nrs[i] * 10000; 260 damon_add_region(r, t); 261 } 262 263 damon_merge_regions_of(t, 9, 9999); 264 /* 0-112, 114-130, 130-156, 156-170, 170-230, 230-10170 */ 265 KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 6u); 266 for (i = 0; i < 6; i++) { 267 r = __nth_region_of(t, i); 268 KUNIT_EXPECT_EQ(test, r->ar.start, saddrs[i]); 269 KUNIT_EXPECT_EQ(test, r->ar.end, eaddrs[i]); 270 } 271 damon_free_target(t); 272 } 273 274 static void damon_test_split_regions_of(struct kunit *test) 275 { 276 struct damon_ctx *c; 277 struct damon_target *t; 278 struct damon_region *r; 279 unsigned long sa[] = {0, 300, 500}; 280 unsigned long ea[] = {220, 400, 700}; 281 int i; 282 283 c = damon_new_ctx(); 284 if (!c) 285 kunit_skip(test, "ctx alloc fail"); 286 287 t = damon_new_target(); 288 if (!t) { 289 damon_destroy_ctx(c); 290 kunit_skip(test, "target alloc fail"); 291 } 292 r = damon_new_region(0, 22); 293 if (!r) { 294 damon_free_target(t); 295 damon_destroy_ctx(c); 296 kunit_skip(test, "region alloc fail"); 297 } 298 damon_add_region(r, t); 299 damon_split_regions_of(c, t, 2, 1); 300 KUNIT_EXPECT_LE(test, damon_nr_regions(t), 2u); 301 damon_free_target(t); 302 303 t = damon_new_target(); 304 if (!t) { 305 damon_destroy_ctx(c); 306 kunit_skip(test, "second target alloc fail"); 307 } 308 r = damon_new_region(0, 220); 309 if (!r) { 310 damon_free_target(t); 311 damon_destroy_ctx(c); 312 kunit_skip(test, "second region alloc fail"); 313 } 314 damon_add_region(r, t); 315 damon_split_regions_of(c, t, 4, 1); 316 KUNIT_EXPECT_LE(test, damon_nr_regions(t), 4u); 317 damon_free_target(t); 318 319 t = damon_new_target(); 320 if (!t) { 321 damon_destroy_ctx(c); 322 kunit_skip(test, "third target alloc fail"); 323 } 324 for (i = 0; i < ARRAY_SIZE(sa); i++) { 325 r = damon_new_region(sa[i], ea[i]); 326 if (!r) { 327 damon_free_target(t); 328 damon_destroy_ctx(c); 329 kunit_skip(test, "region alloc fail"); 330 } 331 damon_add_region(r, t); 332 } 333 damon_split_regions_of(c, t, 4, 5); 334 KUNIT_EXPECT_LE(test, damon_nr_regions(t), 12u); 335 damon_for_each_region(r, t) 336 KUNIT_EXPECT_GE(test, damon_sz_region(r) % 5ul, 0ul); 337 damon_free_target(t); 338 339 damon_destroy_ctx(c); 340 } 341 342 static void damon_test_ops_registration(struct kunit *test) 343 { 344 struct damon_ctx *c = damon_new_ctx(); 345 struct damon_operations ops = {.id = DAMON_OPS_VADDR}, bak; 346 bool need_cleanup = false; 347 348 if (!c) 349 kunit_skip(test, "ctx alloc fail"); 350 351 /* DAMON_OPS_VADDR is registered only if CONFIG_DAMON_VADDR is set */ 352 if (!damon_is_registered_ops(DAMON_OPS_VADDR)) { 353 bak.id = DAMON_OPS_VADDR; 354 KUNIT_EXPECT_EQ(test, damon_register_ops(&bak), 0); 355 need_cleanup = true; 356 } 357 358 /* DAMON_OPS_VADDR is ensured to be registered */ 359 KUNIT_EXPECT_EQ(test, damon_select_ops(c, DAMON_OPS_VADDR), 0); 360 361 /* Double-registration is prohibited */ 362 KUNIT_EXPECT_EQ(test, damon_register_ops(&ops), -EINVAL); 363 364 /* Unknown ops id cannot be registered */ 365 KUNIT_EXPECT_EQ(test, damon_select_ops(c, NR_DAMON_OPS), -EINVAL); 366 367 /* Registration should success after unregistration */ 368 mutex_lock(&damon_ops_lock); 369 bak = damon_registered_ops[DAMON_OPS_VADDR]; 370 damon_registered_ops[DAMON_OPS_VADDR] = (struct damon_operations){}; 371 mutex_unlock(&damon_ops_lock); 372 373 ops.id = DAMON_OPS_VADDR; 374 KUNIT_EXPECT_EQ(test, damon_register_ops(&ops), 0); 375 376 mutex_lock(&damon_ops_lock); 377 damon_registered_ops[DAMON_OPS_VADDR] = bak; 378 mutex_unlock(&damon_ops_lock); 379 380 /* Check double-registration failure again */ 381 KUNIT_EXPECT_EQ(test, damon_register_ops(&ops), -EINVAL); 382 383 damon_destroy_ctx(c); 384 385 if (need_cleanup) { 386 mutex_lock(&damon_ops_lock); 387 damon_registered_ops[DAMON_OPS_VADDR] = 388 (struct damon_operations){}; 389 mutex_unlock(&damon_ops_lock); 390 } 391 } 392 393 static void damon_test_set_regions_for(struct kunit *test, 394 struct damon_addr_range *old_ranges, int sz_old_ranges, 395 struct damon_addr_range *new_ranges, int sz_new_ranges, 396 unsigned long min_region_sz, 397 struct damon_addr_range *expect_ranges, int sz_expect_ranges) 398 { 399 struct damon_target *t; 400 struct damon_region *r; 401 int i; 402 403 t = damon_new_target(); 404 if (!t) 405 kunit_skip(test, "target alloc fail"); 406 for (i = 0; i < sz_old_ranges; i++) { 407 r = damon_new_region(old_ranges[i].start, old_ranges[i].end); 408 if (!r) { 409 damon_destroy_target(t, NULL); 410 kunit_skip(test, "%d-th r alloc fail\n", i); 411 } 412 damon_add_region(r, t); 413 } 414 415 damon_set_regions(t, new_ranges, sz_new_ranges, min_region_sz); 416 417 KUNIT_EXPECT_EQ(test, damon_nr_regions(t), sz_expect_ranges); 418 if (damon_nr_regions(t) != sz_expect_ranges) { 419 damon_destroy_target(t, NULL); 420 return; 421 } 422 i = 0; 423 damon_for_each_region(r, t) { 424 KUNIT_EXPECT_EQ(test, r->ar.start, expect_ranges[i].start); 425 KUNIT_EXPECT_EQ(test, r->ar.end, expect_ranges[i++].end); 426 } 427 428 damon_destroy_target(t, NULL); 429 } 430 431 static void damon_test_set_regions(struct kunit *test) 432 { 433 /* Initial build up on empty target. */ 434 damon_test_set_regions_for(test, 435 (struct damon_addr_range[]){}, 0, 436 (struct damon_addr_range[]){ 437 {.start = 5, .end = 15}, 438 {.start = 15, .end = 25}, 439 }, 2, 440 1, 441 (struct damon_addr_range[]){ 442 {.start = 5, .end = 15}, 443 {.start = 15, .end = 25}, 444 }, 2); 445 /* Un-intersecting regions should be removed. */ 446 damon_test_set_regions_for(test, 447 (struct damon_addr_range[]){ 448 {.start = 4, .end = 16}, 449 {.start = 24, .end = 32}, 450 }, 2, 451 (struct damon_addr_range[]){ 452 {.start = 18, .end = 23}, 453 }, 1, 454 1, 455 (struct damon_addr_range[]){ 456 {.start = 18, .end = 23}, 457 }, 1); 458 /* 459 * Holes should be filled up with new regions. 460 * 461 * old: [4, 16) [24, 32) 462 * new: [8, 28) 463 * expect: [8, 16)[16,24),[24, 28) 464 */ 465 damon_test_set_regions_for(test, 466 (struct damon_addr_range[]){ 467 {.start = 4, .end = 16}, 468 {.start = 24, .end = 32}, 469 }, 2, 470 (struct damon_addr_range[]){ 471 {.start = 8, .end = 28}, 472 }, 1, 473 1, 474 (struct damon_addr_range[]){ 475 {.start = 8, .end = 16}, 476 {.start = 16, .end = 24}, 477 {.start = 24, .end = 28}, 478 }, 3); 479 /* 480 * New regions should be able to be appended. 481 * 482 * old: [0, 4)[4, 17) 483 * new: [0, 15) [25, 40) 484 * expect: [0, 4)[4, 15) [25, 40) 485 */ 486 damon_test_set_regions_for(test, 487 (struct damon_addr_range[]){ 488 {.start = 0, .end = 4}, 489 {.start = 4, .end = 17}, 490 }, 2, 491 (struct damon_addr_range[]){ 492 {.start = 0, .end = 15}, 493 {.start = 25, .end = 40}, 494 }, 2, 495 1, 496 (struct damon_addr_range[]){ 497 {.start = 0, .end = 4}, 498 {.start = 4, .end = 15}, 499 {.start = 25, .end = 40}, 500 }, 3); 501 /* 502 * New regions should be able to be inserted. 503 * 504 * old: [0, 4) [42, 52) 505 * new: [0, 15) [25, 40) [44, 50) 506 * expect: [0, 15) [25, 40) [44, 50) 507 */ 508 damon_test_set_regions_for(test, 509 (struct damon_addr_range[]){ 510 {.start = 0, .end = 4}, 511 {.start = 42, .end = 52}, 512 }, 2, 513 (struct damon_addr_range[]){ 514 {.start = 0, .end = 15}, 515 {.start = 25, .end = 40}, 516 {.start = 44, .end = 50}, 517 }, 3, 518 1, 519 (struct damon_addr_range[]){ 520 {.start = 0, .end = 15}, 521 {.start = 25, .end = 40}, 522 {.start = 44, .end = 50}, 523 }, 3); 524 } 525 526 static void damon_test_nr_accesses_to_accesses_bp(struct kunit *test) 527 { 528 struct damon_attrs attrs = { 529 .sample_interval = 10, 530 .aggr_interval = ((unsigned long)UINT_MAX + 1) * 10 531 }; 532 533 /* 534 * In some cases such as 32bit architectures where UINT_MAX is 535 * ULONG_MAX, attrs.aggr_interval becomes zero. Calling 536 * damon_nr_accesses_to_accesses_bp() in the case will cause 537 * divide-by-zero. Such case is prohibited in normal execution since 538 * the caution is documented on the comment for the function, and 539 * damon_update_monitoring_results() does the check. Skip the test in 540 * the case. 541 */ 542 if (!attrs.aggr_interval) 543 kunit_skip(test, "aggr_interval is zero."); 544 545 KUNIT_EXPECT_EQ(test, damon_nr_accesses_to_accesses_bp(123, &attrs), 0); 546 } 547 548 static void damon_test_update_monitoring_result(struct kunit *test) 549 { 550 struct damon_attrs old_attrs = { 551 .sample_interval = 10, .aggr_interval = 1000,}; 552 struct damon_attrs new_attrs; 553 struct damon_region *r = damon_new_region(3, 7); 554 555 if (!r) 556 kunit_skip(test, "region alloc fail"); 557 558 r->nr_accesses = 15; 559 r->nr_accesses_bp = 150000; 560 r->age = 20; 561 562 new_attrs = (struct damon_attrs){ 563 .sample_interval = 100, .aggr_interval = 10000,}; 564 damon_update_monitoring_result(r, &old_attrs, &new_attrs, false); 565 KUNIT_EXPECT_EQ(test, r->nr_accesses, 15); 566 KUNIT_EXPECT_EQ(test, r->age, 2); 567 568 new_attrs = (struct damon_attrs){ 569 .sample_interval = 1, .aggr_interval = 1000}; 570 damon_update_monitoring_result(r, &old_attrs, &new_attrs, false); 571 KUNIT_EXPECT_EQ(test, r->nr_accesses, 150); 572 KUNIT_EXPECT_EQ(test, r->age, 2); 573 574 new_attrs = (struct damon_attrs){ 575 .sample_interval = 1, .aggr_interval = 100}; 576 damon_update_monitoring_result(r, &old_attrs, &new_attrs, false); 577 KUNIT_EXPECT_EQ(test, r->nr_accesses, 150); 578 KUNIT_EXPECT_EQ(test, r->age, 20); 579 580 damon_free_region(r); 581 } 582 583 static void damon_test_set_attrs(struct kunit *test) 584 { 585 struct damon_ctx *c = damon_new_ctx(); 586 struct damon_attrs valid_attrs = { 587 .min_nr_regions = 10, .max_nr_regions = 1000, 588 .sample_interval = 5000, .aggr_interval = 100000,}; 589 struct damon_attrs invalid_attrs; 590 591 if (!c) 592 kunit_skip(test, "ctx alloc fail"); 593 594 KUNIT_EXPECT_EQ(test, damon_set_attrs(c, &valid_attrs), 0); 595 596 invalid_attrs = valid_attrs; 597 invalid_attrs.min_nr_regions = 1; 598 KUNIT_EXPECT_EQ(test, damon_set_attrs(c, &invalid_attrs), -EINVAL); 599 600 invalid_attrs = valid_attrs; 601 invalid_attrs.max_nr_regions = 9; 602 KUNIT_EXPECT_EQ(test, damon_set_attrs(c, &invalid_attrs), -EINVAL); 603 604 invalid_attrs = valid_attrs; 605 invalid_attrs.aggr_interval = 4999; 606 KUNIT_EXPECT_EQ(test, damon_set_attrs(c, &invalid_attrs), -EINVAL); 607 608 damon_destroy_ctx(c); 609 } 610 611 static void damon_test_moving_sum(struct kunit *test) 612 { 613 unsigned int mvsum = 50000, nomvsum = 50000, len_window = 10; 614 unsigned int new_values[] = {10000, 0, 10000, 0, 0, 0, 10000, 0, 0, 0}; 615 unsigned int expects[] = {55000, 50000, 55000, 50000, 45000, 40000, 616 45000, 40000, 35000, 30000}; 617 int i; 618 619 for (i = 0; i < ARRAY_SIZE(new_values); i++) { 620 mvsum = damon_moving_sum(mvsum, nomvsum, len_window, 621 new_values[i]); 622 KUNIT_EXPECT_EQ(test, mvsum, expects[i]); 623 } 624 } 625 626 static void damos_test_new_filter(struct kunit *test) 627 { 628 struct damos_filter *filter; 629 630 filter = damos_new_filter(DAMOS_FILTER_TYPE_ANON, true, false); 631 if (!filter) 632 kunit_skip(test, "filter alloc fail"); 633 KUNIT_EXPECT_EQ(test, filter->type, DAMOS_FILTER_TYPE_ANON); 634 KUNIT_EXPECT_EQ(test, filter->matching, true); 635 KUNIT_EXPECT_PTR_EQ(test, filter->list.prev, &filter->list); 636 KUNIT_EXPECT_PTR_EQ(test, filter->list.next, &filter->list); 637 damos_destroy_filter(filter); 638 } 639 640 static void damos_test_commit_quota_goal_for(struct kunit *test, 641 struct damos_quota_goal *dst, 642 struct damos_quota_goal *src) 643 { 644 u64 dst_last_psi_total = 0; 645 646 if (dst->metric == DAMOS_QUOTA_SOME_MEM_PSI_US) 647 dst_last_psi_total = dst->last_psi_total; 648 damos_commit_quota_goal(dst, src); 649 650 KUNIT_EXPECT_EQ(test, dst->metric, src->metric); 651 KUNIT_EXPECT_EQ(test, dst->target_value, src->target_value); 652 if (src->metric == DAMOS_QUOTA_USER_INPUT) 653 KUNIT_EXPECT_EQ(test, dst->current_value, src->current_value); 654 if (dst_last_psi_total && src->metric == DAMOS_QUOTA_SOME_MEM_PSI_US) 655 KUNIT_EXPECT_EQ(test, dst->last_psi_total, dst_last_psi_total); 656 switch (dst->metric) { 657 case DAMOS_QUOTA_NODE_MEM_USED_BP: 658 case DAMOS_QUOTA_NODE_MEM_FREE_BP: 659 KUNIT_EXPECT_EQ(test, dst->nid, src->nid); 660 break; 661 case DAMOS_QUOTA_NODE_MEMCG_USED_BP: 662 case DAMOS_QUOTA_NODE_MEMCG_FREE_BP: 663 KUNIT_EXPECT_EQ(test, dst->nid, src->nid); 664 KUNIT_EXPECT_EQ(test, dst->memcg_id, src->memcg_id); 665 break; 666 default: 667 break; 668 } 669 } 670 671 static void damos_test_commit_quota_goal(struct kunit *test) 672 { 673 struct damos_quota_goal dst = { 674 .metric = DAMOS_QUOTA_SOME_MEM_PSI_US, 675 .target_value = 1000, 676 .current_value = 123, 677 .last_psi_total = 456, 678 }; 679 680 damos_test_commit_quota_goal_for(test, &dst, 681 &(struct damos_quota_goal){ 682 .metric = DAMOS_QUOTA_USER_INPUT, 683 .target_value = 789, 684 .current_value = 12}); 685 damos_test_commit_quota_goal_for(test, &dst, 686 &(struct damos_quota_goal){ 687 .metric = DAMOS_QUOTA_NODE_MEM_FREE_BP, 688 .target_value = 345, 689 .current_value = 678, 690 .nid = 9, 691 }); 692 damos_test_commit_quota_goal_for(test, &dst, 693 &(struct damos_quota_goal){ 694 .metric = DAMOS_QUOTA_NODE_MEM_USED_BP, 695 .target_value = 12, 696 .current_value = 345, 697 .nid = 6, 698 }); 699 damos_test_commit_quota_goal_for(test, &dst, 700 &(struct damos_quota_goal){ 701 .metric = DAMOS_QUOTA_NODE_MEMCG_USED_BP, 702 .target_value = 456, 703 .current_value = 567, 704 .nid = 6, 705 .memcg_id = 7, 706 }); 707 damos_test_commit_quota_goal_for(test, &dst, 708 &(struct damos_quota_goal){ 709 .metric = DAMOS_QUOTA_NODE_MEMCG_FREE_BP, 710 .target_value = 890, 711 .current_value = 901, 712 .nid = 10, 713 .memcg_id = 1, 714 }); 715 damos_test_commit_quota_goal_for(test, &dst, 716 &(struct damos_quota_goal) { 717 .metric = DAMOS_QUOTA_SOME_MEM_PSI_US, 718 .target_value = 234, 719 .current_value = 345, 720 .last_psi_total = 567, 721 }); 722 } 723 724 static void damos_test_commit_quota_goals_for(struct kunit *test, 725 struct damos_quota_goal *dst_goals, int nr_dst_goals, 726 struct damos_quota_goal *src_goals, int nr_src_goals) 727 { 728 struct damos_quota dst, src; 729 struct damos_quota_goal *goal, *next; 730 bool skip = true; 731 int i; 732 733 INIT_LIST_HEAD(&dst.goals); 734 INIT_LIST_HEAD(&src.goals); 735 736 for (i = 0; i < nr_dst_goals; i++) { 737 /* 738 * When nr_src_goals is smaller than dst_goals, 739 * damos_commit_quota_goals() will kfree() the dst goals. 740 * Make it kfree()-able. 741 */ 742 goal = damos_new_quota_goal(dst_goals[i].metric, 743 dst_goals[i].target_value); 744 if (!goal) 745 goto out; 746 damos_add_quota_goal(&dst, goal); 747 } 748 skip = false; 749 for (i = 0; i < nr_src_goals; i++) 750 damos_add_quota_goal(&src, &src_goals[i]); 751 752 damos_commit_quota_goals(&dst, &src); 753 754 i = 0; 755 damos_for_each_quota_goal(goal, (&dst)) { 756 KUNIT_EXPECT_EQ(test, goal->metric, src_goals[i].metric); 757 KUNIT_EXPECT_EQ(test, goal->target_value, 758 src_goals[i++].target_value); 759 } 760 KUNIT_EXPECT_EQ(test, i, nr_src_goals); 761 762 out: 763 damos_for_each_quota_goal_safe(goal, next, (&dst)) 764 damos_destroy_quota_goal(goal); 765 if (skip) 766 kunit_skip(test, "goal alloc fail"); 767 } 768 769 static void damos_test_commit_quota_goals(struct kunit *test) 770 { 771 damos_test_commit_quota_goals_for(test, 772 (struct damos_quota_goal[]){}, 0, 773 (struct damos_quota_goal[]){ 774 { 775 .metric = DAMOS_QUOTA_USER_INPUT, 776 .target_value = 123, 777 }, 778 }, 1); 779 damos_test_commit_quota_goals_for(test, 780 (struct damos_quota_goal[]){ 781 { 782 .metric = DAMOS_QUOTA_USER_INPUT, 783 .target_value = 234, 784 }, 785 786 }, 1, 787 (struct damos_quota_goal[]){ 788 { 789 .metric = DAMOS_QUOTA_USER_INPUT, 790 .target_value = 345, 791 }, 792 }, 1); 793 damos_test_commit_quota_goals_for(test, 794 (struct damos_quota_goal[]){ 795 { 796 .metric = DAMOS_QUOTA_USER_INPUT, 797 .target_value = 456, 798 }, 799 800 }, 1, 801 (struct damos_quota_goal[]){}, 0); 802 } 803 804 static void damos_test_commit_quota(struct kunit *test) 805 { 806 struct damos_quota dst = { 807 .reset_interval = 1, 808 .ms = 2, 809 .sz = 3, 810 .goal_tuner = DAMOS_QUOTA_GOAL_TUNER_CONSIST, 811 .fail_charge_num = 2, 812 .fail_charge_denom = 3, 813 .weight_sz = 4, 814 .weight_nr_accesses = 5, 815 .weight_age = 6, 816 }; 817 struct damos_quota src = { 818 .reset_interval = 7, 819 .ms = 8, 820 .sz = 9, 821 .goal_tuner = DAMOS_QUOTA_GOAL_TUNER_TEMPORAL, 822 .fail_charge_num = 1, 823 .fail_charge_denom = 1024, 824 .weight_sz = 10, 825 .weight_nr_accesses = 11, 826 .weight_age = 12, 827 }; 828 829 INIT_LIST_HEAD(&dst.goals); 830 INIT_LIST_HEAD(&src.goals); 831 832 damos_commit_quota(&dst, &src); 833 834 KUNIT_EXPECT_EQ(test, dst.reset_interval, src.reset_interval); 835 KUNIT_EXPECT_EQ(test, dst.ms, src.ms); 836 KUNIT_EXPECT_EQ(test, dst.sz, src.sz); 837 KUNIT_EXPECT_EQ(test, dst.goal_tuner, src.goal_tuner); 838 KUNIT_EXPECT_EQ(test, dst.fail_charge_num, src.fail_charge_num); 839 KUNIT_EXPECT_EQ(test, dst.fail_charge_denom, src.fail_charge_denom); 840 KUNIT_EXPECT_EQ(test, dst.weight_sz, src.weight_sz); 841 KUNIT_EXPECT_EQ(test, dst.weight_nr_accesses, src.weight_nr_accesses); 842 KUNIT_EXPECT_EQ(test, dst.weight_age, src.weight_age); 843 } 844 845 static int damos_test_help_dests_setup(struct damos_migrate_dests *dests, 846 unsigned int *node_id_arr, unsigned int *weight_arr, 847 size_t nr_dests) 848 { 849 size_t i; 850 851 dests->node_id_arr = kmalloc_objs(*dests->node_id_arr, nr_dests); 852 if (!dests->node_id_arr) 853 return -ENOMEM; 854 dests->weight_arr = kmalloc_objs(*dests->weight_arr, nr_dests); 855 if (!dests->weight_arr) { 856 kfree(dests->node_id_arr); 857 dests->node_id_arr = NULL; 858 return -ENOMEM; 859 } 860 861 for (i = 0; i < nr_dests; i++) { 862 dests->node_id_arr[i] = node_id_arr[i]; 863 dests->weight_arr[i] = weight_arr[i]; 864 } 865 dests->nr_dests = nr_dests; 866 return 0; 867 } 868 869 static void damos_test_help_dests_free(struct damos_migrate_dests *dests) 870 { 871 kfree(dests->node_id_arr); 872 kfree(dests->weight_arr); 873 } 874 875 static void damos_test_commit_dests_for(struct kunit *test, 876 unsigned int *dst_node_id_arr, unsigned int *dst_weight_arr, 877 size_t dst_nr_dests, 878 unsigned int *src_node_id_arr, unsigned int *src_weight_arr, 879 size_t src_nr_dests) 880 { 881 struct damos_migrate_dests dst = {}, src = {}; 882 int i, err; 883 bool skip = true; 884 885 err = damos_test_help_dests_setup(&dst, dst_node_id_arr, 886 dst_weight_arr, dst_nr_dests); 887 if (err) 888 kunit_skip(test, "dests setup fail"); 889 err = damos_test_help_dests_setup(&src, src_node_id_arr, 890 src_weight_arr, src_nr_dests); 891 if (err) { 892 damos_test_help_dests_free(&dst); 893 kunit_skip(test, "src setup fail"); 894 } 895 err = damos_commit_dests(&dst, &src); 896 if (err) 897 goto out; 898 skip = false; 899 900 KUNIT_EXPECT_EQ(test, dst.nr_dests, src_nr_dests); 901 for (i = 0; i < dst.nr_dests; i++) { 902 KUNIT_EXPECT_EQ(test, dst.node_id_arr[i], src_node_id_arr[i]); 903 KUNIT_EXPECT_EQ(test, dst.weight_arr[i], src_weight_arr[i]); 904 } 905 906 out: 907 damos_test_help_dests_free(&dst); 908 damos_test_help_dests_free(&src); 909 if (skip) 910 kunit_skip(test, "skip"); 911 } 912 913 static void damos_test_commit_dests(struct kunit *test) 914 { 915 damos_test_commit_dests_for(test, 916 (unsigned int[]){1, 2, 3}, (unsigned int[]){2, 3, 4}, 917 3, 918 (unsigned int[]){4, 5, 6}, (unsigned int[]){5, 6, 7}, 919 3); 920 damos_test_commit_dests_for(test, 921 (unsigned int[]){1, 2}, (unsigned int[]){2, 3}, 922 2, 923 (unsigned int[]){4, 5, 6}, (unsigned int[]){5, 6, 7}, 924 3); 925 damos_test_commit_dests_for(test, 926 NULL, NULL, 0, 927 (unsigned int[]){4, 5, 6}, (unsigned int[]){5, 6, 7}, 928 3); 929 damos_test_commit_dests_for(test, 930 (unsigned int[]){1, 2, 3}, (unsigned int[]){2, 3, 4}, 931 3, 932 (unsigned int[]){4, 5}, (unsigned int[]){5, 6}, 2); 933 damos_test_commit_dests_for(test, 934 (unsigned int[]){1, 2, 3}, (unsigned int[]){2, 3, 4}, 935 3, 936 NULL, NULL, 0); 937 } 938 939 static void damos_test_commit_filter_for(struct kunit *test, 940 struct damos_filter *dst, struct damos_filter *src) 941 { 942 damos_commit_filter(dst, src); 943 KUNIT_EXPECT_EQ(test, dst->type, src->type); 944 KUNIT_EXPECT_EQ(test, dst->matching, src->matching); 945 KUNIT_EXPECT_EQ(test, dst->allow, src->allow); 946 switch (src->type) { 947 case DAMOS_FILTER_TYPE_MEMCG: 948 KUNIT_EXPECT_EQ(test, dst->memcg_id, src->memcg_id); 949 break; 950 case DAMOS_FILTER_TYPE_ADDR: 951 KUNIT_EXPECT_EQ(test, dst->addr_range.start, 952 src->addr_range.start); 953 KUNIT_EXPECT_EQ(test, dst->addr_range.end, 954 src->addr_range.end); 955 break; 956 case DAMOS_FILTER_TYPE_TARGET: 957 KUNIT_EXPECT_EQ(test, dst->target_idx, src->target_idx); 958 break; 959 case DAMOS_FILTER_TYPE_HUGEPAGE_SIZE: 960 KUNIT_EXPECT_EQ(test, dst->sz_range.min, src->sz_range.min); 961 KUNIT_EXPECT_EQ(test, dst->sz_range.max, src->sz_range.max); 962 break; 963 default: 964 break; 965 } 966 } 967 968 static void damos_test_commit_filter(struct kunit *test) 969 { 970 struct damos_filter dst = { 971 .type = DAMOS_FILTER_TYPE_ACTIVE, 972 .matching = false, 973 .allow = false, 974 }; 975 976 damos_test_commit_filter_for(test, &dst, 977 &(struct damos_filter){ 978 .type = DAMOS_FILTER_TYPE_ANON, 979 .matching = true, 980 .allow = true, 981 }); 982 damos_test_commit_filter_for(test, &dst, 983 &(struct damos_filter){ 984 .type = DAMOS_FILTER_TYPE_MEMCG, 985 .matching = false, 986 .allow = false, 987 .memcg_id = 123, 988 }); 989 damos_test_commit_filter_for(test, &dst, 990 &(struct damos_filter){ 991 .type = DAMOS_FILTER_TYPE_YOUNG, 992 .matching = true, 993 .allow = true, 994 }); 995 damos_test_commit_filter_for(test, &dst, 996 &(struct damos_filter){ 997 .type = DAMOS_FILTER_TYPE_HUGEPAGE_SIZE, 998 .matching = false, 999 .allow = false, 1000 .sz_range = {.min = 234, .max = 345}, 1001 }); 1002 damos_test_commit_filter_for(test, &dst, 1003 &(struct damos_filter){ 1004 .type = DAMOS_FILTER_TYPE_UNMAPPED, 1005 .matching = true, 1006 .allow = true, 1007 }); 1008 damos_test_commit_filter_for(test, &dst, 1009 &(struct damos_filter){ 1010 .type = DAMOS_FILTER_TYPE_ADDR, 1011 .matching = false, 1012 .allow = false, 1013 .addr_range = {.start = 456, .end = 567}, 1014 }); 1015 damos_test_commit_filter_for(test, &dst, 1016 &(struct damos_filter){ 1017 .type = DAMOS_FILTER_TYPE_TARGET, 1018 .matching = true, 1019 .allow = true, 1020 .target_idx = 6, 1021 }); 1022 } 1023 1024 static void damos_test_help_initailize_scheme(struct damos *scheme) 1025 { 1026 INIT_LIST_HEAD(&scheme->quota.goals); 1027 INIT_LIST_HEAD(&scheme->core_filters); 1028 INIT_LIST_HEAD(&scheme->ops_filters); 1029 } 1030 1031 static void damos_test_commit_for(struct kunit *test, struct damos *dst, 1032 struct damos *src) 1033 { 1034 int err; 1035 1036 damos_test_help_initailize_scheme(dst); 1037 damos_test_help_initailize_scheme(src); 1038 1039 err = damos_commit(dst, src); 1040 if (err) 1041 kunit_skip(test, "damos_commit fail"); 1042 1043 KUNIT_EXPECT_EQ(test, dst->pattern.min_sz_region, 1044 src->pattern.min_sz_region); 1045 KUNIT_EXPECT_EQ(test, dst->pattern.max_sz_region, 1046 src->pattern.max_sz_region); 1047 KUNIT_EXPECT_EQ(test, dst->pattern.min_nr_accesses, 1048 src->pattern.min_nr_accesses); 1049 KUNIT_EXPECT_EQ(test, dst->pattern.max_nr_accesses, 1050 src->pattern.max_nr_accesses); 1051 KUNIT_EXPECT_EQ(test, dst->pattern.min_age_region, 1052 src->pattern.min_age_region); 1053 KUNIT_EXPECT_EQ(test, dst->pattern.max_age_region, 1054 src->pattern.max_age_region); 1055 1056 KUNIT_EXPECT_EQ(test, dst->action, src->action); 1057 KUNIT_EXPECT_EQ(test, dst->apply_interval_us, src->apply_interval_us); 1058 1059 KUNIT_EXPECT_EQ(test, dst->wmarks.metric, src->wmarks.metric); 1060 KUNIT_EXPECT_EQ(test, dst->wmarks.interval, src->wmarks.interval); 1061 KUNIT_EXPECT_EQ(test, dst->wmarks.high, src->wmarks.high); 1062 KUNIT_EXPECT_EQ(test, dst->wmarks.mid, src->wmarks.mid); 1063 KUNIT_EXPECT_EQ(test, dst->wmarks.low, src->wmarks.low); 1064 1065 switch (src->action) { 1066 case DAMOS_MIGRATE_COLD: 1067 case DAMOS_MIGRATE_HOT: 1068 KUNIT_EXPECT_EQ(test, dst->target_nid, src->target_nid); 1069 break; 1070 default: 1071 break; 1072 } 1073 } 1074 1075 static void damos_test_commit_pageout(struct kunit *test) 1076 { 1077 damos_test_commit_for(test, 1078 &(struct damos){ 1079 .pattern = (struct damos_access_pattern){ 1080 1, 2, 3, 4, 5, 6}, 1081 .action = DAMOS_PAGEOUT, 1082 .apply_interval_us = 1000000, 1083 .wmarks = (struct damos_watermarks){ 1084 DAMOS_WMARK_FREE_MEM_RATE, 1085 900, 100, 50}, 1086 }, 1087 &(struct damos){ 1088 .pattern = (struct damos_access_pattern){ 1089 2, 3, 4, 5, 6, 7}, 1090 .action = DAMOS_PAGEOUT, 1091 .apply_interval_us = 2000000, 1092 .wmarks = (struct damos_watermarks){ 1093 DAMOS_WMARK_FREE_MEM_RATE, 1094 800, 50, 30}, 1095 }); 1096 } 1097 1098 static void damos_test_commit_migrate_hot(struct kunit *test) 1099 { 1100 damos_test_commit_for(test, 1101 &(struct damos){ 1102 .pattern = (struct damos_access_pattern){ 1103 1, 2, 3, 4, 5, 6}, 1104 .action = DAMOS_PAGEOUT, 1105 .apply_interval_us = 1000000, 1106 .wmarks = (struct damos_watermarks){ 1107 DAMOS_WMARK_FREE_MEM_RATE, 1108 900, 100, 50}, 1109 }, 1110 &(struct damos){ 1111 .pattern = (struct damos_access_pattern){ 1112 2, 3, 4, 5, 6, 7}, 1113 .action = DAMOS_MIGRATE_HOT, 1114 .apply_interval_us = 2000000, 1115 .target_nid = 5, 1116 }); 1117 } 1118 1119 static struct damon_target *damon_test_help_setup_target( 1120 unsigned long region_start_end[][2], int nr_regions) 1121 { 1122 struct damon_target *t; 1123 struct damon_region *r; 1124 int i; 1125 1126 t = damon_new_target(); 1127 if (!t) 1128 return NULL; 1129 for (i = 0; i < nr_regions; i++) { 1130 r = damon_new_region(region_start_end[i][0], 1131 region_start_end[i][1]); 1132 if (!r) { 1133 damon_free_target(t); 1134 return NULL; 1135 } 1136 damon_add_region(r, t); 1137 } 1138 return t; 1139 } 1140 1141 static void damon_test_commit_target_regions_for(struct kunit *test, 1142 unsigned long dst_start_end[][2], int nr_dst_regions, 1143 unsigned long src_start_end[][2], int nr_src_regions, 1144 unsigned long expect_start_end[][2], int nr_expect_regions) 1145 { 1146 struct damon_target *dst_target, *src_target; 1147 struct damon_region *r; 1148 int i; 1149 1150 dst_target = damon_test_help_setup_target(dst_start_end, nr_dst_regions); 1151 if (!dst_target) 1152 kunit_skip(test, "dst target setup fail"); 1153 src_target = damon_test_help_setup_target(src_start_end, nr_src_regions); 1154 if (!src_target) { 1155 damon_free_target(dst_target); 1156 kunit_skip(test, "src target setup fail"); 1157 } 1158 damon_commit_target_regions(dst_target, src_target, 1); 1159 i = 0; 1160 damon_for_each_region(r, dst_target) { 1161 KUNIT_EXPECT_EQ(test, r->ar.start, expect_start_end[i][0]); 1162 KUNIT_EXPECT_EQ(test, r->ar.end, expect_start_end[i][1]); 1163 i++; 1164 } 1165 KUNIT_EXPECT_EQ(test, damon_nr_regions(dst_target), nr_expect_regions); 1166 KUNIT_EXPECT_EQ(test, i, nr_expect_regions); 1167 damon_free_target(dst_target); 1168 damon_free_target(src_target); 1169 } 1170 1171 static void damon_test_commit_target_regions(struct kunit *test) 1172 { 1173 damon_test_commit_target_regions_for(test, 1174 (unsigned long[][2]) {{3, 8}, {8, 10}}, 2, 1175 (unsigned long[][2]) {{4, 6}}, 1, 1176 (unsigned long[][2]) {{4, 6}}, 1); 1177 damon_test_commit_target_regions_for(test, 1178 (unsigned long[][2]) {{3, 8}, {8, 10}}, 2, 1179 (unsigned long[][2]) {}, 0, 1180 (unsigned long[][2]) {{3, 8}, {8, 10}}, 2); 1181 } 1182 1183 static void damon_test_commit_ctx(struct kunit *test) 1184 { 1185 struct damon_ctx *src, *dst; 1186 1187 src = damon_new_ctx(); 1188 if (!src) 1189 kunit_skip(test, "src alloc fail"); 1190 dst = damon_new_ctx(); 1191 if (!dst) { 1192 damon_destroy_ctx(src); 1193 kunit_skip(test, "dst alloc fail"); 1194 } 1195 /* Only power of two min_region_sz is allowed. */ 1196 src->min_region_sz = 4096; 1197 KUNIT_EXPECT_EQ(test, damon_commit_ctx(dst, src), 0); 1198 src->min_region_sz = 4095; 1199 KUNIT_EXPECT_EQ(test, damon_commit_ctx(dst, src), -EINVAL); 1200 src->min_region_sz = 4096; 1201 src->pause = true; 1202 KUNIT_EXPECT_EQ(test, damon_commit_ctx(dst, src), 0); 1203 KUNIT_EXPECT_TRUE(test, dst->pause); 1204 damon_destroy_ctx(src); 1205 damon_destroy_ctx(dst); 1206 } 1207 1208 static void damos_test_filter_out(struct kunit *test) 1209 { 1210 struct damon_target *t; 1211 struct damon_region *r, *r2; 1212 struct damos_filter *f; 1213 1214 f = damos_new_filter(DAMOS_FILTER_TYPE_ADDR, true, false); 1215 if (!f) 1216 kunit_skip(test, "filter alloc fail"); 1217 f->addr_range = (struct damon_addr_range){.start = 2, .end = 6}; 1218 1219 t = damon_new_target(); 1220 if (!t) { 1221 damos_destroy_filter(f); 1222 kunit_skip(test, "target alloc fail"); 1223 } 1224 r = damon_new_region(3, 5); 1225 if (!r) { 1226 damos_destroy_filter(f); 1227 damon_free_target(t); 1228 kunit_skip(test, "region alloc fail"); 1229 } 1230 damon_add_region(r, t); 1231 1232 /* region in the range */ 1233 KUNIT_EXPECT_TRUE(test, damos_filter_match(NULL, t, r, f, 1)); 1234 KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 1); 1235 1236 /* region before the range */ 1237 r->ar.start = 1; 1238 r->ar.end = 2; 1239 KUNIT_EXPECT_FALSE(test, 1240 damos_filter_match(NULL, t, r, f, 1)); 1241 KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 1); 1242 1243 /* region after the range */ 1244 r->ar.start = 6; 1245 r->ar.end = 8; 1246 KUNIT_EXPECT_FALSE(test, 1247 damos_filter_match(NULL, t, r, f, 1)); 1248 KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 1); 1249 1250 /* region started before the range */ 1251 r->ar.start = 1; 1252 r->ar.end = 4; 1253 KUNIT_EXPECT_FALSE(test, damos_filter_match(NULL, t, r, f, 1)); 1254 /* filter should have split the region */ 1255 KUNIT_EXPECT_EQ(test, r->ar.start, 1); 1256 KUNIT_EXPECT_EQ(test, r->ar.end, 2); 1257 KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 2); 1258 r2 = damon_next_region(r); 1259 KUNIT_EXPECT_EQ(test, r2->ar.start, 2); 1260 KUNIT_EXPECT_EQ(test, r2->ar.end, 4); 1261 damon_destroy_region(r2, t); 1262 1263 /* region started in the range */ 1264 r->ar.start = 2; 1265 r->ar.end = 8; 1266 KUNIT_EXPECT_TRUE(test, 1267 damos_filter_match(NULL, t, r, f, 1)); 1268 /* filter should have split the region */ 1269 KUNIT_EXPECT_EQ(test, r->ar.start, 2); 1270 KUNIT_EXPECT_EQ(test, r->ar.end, 6); 1271 KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 2); 1272 r2 = damon_next_region(r); 1273 KUNIT_EXPECT_EQ(test, r2->ar.start, 6); 1274 KUNIT_EXPECT_EQ(test, r2->ar.end, 8); 1275 damon_destroy_region(r2, t); 1276 1277 damon_free_target(t); 1278 damos_free_filter(f); 1279 } 1280 1281 static void damon_test_feed_loop_next_input(struct kunit *test) 1282 { 1283 unsigned long last_input = 900000, current_score = 200; 1284 1285 /* 1286 * If current score is lower than the goal, which is always 10,000 1287 * (read the comment on damon_feed_loop_next_input()'s comment), next 1288 * input should be higher than the last input. 1289 */ 1290 KUNIT_EXPECT_GT(test, 1291 damon_feed_loop_next_input(last_input, current_score), 1292 last_input); 1293 1294 /* 1295 * If current score is higher than the goal, next input should be lower 1296 * than the last input. 1297 */ 1298 current_score = 250000000; 1299 KUNIT_EXPECT_LT(test, 1300 damon_feed_loop_next_input(last_input, current_score), 1301 last_input); 1302 1303 /* 1304 * The next input depends on the distance between the current score and 1305 * the goal 1306 */ 1307 KUNIT_EXPECT_GT(test, 1308 damon_feed_loop_next_input(last_input, 200), 1309 damon_feed_loop_next_input(last_input, 2000)); 1310 } 1311 1312 static void damon_test_set_filters_default_reject(struct kunit *test) 1313 { 1314 struct damos scheme; 1315 struct damos_filter *target_filter, *anon_filter; 1316 1317 INIT_LIST_HEAD(&scheme.core_filters); 1318 INIT_LIST_HEAD(&scheme.ops_filters); 1319 1320 damos_set_filters_default_reject(&scheme); 1321 /* 1322 * No filter is installed. Allow by default on both core and ops layer 1323 * filtering stages, since there are no filters at all. 1324 */ 1325 KUNIT_EXPECT_EQ(test, scheme.core_filters_default_reject, false); 1326 KUNIT_EXPECT_EQ(test, scheme.ops_filters_default_reject, false); 1327 1328 target_filter = damos_new_filter(DAMOS_FILTER_TYPE_TARGET, true, true); 1329 if (!target_filter) 1330 kunit_skip(test, "filter alloc fail"); 1331 damos_add_filter(&scheme, target_filter); 1332 damos_set_filters_default_reject(&scheme); 1333 /* 1334 * A core-handled allow-filter is installed. 1335 * Reject by default on core layer filtering stage due to the last 1336 * core-layer-filter's behavior. 1337 * Allow by default on ops layer filtering stage due to the absence of 1338 * ops layer filters. 1339 */ 1340 KUNIT_EXPECT_EQ(test, scheme.core_filters_default_reject, true); 1341 KUNIT_EXPECT_EQ(test, scheme.ops_filters_default_reject, false); 1342 1343 target_filter->allow = false; 1344 damos_set_filters_default_reject(&scheme); 1345 /* 1346 * A core-handled reject-filter is installed. 1347 * Allow by default on core layer filtering stage due to the last 1348 * core-layer-filter's behavior. 1349 * Allow by default on ops layer filtering stage due to the absence of 1350 * ops layer filters. 1351 */ 1352 KUNIT_EXPECT_EQ(test, scheme.core_filters_default_reject, false); 1353 KUNIT_EXPECT_EQ(test, scheme.ops_filters_default_reject, false); 1354 1355 anon_filter = damos_new_filter(DAMOS_FILTER_TYPE_ANON, true, true); 1356 if (!anon_filter) { 1357 damos_free_filter(target_filter); 1358 kunit_skip(test, "anon_filter alloc fail"); 1359 } 1360 damos_add_filter(&scheme, anon_filter); 1361 1362 damos_set_filters_default_reject(&scheme); 1363 /* 1364 * A core-handled reject-filter and ops-handled allow-filter are installed. 1365 * Allow by default on core layer filtering stage due to the existence 1366 * of the ops-handled filter. 1367 * Reject by default on ops layer filtering stage due to the last 1368 * ops-layer-filter's behavior. 1369 */ 1370 KUNIT_EXPECT_EQ(test, scheme.core_filters_default_reject, false); 1371 KUNIT_EXPECT_EQ(test, scheme.ops_filters_default_reject, true); 1372 1373 target_filter->allow = true; 1374 damos_set_filters_default_reject(&scheme); 1375 /* 1376 * A core-handled allow-filter and ops-handled allow-filter are 1377 * installed. 1378 * Allow by default on core layer filtering stage due to the existence 1379 * of the ops-handled filter. 1380 * Reject by default on ops layer filtering stage due to the last 1381 * ops-layer-filter's behavior. 1382 */ 1383 KUNIT_EXPECT_EQ(test, scheme.core_filters_default_reject, false); 1384 KUNIT_EXPECT_EQ(test, scheme.ops_filters_default_reject, true); 1385 1386 damos_free_filter(anon_filter); 1387 damos_free_filter(target_filter); 1388 } 1389 1390 static void damon_test_apply_min_nr_regions_for(struct kunit *test, 1391 unsigned long sz_regions, unsigned long min_region_sz, 1392 unsigned long min_nr_regions, 1393 unsigned long max_region_sz_expect, 1394 unsigned long nr_regions_expect) 1395 { 1396 struct damon_ctx *ctx; 1397 struct damon_target *t; 1398 struct damon_region *r; 1399 unsigned long max_region_size; 1400 1401 ctx = damon_new_ctx(); 1402 if (!ctx) 1403 kunit_skip(test, "ctx alloc fail\n"); 1404 t = damon_new_target(); 1405 if (!t) { 1406 damon_destroy_ctx(ctx); 1407 kunit_skip(test, "target alloc fail\n"); 1408 } 1409 damon_add_target(ctx, t); 1410 r = damon_new_region(0, sz_regions); 1411 if (!r) { 1412 damon_destroy_ctx(ctx); 1413 kunit_skip(test, "region alloc fail\n"); 1414 } 1415 damon_add_region(r, t); 1416 1417 ctx->min_region_sz = min_region_sz; 1418 ctx->attrs.min_nr_regions = min_nr_regions; 1419 max_region_size = damon_apply_min_nr_regions(ctx); 1420 1421 KUNIT_EXPECT_EQ(test, max_region_size, max_region_sz_expect); 1422 KUNIT_EXPECT_EQ(test, damon_nr_regions(t), nr_regions_expect); 1423 1424 damon_destroy_ctx(ctx); 1425 } 1426 1427 static void damon_test_apply_min_nr_regions(struct kunit *test) 1428 { 1429 /* common, expected setup */ 1430 damon_test_apply_min_nr_regions_for(test, 10, 1, 10, 1, 10); 1431 /* no zero size limit */ 1432 damon_test_apply_min_nr_regions_for(test, 10, 1, 15, 1, 10); 1433 /* max size should be aligned by min_region_sz */ 1434 damon_test_apply_min_nr_regions_for(test, 10, 2, 2, 6, 2); 1435 /* 1436 * when min_nr_regions and min_region_sz conflicts, min_region_sz wins. 1437 */ 1438 damon_test_apply_min_nr_regions_for(test, 10, 2, 10, 2, 5); 1439 } 1440 1441 static void damon_test_is_last_region(struct kunit *test) 1442 { 1443 struct damon_region *r; 1444 struct damon_target *t; 1445 int i; 1446 1447 t = damon_new_target(); 1448 if (!t) 1449 kunit_skip(test, "target alloc fail\n"); 1450 1451 for (i = 0; i < 4; i++) { 1452 r = damon_new_region(i * 2, (i + 1) * 2); 1453 if (!r) { 1454 damon_free_target(t); 1455 kunit_skip(test, "region alloc %d fail\n", i); 1456 } 1457 damon_add_region(r, t); 1458 KUNIT_EXPECT_TRUE(test, damon_is_last_region(r, t)); 1459 } 1460 damon_free_target(t); 1461 } 1462 1463 static struct kunit_case damon_test_cases[] = { 1464 KUNIT_CASE(damon_test_target), 1465 KUNIT_CASE(damon_test_regions), 1466 KUNIT_CASE(damon_test_aggregate), 1467 KUNIT_CASE(damon_test_split_at), 1468 KUNIT_CASE(damon_test_merge_two), 1469 KUNIT_CASE(damon_test_merge_regions_of), 1470 KUNIT_CASE(damon_test_split_regions_of), 1471 KUNIT_CASE(damon_test_ops_registration), 1472 KUNIT_CASE(damon_test_set_regions), 1473 KUNIT_CASE(damon_test_nr_accesses_to_accesses_bp), 1474 KUNIT_CASE(damon_test_update_monitoring_result), 1475 KUNIT_CASE(damon_test_set_attrs), 1476 KUNIT_CASE(damon_test_moving_sum), 1477 KUNIT_CASE(damos_test_new_filter), 1478 KUNIT_CASE(damos_test_commit_quota_goal), 1479 KUNIT_CASE(damos_test_commit_quota_goals), 1480 KUNIT_CASE(damos_test_commit_quota), 1481 KUNIT_CASE(damos_test_commit_dests), 1482 KUNIT_CASE(damos_test_commit_filter), 1483 KUNIT_CASE(damos_test_commit_pageout), 1484 KUNIT_CASE(damos_test_commit_migrate_hot), 1485 KUNIT_CASE(damon_test_commit_target_regions), 1486 KUNIT_CASE(damon_test_commit_ctx), 1487 KUNIT_CASE(damos_test_filter_out), 1488 KUNIT_CASE(damon_test_feed_loop_next_input), 1489 KUNIT_CASE(damon_test_set_filters_default_reject), 1490 KUNIT_CASE(damon_test_apply_min_nr_regions), 1491 KUNIT_CASE(damon_test_is_last_region), 1492 {}, 1493 }; 1494 1495 static struct kunit_suite damon_test_suite = { 1496 .name = "damon", 1497 .test_cases = damon_test_cases, 1498 }; 1499 kunit_test_suite(damon_test_suite); 1500 1501 #endif /* _DAMON_CORE_TEST_H */ 1502 1503 #endif /* CONFIG_DAMON_KUNIT_TEST */ 1504