Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

mm/damon/core: split regions for min_nr_regions

Patch series "mm/damon: strictly respect min_nr_regions".

DAMON core respects min_nr_regions only at merge operation. DAMON API
callers are therefore responsible to respect or ignore that. Only vaddr
ops is respecting that, but only for initial start time. DAMON sysfs
interface allows users to setup the initial regions that DAMON core also
respects. But, again, it works for only the initial time. Users setting
the regions for min_nr_regions can be difficult and inefficient, when the
min_nr_regions value is high. There was actually a report [1] from a
user. The use case was page granular access monitoring with a large
aggregation interval.

Make the following three changes for resolving the issue. First (patch
1), make DAMON core split regions at the beginning and every aggregation
interval, to respect the min_nr_regions. Second (patch 2), drop the
vaddr's split operations and related code that are no more needed. Third
(patch 3), add a kunit test for the newly introduced function.


This patch (of 3):

DAMON core layer respects the min_nr_regions parameter by setting the
maximum size of each region as total monitoring region size divided by the
parameter value. And the limit is applied by preventing merge of regions
that result in a region larger than the maximum size. The limit is
updated per ops update interval, because vaddr updates the monitoring
regions on the ops update callback.

It does nothing for the beginning state. That's because the users can set
the initial monitoring regions as they want. That is, if the users really
care about the min_nr_regions, they are supposed to set the initial
monitoring regions to have more than min_nr_regions regions. The virtual
address space operation set, vaddr, has an exceptional case. Users can
ask the ops set to configure the initial regions on its own. For the
case, vaddr sets up the initial regions to meet the min_nr_regions. So,
vaddr has exceptional support, but basically users are required to set the
regions on their own if they want min_nr_regions to be respected.

When 'min_nr_regions' is high, such initial setup is difficult. If DAMON
sysfs interface is used for that, the memory for saving the initial setup
is also a waste.

Even if the user forgives the setup, DAMON will eventually make more than
min_nr_regions regions by splitting operations. But it will take time.
If the aggregation interval is long, the delay could be problematic.
There was actually a report [1] of the case. The reporter wanted to do
page granular monitoring with a large aggregation interval.

Also, DAMON is doing nothing for online changes on monitoring regions and
min_nr_regions. For example, the user can remove a monitoring region or
increase min_nr_regions while DAMON is running.

Split regions larger than the size at the beginning of the kdamond main
loop, to fix the initial setup issue. Also do the split every aggregation
interval, for online changes. This means the behavior is slightly
changed. It is difficult to imagine a use case that actually depends on
the old behavior, though. So this change is arguably fine.

Note that the size limit is aligned by damon_ctx->min_region_sz and cannot
be zero. That is, if min_nr_region is larger than the total size of
monitoring regions divided by ->min_region_sz, that cannot be respected.

Link: https://lkml.kernel.org/r/20260228222831.7232-1-sj@kernel.org
Link: https://lkml.kernel.org/r/20260228222831.7232-2-sj@kernel.org
Link: https://lore.kernel.org/CAC5umyjmJE9SBqjbetZZecpY54bHpn2AvCGNv3aF6J=1cfoPXQ@mail.gmail.com [1]
Signed-off-by: SeongJae Park <sj@kernel.org>
Cc: Brendan Higgins <brendan.higgins@linux.dev>
Cc: David Gow <davidgow@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

SeongJae Park and committed by
Andrew Morton
b1029f29 51d8c78b

+39 -6
+39 -6
mm/damon/core.c
··· 1316 1316 return sz; 1317 1317 } 1318 1318 1319 + static void damon_split_region_at(struct damon_target *t, 1320 + struct damon_region *r, unsigned long sz_r); 1321 + 1322 + /* 1323 + * damon_apply_min_nr_regions() - Make effect of min_nr_regions parameter. 1324 + * @ctx: monitoring context. 1325 + * 1326 + * This function implement min_nr_regions (minimum number of damon_region 1327 + * objects in the given monitoring context) behavior. It first calculates 1328 + * maximum size of each region for enforcing the min_nr_regions as total size 1329 + * of the regions divided by the min_nr_regions. After that, this function 1330 + * splits regions to ensure all regions are equal to or smaller than the size 1331 + * limit. Finally, this function returns the maximum size limit. 1332 + * 1333 + * Returns: maximum size of each region for convincing min_nr_regions. 1334 + */ 1335 + static unsigned long damon_apply_min_nr_regions(struct damon_ctx *ctx) 1336 + { 1337 + unsigned long max_region_sz = damon_region_sz_limit(ctx); 1338 + struct damon_target *t; 1339 + struct damon_region *r, *next; 1340 + 1341 + max_region_sz = ALIGN(max_region_sz, ctx->min_region_sz); 1342 + damon_for_each_target(t, ctx) { 1343 + damon_for_each_region_safe(r, next, t) { 1344 + while (damon_sz_region(r) > max_region_sz) { 1345 + damon_split_region_at(t, r, max_region_sz); 1346 + r = damon_next_region(r); 1347 + } 1348 + } 1349 + } 1350 + return max_region_sz; 1351 + } 1352 + 1319 1353 static int kdamond_fn(void *data); 1320 1354 1321 1355 /* ··· 1705 1671 trace_damon_monitor_intervals_tune(new_attrs.sample_interval); 1706 1672 damon_set_attrs(c, &new_attrs); 1707 1673 } 1708 - 1709 - static void damon_split_region_at(struct damon_target *t, 1710 - struct damon_region *r, unsigned long sz_r); 1711 1674 1712 1675 static bool __damos_valid_target(struct damon_region *r, struct damos *s) 1713 1676 { ··· 2794 2763 if (!ctx->regions_score_histogram) 2795 2764 goto done; 2796 2765 2797 - sz_limit = damon_region_sz_limit(ctx); 2766 + sz_limit = damon_apply_min_nr_regions(ctx); 2798 2767 2799 2768 while (!kdamond_need_stop(ctx)) { 2800 2769 /* ··· 2819 2788 if (ctx->ops.check_accesses) 2820 2789 max_nr_accesses = ctx->ops.check_accesses(ctx); 2821 2790 2822 - if (ctx->passed_sample_intervals >= next_aggregation_sis) 2791 + if (ctx->passed_sample_intervals >= next_aggregation_sis) { 2823 2792 kdamond_merge_regions(ctx, 2824 2793 max_nr_accesses / 10, 2825 2794 sz_limit); 2795 + /* online updates might be made */ 2796 + sz_limit = damon_apply_min_nr_regions(ctx); 2797 + } 2826 2798 2827 2799 /* 2828 2800 * do kdamond_call() and kdamond_apply_schemes() after ··· 2884 2850 sample_interval; 2885 2851 if (ctx->ops.update) 2886 2852 ctx->ops.update(ctx); 2887 - sz_limit = damon_region_sz_limit(ctx); 2888 2853 } 2889 2854 } 2890 2855 done: