Remove the type-unclear target id concept
Subsystems (4)
SeongJae Park
maintainercover Remove the type-unclear target id concept
DAMON asks each monitoring target ('struct damon_target') to have one 'unsigned long' integer called 'id', which should be unique among the targets of same monitoring context. Meaning of it is, however, totally up to the monitoring primitives that registered to the monitoring context. For example, the virtual address spaces monitoring primitives treats the id as a 'struct pid' pointer.
This makes the code flexible but ugly, not well-documented, and type-unsafe[1]. Also, identification of each target can be done via its index. For the reason, this patchset removes the concept and uses clear type definition.
[1] https://lore.kernel.org/linux-mm/[email protected]/
SeongJae Park (4):
mm/damon/dbgfs/init_regions: Use target index instead of target id Docs/admin-guide/mm/damon/usage: Update for changed initail_regions
file input
mm/damon/core: Move damon_set_targets() into dbgfs mm/damon: Remove the target id concept
Documentation/admin-guide/mm/damon/usage.rst | 24 ++- include/linux/damon.h | 13 +- mm/damon/core-test.h | 21 +- mm/damon/core.c | 36 +--- mm/damon/dbgfs-test.h | 83 +++----- mm/damon/dbgfs.c | 202 ++++++++++++------- mm/damon/reclaim.c | 3 +- mm/damon/vaddr-test.h | 6 +- mm/damon/vaddr.c | 4 +- 9 files changed, 199 insertions(+), 193 deletions(-)
Signature · 1 line
2.17.1
SeongJae Park
maintainerPATCH 1/4 mm/damon/dbgfs/init_regions: Use target index instead of target id
Target id is a 'unsigned long' data, which can be interpreted differently by each monitoring primitives. For example, it means 'struct pid *' for the virtual address spaces monitoring, while it means nothing but an integer to be displayed to debugfs interface users for the physical address space monitoring. It's flexible but makes code ugly and type-unsafe[1].
To be prepared for eventual removal of the concept, this commit removes a use case of the concept in 'init_regions' debugfs file handling. In detail, this commit replaces use of the id with the index of each target in the context's targets list.
[1] https://lore.kernel.org/linux-mm/[email protected]/
--- mm/damon/dbgfs-test.h | 20 ++++++++++---------- mm/damon/dbgfs.c | 25 ++++++++++++------------- 2 files changed, 22 insertions(+), 23 deletions(-)
mm/damon/dbgfs-test.h +10 -10
@@ -113,19 +113,19 @@ static void damon_dbgfs_test_set_init_regions(struct kunit *test) {struct damon_ctx *ctx =damon_new_ctx ();unsigned long ids[] = {1 ,2 ,3 }; -/* Each line represents one region in ``<target id> <start> <end>`` */ -char *const valid_inputs[] = {"2 10 20\n 2 20 30\n2 35 45" , -"2 10 20\n" , -"2 10 20\n1 39 59\n1 70 134\n 2 20 25\n" , +/* Each line represents one region in ``<target idx> <start> <end>`` */ +char *const valid_inputs[] = {"1 10 20\n 1 20 30\n1 35 45" , +"1 10 20\n" , +"1 10 20\n0 39 59\n0 70 134\n 1 20 25\n" ,"" };/* Reading the file again will show sorted, clean output */ -char *const valid_expects[] = {"2 10 20\n2 20 30\n2 35 45\n" , -"2 10 20\n" , -"1 39 59\n1 70 134\n2 10 20\n2 20 25\n" , +char *const valid_expects[] = {"1 10 20\n1 20 30\n1 35 45\n" , +"1 10 20\n" , +"0 39 59\n0 70 134\n1 10 20\n1 20 25\n" ,"" }; -char *const invalid_inputs[] = {"4 10 20\n" ,/* target not exists */ -"2 10 20\n 2 14 26\n" ,/* regions overlap */ -"1 10 20\n2 30 40\n 1 5 8" };/* not sorted by address */ +char *const invalid_inputs[] = {"3 10 20\n" ,/* target not exists */ +"1 10 20\n 1 14 26\n" ,/* regions overlap */ +"0 10 20\n1 30 40\n 0 5 8" };/* not sorted by address */ char *input, *expect;int i, rc;char buf[256 ];
mm/damon/dbgfs.c +12 -13
@@ -440,18 +440,20 @@ static ssize_t sprint_init_regions(struct damon_ctx *c, char *buf, ssize_t len) {struct damon_target *t;struct damon_region *r; +int target_idx =0 ;int written =0 ;int rc;damon_for_each_target (t, c) {damon_for_each_region (r, t) { rc =scnprintf (&buf[written], len - written, -"%lu %lu %lu\n" , - t->id, r->ar.start, r->ar.end); +"%d %lu %lu\n" , + target_idx, r->ar.start, r->ar.end);if (!rc)return -ENOMEM ; written += rc; } + target_idx++; }return written; }
@@ -485,22 +487,19 @@ static ssize_t dbgfs_init_regions_read(struct file *file, char __user *buf,return len; } -static int add_init_region (struct damon_ctx *c, -unsigned long target_id,struct damon_addr_range *ar) +static int add_init_region (struct damon_ctx *c,int target_idx, +struct damon_addr_range *ar) {struct damon_target *t;struct damon_region *r, *prev; -unsigned long id; +unsigned long idx =0 ;int rc = -EINVAL ;if (ar->start >= ar->end)return -EINVAL ;damon_for_each_target (t, c) { - id = t->id; -if (targetid_is_pid (c)) - id = (unsigned long )pid_vnr ((struct pid *)id); -if (id == target_id) { +if (idx++ == target_idx) { r =damon_new_region (ar->start, ar->end);if (!r)return -ENOMEM ;
@@ -523,7 +522,7 @@ static int set_init_regions(struct damon_ctx *c, const char *str, ssize_t len)struct damon_target *t;struct damon_region *r, *next;int pos =0 , parsed, ret; -unsigned long target_id; +int target_idx;struct damon_addr_range ar;int err;
@@ -533,11 +532,11 @@ static int set_init_regions(struct damon_ctx *c, const char *str, ssize_t len) }while (pos < len) { - ret =sscanf (&str[pos],"%lu %lu %lu%n" , - &target_id, &ar.start, &ar.end, &parsed); + ret =sscanf (&str[pos],"%d %lu %lu%n" , + &target_idx, &ar.start, &ar.end, &parsed);if (ret !=3 )break ; - err =add_init_region (c, target_id, &ar); + err =add_init_region (c, target_idx, &ar);if (err) goto fail; pos += parsed;
Signature · 1 line
2.17.1
SeongJae Park
maintainerPATCH 2/4 Docs/admin-guide/mm/damon/usage: Update for changed initail_regions file input
In reply to SeongJae ParkA previous commit made init_regions debugfs file to use target index instead of target id for specifying the target of the init regions. This commit updates the usage document to reflect the change.
--- Documentation/admin-guide/mm/damon/usage.rst | 24 ++++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-)
Documentation/admin-guide/mm/damon/usage.rst +14 -10
@@ -108,19 +108,23 @@ In such cases, users can explicitly set the initial monitoring target regions as they want, by writing proper values to the ``init_regions`` file. Each line of the input should represent one region in below form.:: - <target id> <start address> <end address> + <target idx> <start address> <end address> -The ``target id`` should already in ``target_ids`` file, and the regions should -be passed in address order. For example, below commands will set a couple of -address ranges, ``1-100`` and ``100-200`` as the initial monitoring target -region of process 42, and another couple of address ranges, ``20-40`` and -``50-100`` as that of process 4242.:: +The ``target idx`` should be the index of the target in ``target_ids`` file, +starting from ``0``, and the regions should be passed in address order. For +example, below commands will set a couple of address ranges, ``1-100`` and +``100-200`` as the initial monitoring target region of pid 42, which is the +first one (index ``0``) in ``target_ids``, and another couple of address +ranges, ``20-40`` and ``50-100`` as that of pid 4242, which is the second one +(index ``1``) in ``target_ids``.:: # cd <debugfs>/damon - # echo "42 1 100 - 42 100 200 - 4242 20 40 - 4242 50 100" > init_regions + # cat target_ids + 42 4242 + # echo "0 1 100 + 0 100 200 + 1 20 40 + 1 50 100" > init_regions Note that this sets the initial monitoring target regions only. In case of virtual memory monitoring, DAMON will automatically updates the boundary of the
Signature · 1 line
2.17.1
SeongJae Park
maintainerPATCH 3/4 mm/damon/core: Move damon_set_targets() into dbgfs
In reply to SeongJae Parkdamon_set_targets() function is defined in the core for general use cases, but called from only dbgfs. Also, because the function is for general use cases, dbgfs does additional handling of pid type target id case. To make the situation simpler, this commit moves the function into dbgfs and makes it to do the pid type case handling on its own.
--- include/linux/damon.h | 2 -- mm/damon/core-test.h | 5 +++- mm/damon/core.c | 32 -------------------------- mm/damon/dbgfs-test.h | 14 ++++++------ mm/damon/dbgfs.c | 53 +++++++++++++++++++++++++++++++++---------- 5 files changed, 52 insertions(+), 54 deletions(-)
include/linux/damon.h +0 -2
@@ -484,8 +484,6 @@ unsigned int damon_nr_regions(struct damon_target *t);struct damon_ctx *damon_new_ctx (void );void damon_destroy_ctx (struct damon_ctx *ctx); -int damon_set_targets (struct damon_ctx *ctx, -unsigned long *ids,ssize_t nr_ids);int damon_set_attrs (struct damon_ctx *ctx,unsigned long sample_int,unsigned long aggr_int,unsigned long primitive_upd_int,unsigned long min_nr_reg,unsigned long max_nr_reg);
mm/damon/core-test.h +4 -1
@@ -86,7 +86,10 @@ static void damon_test_aggregate(struct kunit *test)struct damon_region *r;int it, ir; -damon_set_targets (ctx, target_ids,3 ); +for (it =0 ; it <3 ; it++) { + t =damon_new_target (target_ids[it]); +damon_add_target (ctx, t); + } it =0 ;damon_for_each_target (t, ctx) {
mm/damon/core.c +0 -32
@@ -245,38 +245,6 @@ void damon_destroy_ctx(struct damon_ctx *ctx)kfree (ctx); } -/** -* damon_set_targets() - Set monitoring targets. -* @ctx: monitoring context -* @ids: array of target ids -* @nr_ids: number of entries in @ids -* -* This function should not be called while the kdamond is running. -* -* Return: 0 on success, negative error code otherwise. -*/ -int damon_set_targets (struct damon_ctx *ctx, -unsigned long *ids,ssize_t nr_ids) -{ -ssize_t i; -struct damon_target *t, *next; - -damon_destroy_targets (ctx); - -for (i =0 ; i < nr_ids; i++) { - t =damon_new_target (ids[i]); -if (!t) { -/* The caller should do cleanup of the ids itself */ -damon_for_each_target_safe (t, next, ctx) -damon_destroy_target (t); -return -ENOMEM ; - } -damon_add_target (ctx, t); - } - -return 0 ; -} -/** * damon_set_attrs() - Set attributes for the monitoring. * @ctx: monitoring context
mm/damon/dbgfs-test.h +7 -7
@@ -86,23 +86,23 @@ static void damon_dbgfs_test_set_targets(struct kunit *test) ctx->primitive.target_valid =NULL ; ctx->primitive.cleanup =NULL ; -damon_set_targets (ctx, ids,3 ); +dbgfs_set_targets (ctx, ids,3 );sprint_target_ids (ctx, buf,64 );KUNIT_EXPECT_STREQ (test, (char *)buf,"1 2 3\n" ); -damon_set_targets (ctx,NULL ,0 ); +dbgfs_set_targets (ctx,NULL ,0 );sprint_target_ids (ctx, buf,64 );KUNIT_EXPECT_STREQ (test, (char *)buf,"\n" ); -damon_set_targets (ctx, (unsigned long []){1 ,2 },2 ); +dbgfs_set_targets (ctx, (unsigned long []){1 ,2 },2 );sprint_target_ids (ctx, buf,64 );KUNIT_EXPECT_STREQ (test, (char *)buf,"1 2\n" ); -damon_set_targets (ctx, (unsigned long []){2 },1 ); +dbgfs_set_targets (ctx, (unsigned long []){2 },1 );sprint_target_ids (ctx, buf,64 );KUNIT_EXPECT_STREQ (test, (char *)buf,"2\n" ); -damon_set_targets (ctx,NULL ,0 ); +dbgfs_set_targets (ctx,NULL ,0 );sprint_target_ids (ctx, buf,64 );KUNIT_EXPECT_STREQ (test, (char *)buf,"\n" );
@@ -130,7 +130,7 @@ static void damon_dbgfs_test_set_init_regions(struct kunit *test)int i, rc;char buf[256 ]; -damon_set_targets (ctx, ids,3 ); +dbgfs_set_targets (ctx, ids,3 );/* Put valid inputs and check the results */ for (i =0 ; i <ARRAY_SIZE (valid_inputs); i++) {
@@ -158,7 +158,7 @@ static void damon_dbgfs_test_set_init_regions(struct kunit *test)KUNIT_EXPECT_STREQ (test, (char *)buf,"" ); } -damon_set_targets (ctx,NULL ,0 ); +dbgfs_set_targets (ctx,NULL ,0 );damon_destroy_ctx (ctx); }
mm/damon/dbgfs.c +41 -12
76 lines not on this page · raw message
Signature · 1 line
2.17.1
SeongJae Park
maintainerPATCH 4/4 mm/damon: Remove the target id concept
In reply to SeongJae ParkDAMON asks each monitoring target ('struct damon_target') to have one 'unsigned long' integer called 'id', which should be unique among the targets of same monitoring context. Meaning of it is, however, totally up to the monitoring primitives that registered to the monitoring context. For example, the virtual address spaces monitoring primitives treats the id as a 'struct pid' pointer.
This makes the code flexible, but ugly, not well-documented, and type-unsafe[1]. Also, identification of each target can be done via its index. For the reason, this commit removes the concept and uses clear type definition. For now, only 'struct pid' pointer is used for the virtual address spaces monitoring. If DAMON is extended in future so that we need to put another identifier field in the struct, we will use a union for such primitives-dependent fields and document which primitives are using which type.
[1] https://lore.kernel.org/linux-mm/[email protected]/
--- include/linux/damon.h | 11 ++- mm/damon/core-test.h | 18 +++-- mm/damon/core.c | 4 +- mm/damon/dbgfs-test.h | 63 ++++++----------- mm/damon/dbgfs.c | 152 +++++++++++++++++++++++++----------------- mm/damon/reclaim.c | 3 +- mm/damon/vaddr-test.h | 6 +- mm/damon/vaddr.c | 4 +- 8 files changed, 133 insertions(+), 128 deletions(-)
include/linux/damon.h +5 -6
@@ -60,19 +60,18 @@ struct damon_region {/** * struct damon_target - Represents a monitoring target. -* @id: Unique identifier for this target. +* @pid: The PID of the virtual address space to monitor. * @nr_regions: Number of monitoring target regions of this target. * @regions_list: Head of the monitoring target regions of this target. * @list: List head for siblings. * * Each monitoring context could have multiple targets. For example, a context * for virtual memory address spaces could have multiple target processes. The -* @id of each target should be unique among the targets of the context. For -* example, in the virtual address monitoring context, it could be a pidfd or -* an address of an mm_struct. +* @pid should be set for appropriate address space monitoring primitives +* including the virtual address spaces monitoring primitives. */ struct damon_target { -unsigned long id; +struct pid *pid;unsigned int nr_regions;struct list_head regions_list;struct list_head list;
@@ -475,7 +474,7 @@ struct damos *damon_new_scheme(void damon_add_scheme (struct damon_ctx *ctx,struct damos *s);void damon_destroy_scheme (struct damos *s); -struct damon_target *damon_new_target (unsigned long id); +struct damon_target *damon_new_target (void );void damon_add_target (struct damon_ctx *ctx,struct damon_target *t);bool damon_targets_empty (struct damon_ctx *ctx);void damon_free_target (struct damon_target *t);
mm/damon/core-test.h +8 -10
@@ -24,7 +24,7 @@ static void damon_test_regions(struct kunit *test)KUNIT_EXPECT_EQ (test,2ul , r->ar.end);KUNIT_EXPECT_EQ (test,0u , r->nr_accesses); - t =damon_new_target (42 ); + t =damon_new_target ();KUNIT_EXPECT_EQ (test,0u ,damon_nr_regions (t));damon_add_region (r, t);
@@ -52,8 +52,7 @@ static void damon_test_target(struct kunit *test)struct damon_ctx *c =damon_new_ctx ();struct damon_target *t; - t =damon_new_target (42 ); -KUNIT_EXPECT_EQ (test,42ul , t->id); + t =damon_new_target ();KUNIT_EXPECT_EQ (test,0u ,nr_damon_targets (c));damon_add_target (c, t);
@@ -78,7 +77,6 @@ static void damon_test_target(struct kunit *test)static void damon_test_aggregate (struct kunit *test) {struct damon_ctx *ctx =damon_new_ctx (); -unsigned long target_ids[] = {1 ,2 ,3 };unsigned long saddr[][3 ] = {{10 ,20 ,30 }, {5 ,42 ,49 }, {13 ,33 ,55 } };unsigned long eaddr[][3 ] = {{15 ,27 ,40 }, {31 ,45 ,55 }, {23 ,44 ,66 } };unsigned long accesses[][3 ] = {{42 ,95 ,84 }, {10 ,20 ,30 }, {0 ,1 ,2 } };
@@ -87,7 +85,7 @@ static void damon_test_aggregate(struct kunit *test)int it, ir;for (it =0 ; it <3 ; it++) { - t =damon_new_target (target_ids[it]); + t =damon_new_target ();damon_add_target (ctx, t); }
@@ -125,7 +123,7 @@ static void damon_test_split_at(struct kunit *test)struct damon_target *t;struct damon_region *r; - t =damon_new_target (42 ); + t =damon_new_target (); r =damon_new_region (0 ,100 );damon_add_region (r, t);damon_split_region_at (c, t, r,25 );
@@ -146,7 +144,7 @@ static void damon_test_merge_two(struct kunit *test)struct damon_region *r, *r2, *r3;int i; - t =damon_new_target (42 ); + t =damon_new_target (); r =damon_new_region (0 ,100 ); r->nr_accesses =10 ;damon_add_region (r, t);
@@ -194,7 +192,7 @@ static void damon_test_merge_regions_of(struct kunit *test)unsigned long eaddrs[] = {112 ,130 ,156 ,170 ,230 };int i; - t =damon_new_target (42 ); + t =damon_new_target ();for (i =0 ; i <ARRAY_SIZE (sa); i++) { r =damon_new_region (sa[i], ea[i]); r->nr_accesses = nrs[i];
@@ -218,14 +216,14 @@ static void damon_test_split_regions_of(struct kunit *test)struct damon_target *t;struct damon_region *r; - t =damon_new_target (42 ); + t =damon_new_target (); r =damon_new_region (0 ,22 );damon_add_region (r, t);damon_split_regions_of (c, t,2 );KUNIT_EXPECT_LE (test,damon_nr_regions (t),2u );damon_free_target (t); - t =damon_new_target (42 ); + t =damon_new_target (); r =damon_new_region (0 ,220 );damon_add_region (r, t);damon_split_regions_of (c, t,4 );
mm/damon/core.c +2 -2
@@ -144,7 +144,7 @@ void damon_destroy_scheme(struct damos *s)* * Returns the pointer to the new struct if success, or NULL otherwise */ -struct damon_target *damon_new_target (unsigned long id) +struct damon_target *damon_new_target (void ) {struct damon_target *t;
@@ -152,7 +152,7 @@ struct damon_target *damon_new_target(unsigned long id)if (!t)return NULL ; - t->id = id; + t->pid =NULL ; t->nr_regions =0 ;INIT_LIST_HEAD (&t->regions_list);
mm/damon/dbgfs-test.h +22 -41
144 lines not on this page · raw message
mm/damon/dbgfs.c +90 -62
263 lines not on this page · raw message
mm/damon/reclaim.c +1 -2
@@ -387,8 +387,7 @@ static int __init damon_reclaim_init(void)damon_pa_set_primitives (ctx); ctx->callback.after_aggregation = damon_reclaim_after_aggregation; -/* 4242 means nothing but fun */ - target =damon_new_target (4242 ); + target =damon_new_target ();if (!target) {damon_destroy_ctx (ctx);return -ENOMEM ;
mm/damon/vaddr-test.h +3 -3
@@ -139,7 +139,7 @@ static void damon_do_test_apply_three_regions(struct kunit *test,struct damon_region *r;int i; - t =damon_new_target (42 ); + t =damon_new_target ();for (i =0 ; i < nr_regions /2 ; i++) { r =damon_new_region (regions[i *2 ], regions[i *2 +1 ]);damon_add_region (r, t);
@@ -251,7 +251,7 @@ static void damon_test_apply_three_regions4(struct kunit *test)static void damon_test_split_evenly_fail (struct kunit *test,unsigned long start,unsigned long end,unsigned int nr_pieces) { -struct damon_target *t =damon_new_target (42 ); +struct damon_target *t =damon_new_target ();struct damon_region *r =damon_new_region (start, end);damon_add_region (r, t);
@@ -270,7 +270,7 @@ static void damon_test_split_evenly_fail(struct kunit *test,static void damon_test_split_evenly_succ (struct kunit *test,unsigned long start,unsigned long end,unsigned int nr_pieces) { -struct damon_target *t =damon_new_target (42 ); +struct damon_target *t =damon_new_target ();struct damon_region *r =damon_new_region (start, end);unsigned long expected_width = (end - start) / nr_pieces;unsigned long i =0 ;
mm/damon/vaddr.c +2 -2
@@ -23,12 +23,12 @@#endif /* -* 't->id' should be the pointer to the relevant 'struct pid' having reference +* 't->pid' should be the pointer to the relevant 'struct pid' having reference * count. Caller must put the returned task, unless it is NULL. */ static inline struct task_struct *damon_get_task_struct (struct damon_target *t) { -return get_pid_task ((struct pid *)t->id,PIDTYPE_PID ); +return get_pid_task (t->pid,PIDTYPE_PID ); }/*
Signature · 1 line
2.17.1
Andrew Morton
maintainerQuoted 11 lines · On Thu, 30 Dec 2021 10:07:19 +0000 SeongJae Park <[email protected]> wrote:
DAMON asks each monitoring target ('struct
damon_target') to have one 'unsigned long' integer called 'id', which should be unique among the targets of same monitoring context. Meaning of it is, however, totally up to the monitoring primitives that registered to the monitoring context. For example, the virtual address spaces monitoring primitives treats the id as a 'struct pid' pointer.This makes the code flexible but ugly, not well-documented, and type-unsafe[1]. Also, identification of each target can be done via its index. For the reason, this patchset removes the concept and uses clear type definition.
Thanks. This doesn't appear to be urgent, so I'll park it until after 5.17-rc1.
SeongJae Park
maintainerQuoted 9 lines · On Thu, 30 Dec 2021 18:20:59 -0800 Andrew Morton <[email protected]>…
Quoted 7 lines · On Thu, 30 Dec 2021 10:07:19 +0000 SeongJae Park <[email protected]> wrote:
DAMON asks each monitoring target ('struct
damon_target') to have one 'unsigned long' integer called 'id', which should be unique among the targets of same monitoring context. Meaning of it is, however, totally up to the monitoring primitives that registered to the monitoring context. For example, the virtual address spaces monitoring primitives treats the id as a 'struct pid' pointer.
Quoted 6 lines
Quoted 4 lines
This makes the code flexible but ugly, not well-documented, and type-unsafe[1]. Also, identification of each target can be done via its index. For the reason, this patchset removes the concept and uses clear type definition.
Thanks. This doesn't appear to be urgent, so I'll park it until after 5.17-rc1.
Just for a remind. I confirmed this patchset is cleanly applicable on the latest -next tree.
Thanks,
SJ