@@ -24,6 +24,13 @@
* @sampling_addr: Address of the sample for the next access check.
* @nr_accesses: Access frequency of this region.
* @list: List head for siblings.
+ * @age: Age of this region.
+ * @last_nr_accesses: Internal value for age calculation.
+ *
+ * @age is initially zero, increased for each aggregation interval, and reset
+ * to zero again if the access frequency is significantly changed. If two
+ * regions are merged into a new region, both @nr_accesses and @age of the new
+ * region are set as region size-weighted average of those of the two regions.
*/
struct damon_region {
unsigned long vm_start;
@@ -31,6 +38,9 @@ struct damon_region {
unsigned long sampling_addr;
unsigned int nr_accesses;
struct list_head list;
+
+ unsigned int age;
+ unsigned int last_nr_accesses;
};
/**
@@ -101,6 +101,9 @@ static struct damon_region *damon_new_region(struct damon_ctx *ctx,
region->nr_accesses = 0;
INIT_LIST_HEAD(®ion->list);
+ region->age = 0;
+ region->last_nr_accesses = 0;
+
return region;
}
@@ -770,6 +773,7 @@ static void kdamond_reset_aggregated(struct damon_ctx *c)
damon_write_rbuf(c, &r->nr_accesses,
sizeof(r->nr_accesses));
trace_damon_aggregated(t, r, nr);
+ r->last_nr_accesses = r->nr_accesses;
r->nr_accesses = 0;
}
}
@@ -783,9 +787,11 @@ static void kdamond_reset_aggregated(struct damon_ctx *c)
static void damon_merge_two_regions(struct damon_region *l,
struct damon_region *r)
{
- l->nr_accesses = (l->nr_accesses * sz_damon_region(l) +
- r->nr_accesses * sz_damon_region(r)) /
- (sz_damon_region(l) + sz_damon_region(r));
+ unsigned long sz_l = sz_damon_region(l), sz_r = sz_damon_region(r);
+
+ l->nr_accesses = (l->nr_accesses * sz_l + r->nr_accesses * sz_r) /
+ (sz_l + sz_r);
+ l->age = (l->age * sz_l + r->age * sz_r) / (sz_l + sz_r);
l->vm_end = r->vm_end;
damon_destroy_region(r);
}
@@ -803,12 +809,16 @@ static void damon_merge_regions_of(struct damon_task *t, unsigned int thres)
struct damon_region *r, *prev = NULL, *next;
damon_for_each_region_safe(r, next, t) {
- if (!prev || prev->vm_end != r->vm_start ||
- diff_of(prev->nr_accesses, r->nr_accesses) > thres) {
+ if (diff_of(r->nr_accesses, r->last_nr_accesses) > thres)
+ r->age = 0;
+ else
+ r->age++;
+
+ if (prev && prev->vm_end == r->vm_start &&
+ diff_of(prev->nr_accesses, r->nr_accesses) <= thres)
+ damon_merge_two_regions(prev, r);
+ else
prev = r;
- continue;
- }
- damon_merge_two_regions(prev, r);
}
}
@@ -844,6 +854,9 @@ static void damon_split_region_at(struct damon_ctx *ctx,
new = damon_new_region(ctx, r->vm_start + sz_r, r->vm_end);
r->vm_end = new->vm_start;
+ new->age = r->age;
+ new->last_nr_accesses = r->last_nr_accesses;
+
damon_insert_region(new, r, damon_next_region(r));
}