}
}
+/*
+ * damos_apply_target() - Apply DAMOS schemes to a given target.
+ * @c: monitoring context to apply its DAMOS schemes to..
+ * @t: monitoring target to apply the schemes to.
+ * @max_region_sz: maximum region size for @c.
+ *
+ * This function could split regions for keeping the quota. To minimize
+ * overhead from the split operations increased number of regions, this
+ * function will also merge regions after the schemes applying attempt is done,
+ * for each region. The merge operation is made only when it doesn't lose the
+ * monitoring information and not violating @max_region_sz.
+ *
+ * Hence, after this function is called, the total number of regions could
+ * be increased or reduced. The increase could make max_nr_regions temporarily
+ * be violated, until the next per-aggregation interval regions merge operation
+ * is executed. The decrease will not violate min_nr_regions though, since it
+ * keeps @max_region_sz.
+ */
+static void damos_apply_target(struct damon_ctx *c, struct damon_target *t,
+ unsigned long max_region_sz)
+{
+ struct damon_region *r;
+
+ damon_for_each_region(r, t) {
+ struct damon_region *prev_r;
+
+ damon_do_apply_schemes(c, t, r);
+ /*
+ * damon_do_apply_scheems() could split the region for the
+ * quota. Keeping the new slices is an overhead. Merge back
+ * the slices into the previous region if it doesn't lose any
+ * information and not violating the max_region_sz.
+ */
+ if (damon_first_region(t) == r)
+ continue;
+ prev_r = damon_prev_region(r);
+ if (prev_r->ar.end != r->ar.start)
+ continue;
+ if (prev_r->age != r->age)
+ continue;
+ if (prev_r->last_nr_accesses != r->last_nr_accesses)
+ continue;
+ if (prev_r->nr_accesses != r->nr_accesses)
+ continue;
+ if (r->ar.end - prev_r->ar.start > max_region_sz)
+ continue;
+ prev_r->ar.end = r->ar.end;
+ damon_destroy_region(r, t);
+ r = prev_r;
+ }
+}
+
/*
* damon_feed_loop_next_input() - get next input to achieve a target score.
* @last_input The last input.
static void kdamond_apply_schemes(struct damon_ctx *c)
{
struct damon_target *t;
- struct damon_region *r;
struct damos *s;
bool has_schemes_to_apply = false;
+ unsigned long max_region_sz;
damon_for_each_scheme(s, c) {
if (time_before(c->passed_sample_intervals, s->next_apply_sis))
if (!has_schemes_to_apply)
return;
+ max_region_sz = damon_region_sz_limit(c);
mutex_lock(&c->walk_control_lock);
damon_for_each_target(t, c) {
if (c->ops.target_valid && c->ops.target_valid(t) == false)
continue;
-
- damon_for_each_region(r, t)
- damon_do_apply_schemes(c, t, r);
+ damos_apply_target(c, t, max_region_sz);
}
damon_for_each_scheme(s, c) {