2020-06-15 16:23:53

by SeongJae Park

[permalink] [raw]
Subject: [PATCH v16 05/14] mm/damon: Allow dynamic monitoring target regions update

From: SeongJae Park <[email protected]>

The monitoring target regions can be dynamically changed. For example,
virtual memory mapping could be dynamically updated and physical memory
could be hot-plugged.

To handle such cases, this commit adds a monitoring attribute, ``regions
update interval`` and a callback ``init_target_regions`` in the
monitoring context. If the two fields are properly set, DAMON will call
the ``init_target_regions()`` callback for every ``regions update
interval``. In the callback, users can check current memory mapping or
hotplugged physical memory sections and appropriately update the
monitoring target regions of the context.

Signed-off-by: SeongJae Park <[email protected]>
---
include/linux/damon.h | 20 +++++++++++++++-----
mm/damon.c | 23 +++++++++++++++++++++--
2 files changed, 36 insertions(+), 7 deletions(-)

diff --git a/include/linux/damon.h b/include/linux/damon.h
index 9588bc162c3a..aa14d4e910e5 100644
--- a/include/linux/damon.h
+++ b/include/linux/damon.h
@@ -64,13 +64,16 @@ struct damon_task {
*
* @sample_interval: The time between access samplings.
* @aggr_interval: The time between monitor results aggregations.
+ * @regions_update_interval: The time between monitor regions updates.
* @min_nr_regions: The number of initial monitoring regions.
* @max_nr_regions: The maximum number of monitoring regions.
*
* For each @sample_interval, DAMON checks whether each region is accessed or
* not. It aggregates and keeps the access information (number of accesses to
- * each region) for @aggr_interval time. All time intervals are in
- * micro-seconds.
+ * each region) for @aggr_interval time. DAMON also checks whether the target
+ * memory regions need update (e.g., by ``mmap()`` calls from the application,
+ * in case of virtual memory monitoring) and applies the changes for each
+ * @regions_update_interval. All time intervals are in micro-seconds.
*
* @kdamond: Kernel thread who does the monitoring.
* @kdamond_stop: Notifies whether kdamond should stop.
@@ -88,6 +91,7 @@ struct damon_task {
* @tasks_list: Head of monitoring target tasks (&damon_task) list.
*
* @init_target_regions: Constructs initial monitoring target regions.
+ * @update_target_regions: Updates monitoring target regions.
* @prepare_access_checks: Prepares next access check of target regions.
* @check_accesses: Checks the access of target regions.
* @sample_cb: Called for each sampling interval.
@@ -96,11 +100,14 @@ struct damon_task {
* DAMON can be extended for various address spaces by users. For this, users
* can register the target address space dependent low level functions for
* their usecases via the callback pointers of the context. The monitoring
- * thread calls @init_target_regions before starting the monitoring, and
+ * thread calls @init_target_regions before starting the monitoring,
+ * @update_target_regions for each @regions_update_interval, and
* @prepare_access_checks and @check_accesses for each @sample_interval.
*
* @init_target_regions should construct proper monitoring target regions and
* link those to the DAMON context struct.
+ * @update_target_regions should update the monitoring target regions for
+ * current status.
* @prepare_access_checks should manipulate the monitoring regions to be
* prepare for the next access check.
* @check_accesses should check the accesses to each region that made after the
@@ -115,10 +122,12 @@ struct damon_task {
struct damon_ctx {
unsigned long sample_interval;
unsigned long aggr_interval;
+ unsigned long regions_update_interval;
unsigned long min_nr_regions;
unsigned long max_nr_regions;

struct timespec64 last_aggregation;
+ struct timespec64 last_regions_update;

struct task_struct *kdamond;
bool kdamond_stop;
@@ -128,6 +137,7 @@ struct damon_ctx {

/* callbacks */
void (*init_target_regions)(struct damon_ctx *context);
+ void (*update_target_regions)(struct damon_ctx *context);
void (*prepare_access_checks)(struct damon_ctx *context);
unsigned int (*check_accesses)(struct damon_ctx *context);
void (*sample_cb)(struct damon_ctx *context);
@@ -135,8 +145,8 @@ struct damon_ctx {
};

int damon_set_pids(struct damon_ctx *ctx, int *pids, ssize_t nr_pids);
-int damon_set_attrs(struct damon_ctx *ctx,
- unsigned long sample_int, unsigned long aggr_int,
+int damon_set_attrs(struct damon_ctx *ctx, unsigned long sample_int,
+ unsigned long aggr_int, unsigned long regions_update_int,
unsigned long min_nr_reg, unsigned long max_nr_reg);
int damon_start(struct damon_ctx *ctx);
int damon_stop(struct damon_ctx *ctx);
diff --git a/mm/damon.c b/mm/damon.c
index 5cf39b3ad222..a19ec17a35cb 100644
--- a/mm/damon.c
+++ b/mm/damon.c
@@ -385,6 +385,17 @@ static void kdamond_split_regions(struct damon_ctx *ctx)
last_nr_regions = nr_regions;
}

+/*
+ * Check whether it is time to check and apply the target monitoring regions
+ *
+ * Returns true if it is.
+ */
+static bool kdamond_need_update_regions(struct damon_ctx *ctx)
+{
+ return damon_check_reset_time_interval(&ctx->last_regions_update,
+ ctx->regions_update_interval);
+}
+
/*
* Check whether current monitoring should be stopped
*
@@ -455,6 +466,12 @@ static int kdamond_fn(void *data)
kdamond_reset_aggregated(ctx);
kdamond_split_regions(ctx);
}
+
+ if (kdamond_need_update_regions(ctx)) {
+ if (ctx->update_target_regions)
+ ctx->update_target_regions(ctx);
+ sz_limit = damon_region_sz_limit(ctx);
+ }
}
damon_for_each_task(t, ctx) {
damon_for_each_region_safe(r, next, t)
@@ -562,6 +579,7 @@ int damon_set_pids(struct damon_ctx *ctx, int *pids, ssize_t nr_pids)
* damon_set_attrs() - Set attributes for the monitoring.
* @ctx: monitoring context
* @sample_int: time interval between samplings
+ * @regions_update_int: time interval between target regions update
* @aggr_int: time interval between aggregations
* @min_nr_reg: minimal number of regions
* @max_nr_reg: maximum number of regions
@@ -571,8 +589,8 @@ int damon_set_pids(struct damon_ctx *ctx, int *pids, ssize_t nr_pids)
*
* Return: 0 on success, negative error code otherwise.
*/
-int damon_set_attrs(struct damon_ctx *ctx,
- unsigned long sample_int, unsigned long aggr_int,
+int damon_set_attrs(struct damon_ctx *ctx, unsigned long sample_int,
+ unsigned long aggr_int, unsigned long regions_update_int,
unsigned long min_nr_reg, unsigned long max_nr_reg)
{
if (min_nr_reg < 3) {
@@ -588,6 +606,7 @@ int damon_set_attrs(struct damon_ctx *ctx,

ctx->sample_interval = sample_int;
ctx->aggr_interval = aggr_int;
+ ctx->regions_update_interval = regions_update_int;
ctx->min_nr_regions = min_nr_reg;
ctx->max_nr_regions = max_nr_reg;

--
2.17.1


2020-06-18 10:02:00

by Leonard Foerster

[permalink] [raw]
Subject: Re: [PATCH v16 05/14] mm/damon: Allow dynamic monitoring target regions update

On 2020-06-15T18:19:18+02:00 SeongJae Park <[email protected]> wrote:

> From: SeongJae Park <[email protected]>
>
> The monitoring target regions can be dynamically changed. For example,
> virtual memory mapping could be dynamically updated and physical memory
> could be hot-plugged.
>
> To handle such cases, this commit adds a monitoring attribute, ``regions
> update interval`` and a callback ``init_target_regions`` in the
> monitoring context. If the two fields are properly set, DAMON will call
> the ``init_target_regions()`` callback for every ``regions update
> interval``. In the callback, users can check current memory mapping or
> hotplugged physical memory sections and appropriately update the
> monitoring target regions of the context.
>
> Signed-off-by: SeongJae Park <[email protected]>
> ---

Reviewed-by: Leonard Foerster <[email protected]>