From patchwork Wed Dec 16 08:43:57 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: SeongJae Park X-Patchwork-Id: 11976959 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-18.8 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0D6ADC4361B for ; Wed, 16 Dec 2020 08:45:17 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id 6C9F522D74 for ; Wed, 16 Dec 2020 08:45:16 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 6C9F522D74 Authentication-Results: mail.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=amazon.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=owner-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix) id B54186B006C; Wed, 16 Dec 2020 03:45:15 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id ADEE06B006E; Wed, 16 Dec 2020 03:45:15 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 9A5F86B0070; Wed, 16 Dec 2020 03:45:15 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0067.hostedemail.com [216.40.44.67]) by kanga.kvack.org (Postfix) with ESMTP id 7D0576B006C for ; Wed, 16 Dec 2020 03:45:15 -0500 (EST) Received: from smtpin06.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay03.hostedemail.com (Postfix) with ESMTP id 3CEB78249980 for ; Wed, 16 Dec 2020 08:45:15 +0000 (UTC) X-FDA: 77598510990.06.dirt28_50114412742a Received: from filter.hostedemail.com (10.5.16.251.rfc1918.com [10.5.16.251]) by smtpin06.hostedemail.com (Postfix) with ESMTP id 13C5B1004585F for ; Wed, 16 Dec 2020 08:45:15 +0000 (UTC) X-HE-Tag: dirt28_50114412742a X-Filterd-Recvd-Size: 7289 Received: from smtp-fw-6001.amazon.com (smtp-fw-6001.amazon.com [52.95.48.154]) by imf03.hostedemail.com (Postfix) with ESMTP for ; Wed, 16 Dec 2020 08:45:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.com; i=@amazon.com; q=dns/txt; s=amazon201209; t=1608108315; x=1639644315; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=cOxYOEllcijsLZUfhIOYA9Vz+qn1GS/GHh4VdpbMXkM=; b=DWMkvYT8DmHtd2ubzJjbxtN2BRaCFL5be8y272EAodfMOcvCsGTkulii hfGk/oNF/k9o6vNO/OsfIrbMV/HecLFPv/IAI+Mj+DDO5IWFVaJQ26wIe Ug89Zi+izzSE4ugO61UPg1wSs6UON7H7LDwdZdK7GtW9ZVAr/5kSDiLFF 8=; X-IronPort-AV: E=Sophos;i="5.78,424,1599523200"; d="scan'208";a="72992221" Received: from iad12-co-svc-p1-lb1-vlan2.amazon.com (HELO email-inbound-relay-1d-98acfc19.us-east-1.amazon.com) ([10.43.8.2]) by smtp-border-fw-out-6001.iad6.amazon.com with ESMTP; 16 Dec 2020 08:45:07 +0000 Received: from EX13D31EUA001.ant.amazon.com (iad12-ws-svc-p26-lb9-vlan3.iad.amazon.com [10.40.163.38]) by email-inbound-relay-1d-98acfc19.us-east-1.amazon.com (Postfix) with ESMTPS id 15BF7A1FD4; Wed, 16 Dec 2020 08:44:54 +0000 (UTC) Received: from u3f2cd687b01c55.ant.amazon.com (10.43.161.102) by EX13D31EUA001.ant.amazon.com (10.43.165.15) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 16 Dec 2020 08:44:38 +0000 From: SeongJae Park To: CC: SeongJae Park , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [RFC v15.1 1/8] mm/damon/core: Account age of target regions Date: Wed, 16 Dec 2020 09:43:57 +0100 Message-ID: <20201216084404.23183-2-sjpark@amazon.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201216084404.23183-1-sjpark@amazon.com> References: <20201216084404.23183-1-sjpark@amazon.com> MIME-Version: 1.0 X-Originating-IP: [10.43.161.102] X-ClientProxiedBy: EX13D22UWB003.ant.amazon.com (10.43.161.76) To EX13D31EUA001.ant.amazon.com (10.43.165.15) X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: From: SeongJae Park DAMON can be used for data access pattern aware memory management optimizations. For that, users should run DAMON, read the monitoring results, analyze it, plan a new memory management scheme, and apply the new scheme by themselves. It would not be too hard, but still require some level of effort. For complicated cases, this effort is inevitable. That said, in many cases, users would simply want to apply an actions to a memory region of a specific size having a specific access frequency for a specific time. For example, "page out a memory region larger than 100 MiB but having a low access frequency more than 10 minutes", or "Use THP for a memory region larger than 2 MiB having a high access frequency for more than 2 seconds". For such optimizations, users will need to first account the age of each region themselves. To reduce such efforts, this commit implements a simple age account of each region in DAMON. For each aggregation step, DAMON compares the access frequency with that from last aggregation and reset the age of the region if the change is significant. Else, the age is incremented. Also, in case of the merge of regions, the region size-weighted average of the ages is set as the age of merged new region. Signed-off-by: SeongJae Park --- include/linux/damon.h | 10 ++++++++++ mm/damon/core.c | 13 +++++++++++++ 2 files changed, 23 insertions(+) diff --git a/include/linux/damon.h b/include/linux/damon.h index f9e0d4349352..ca7b7e8a0025 100644 --- a/include/linux/damon.h +++ b/include/linux/damon.h @@ -31,12 +31,22 @@ struct damon_addr_range { * @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 { struct damon_addr_range ar; unsigned long sampling_addr; unsigned int nr_accesses; struct list_head list; + + unsigned int age; + unsigned int last_nr_accesses; }; /** diff --git a/mm/damon/core.c b/mm/damon/core.c index 214ff404a423..c4d4114a7545 100644 --- a/mm/damon/core.c +++ b/mm/damon/core.c @@ -45,6 +45,9 @@ struct damon_region *damon_new_region(unsigned long start, unsigned long end) region->nr_accesses = 0; INIT_LIST_HEAD(®ion->list); + region->age = 0; + region->last_nr_accesses = 0; + return region; } @@ -439,6 +442,7 @@ static void kdamond_reset_aggregated(struct damon_ctx *c) damon_for_each_region(r, t) { trace_damon_aggregated(t, r, damon_nr_regions(t)); + r->last_nr_accesses = r->nr_accesses; r->nr_accesses = 0; } } @@ -456,6 +460,7 @@ static void damon_merge_two_regions(struct damon_region *l, 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->ar.end = r->ar.end; damon_destroy_region(r); } @@ -475,6 +480,11 @@ static void damon_merge_regions_of(struct damon_target *t, unsigned int thres, struct damon_region *r, *prev = NULL, *next; damon_for_each_region_safe(r, next, t) { + if (diff_of(r->nr_accesses, r->last_nr_accesses) > thres) + r->age = 0; + else + r->age++; + if (prev && prev->ar.end == r->ar.start && diff_of(prev->nr_accesses, r->nr_accesses) <= thres && sz_damon_region(prev) + sz_damon_region(r) <= sz_limit) @@ -518,6 +528,9 @@ static void damon_split_region_at(struct damon_ctx *ctx, new = damon_new_region(r->ar.start + sz_r, r->ar.end); r->ar.end = new->ar.start; + new->age = r->age; + new->last_nr_accesses = r->last_nr_accesses; + damon_insert_region(new, r, damon_next_region(r)); } From patchwork Wed Dec 16 08:43:58 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: SeongJae Park X-Patchwork-Id: 11976961 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-18.8 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 445B4C4361B for ; Wed, 16 Dec 2020 08:45:38 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id 8E93023102 for ; Wed, 16 Dec 2020 08:45:37 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 8E93023102 Authentication-Results: mail.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=amazon.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=owner-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix) id D9F358D0001; Wed, 16 Dec 2020 03:45:36 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id D27B46B0070; Wed, 16 Dec 2020 03:45:36 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id BEF878D0001; Wed, 16 Dec 2020 03:45:36 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0205.hostedemail.com [216.40.44.205]) by kanga.kvack.org (Postfix) with ESMTP id A683D6B006E for ; Wed, 16 Dec 2020 03:45:36 -0500 (EST) Received: from smtpin11.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay04.hostedemail.com (Postfix) with ESMTP id 650291EF2 for ; Wed, 16 Dec 2020 08:45:36 +0000 (UTC) X-FDA: 77598511872.11.use23_1003d702742a Received: from filter.hostedemail.com (10.5.16.251.rfc1918.com [10.5.16.251]) by smtpin11.hostedemail.com (Postfix) with ESMTP id 3D814180F8B81 for ; Wed, 16 Dec 2020 08:45:36 +0000 (UTC) X-HE-Tag: use23_1003d702742a X-Filterd-Recvd-Size: 15884 Received: from smtp-fw-2101.amazon.com (smtp-fw-2101.amazon.com [72.21.196.25]) by imf01.hostedemail.com (Postfix) with ESMTP for ; Wed, 16 Dec 2020 08:45:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.com; i=@amazon.com; q=dns/txt; s=amazon201209; t=1608108336; x=1639644336; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=Jh1GeMiDiW29T6qmjTgFrT97lJiNa591imO1+4f9rYY=; b=X2sBC3QdF5zsl4NvyhzX78kMp4ARfY99uc3jdQox5BeWbD4u/mXfRqR1 S+5x2BkyvnjCfFeqR5bHy5RKzZIWaXxT89F5CiPG/eUWHp/XlnROkHLnY t6wKQOPjKpfJxyQhAQ4NKiRLfw6WR5UdtLbUXBOqxwLrS7XI+4RsEr5Jq E=; X-IronPort-AV: E=Sophos;i="5.78,424,1599523200"; d="scan'208";a="69433180" Received: from iad12-co-svc-p1-lb1-vlan3.amazon.com (HELO email-inbound-relay-1e-42f764a0.us-east-1.amazon.com) ([10.43.8.6]) by smtp-border-fw-out-2101.iad2.amazon.com with ESMTP; 16 Dec 2020 08:45:28 +0000 Received: from EX13D31EUA001.ant.amazon.com (iad12-ws-svc-p26-lb9-vlan2.iad.amazon.com [10.40.163.34]) by email-inbound-relay-1e-42f764a0.us-east-1.amazon.com (Postfix) with ESMTPS id CAC92E0E42; Wed, 16 Dec 2020 08:45:15 +0000 (UTC) Received: from u3f2cd687b01c55.ant.amazon.com (10.43.161.102) by EX13D31EUA001.ant.amazon.com (10.43.165.15) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 16 Dec 2020 08:44:59 +0000 From: SeongJae Park To: CC: SeongJae Park , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [RFC v15.1 2/8] mm/damon/core: Implement DAMON-based Operation Schemes (DAMOS) Date: Wed, 16 Dec 2020 09:43:58 +0100 Message-ID: <20201216084404.23183-3-sjpark@amazon.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201216084404.23183-1-sjpark@amazon.com> References: <20201216084404.23183-1-sjpark@amazon.com> MIME-Version: 1.0 X-Originating-IP: [10.43.161.102] X-ClientProxiedBy: EX13D22UWB003.ant.amazon.com (10.43.161.76) To EX13D31EUA001.ant.amazon.com (10.43.165.15) X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: From: SeongJae Park In many cases, users might use DAMON for simple data access aware memory management optimizations such as applying an operation scheme to a memory region of a specific size having a specific access frequency for a specific time. For example, "page out a memory region larger than 100 MiB but having a low access frequency more than 10 minutes", or "Use THP for a memory region larger than 2 MiB having a high access frequency for more than 2 seconds". Most simple form of the solution would be doing offline data access pattern profiling using DAMON and modifying the application source code or system configuration based on the profiling results. Or, developing a daemon constructed with two modules (one for access monitoring and the other for applying memory management actions via mlock(), madvise(), sysctl, etc) is imaginable. To avoid users spending their time for implementation of such simple data access monitoring-based operation schemes, this commit makes DAMON to handle such schemes directly. With this commit, users can simply specify their desired schemes to DAMON. Then, DAMON will automatically apply the schemes to the user-specified target processes. Each of the schemes is composed with conditions for filtering of the target memory regions and desired memory management action for the target. Specifically, the format is:: The filtering conditions are size of memory region, number of accesses to the region monitored by DAMON, and the age of the region. The age of region is incremented periodically but reset when its addresses or access frequency has significantly changed or the action of a scheme was applied. For the action, current implementation supports a few of madvise()-like hints, ``WILLNEED``, ``COLD``, ``PAGEOUT``, ``HUGEPAGE``, and ``NOHUGEPAGE``. Because DAMON supports various address spaces and application of the actions to a monitoring target region is dependent to the type of the target address space, the application code should be implemented by each primitives and registered to the framework. Note that this commit only implements the framework part. Following commit will implement the action applications for virtual address spaces primitives. Signed-off-by: SeongJae Park --- include/linux/damon.h | 72 ++++++++++++++++++++++++++-- mm/damon/core.c | 107 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 176 insertions(+), 3 deletions(-) diff --git a/include/linux/damon.h b/include/linux/damon.h index ca7b7e8a0025..cfcd399da134 100644 --- a/include/linux/damon.h +++ b/include/linux/damon.h @@ -67,6 +67,48 @@ struct damon_target { struct list_head list; }; +/** + * enum damos_action - Represents an action of a Data Access Monitoring-based + * Operation Scheme. + * + * @DAMOS_WILLNEED: Call ``madvise()`` for the region with MADV_WILLNEED. + * @DAMOS_COLD: Call ``madvise()`` for the region with MADV_COLD. + * @DAMOS_PAGEOUT: Call ``madvise()`` for the region with MADV_PAGEOUT. + * @DAMOS_HUGEPAGE: Call ``madvise()`` for the region with MADV_HUGEPAGE. + * @DAMOS_NOHUGEPAGE: Call ``madvise()`` for the region with MADV_NOHUGEPAGE. + */ +enum damos_action { + DAMOS_WILLNEED, + DAMOS_COLD, + DAMOS_PAGEOUT, + DAMOS_HUGEPAGE, + DAMOS_NOHUGEPAGE, +}; + +/** + * struct damos - Represents a Data Access Monitoring-based Operation Scheme. + * @min_sz_region: Minimum size of target regions. + * @max_sz_region: Maximum size of target regions. + * @min_nr_accesses: Minimum ``->nr_accesses`` of target regions. + * @max_nr_accesses: Maximum ``->nr_accesses`` of target regions. + * @min_age_region: Minimum age of target regions. + * @max_age_region: Maximum age of target regions. + * @action: &damo_action to be applied to the target regions. + * @list: List head for siblings. + * + * Note that both the minimums and the maximums are inclusive. + */ +struct damos { + unsigned long min_sz_region; + unsigned long max_sz_region; + unsigned int min_nr_accesses; + unsigned int max_nr_accesses; + unsigned int min_age_region; + unsigned int max_age_region; + enum damos_action action; + struct list_head list; +}; + struct damon_ctx; /** @@ -77,6 +119,7 @@ struct damon_ctx; * @prepare_access_checks: Prepares next access check of target regions. * @check_accesses: Checks the access of target regions. * @reset_aggregated: Resets aggregated accesses monitoring results. + * @apply_scheme: Apply a DAMON-based operation scheme. * @target_valid: Determine if the target is valid. * @cleanup: Cleans up the context. * @@ -103,6 +146,9 @@ struct damon_ctx; * of its update. * @reset_aggregated should reset the access monitoring results that aggregated * by @check_accesses. + * @apply_scheme is called from @kdamond when a region for user provided + * DAMON-based operation scheme is found. It should apply the scheme's action + * to the region. This is not used for &DAMON_ARBITRARY_TARGET case. * @target_valid should check whether the target is still valid for the * monitoring. It receives &damon_ctx.arbitrary_target or &struct damon_target * pointer depends on &damon_ctx.target_type. @@ -115,6 +161,8 @@ struct damon_primitive { void (*prepare_access_checks)(struct damon_ctx *context); unsigned int (*check_accesses)(struct damon_ctx *context); void (*reset_aggregated)(struct damon_ctx *context); + int (*apply_scheme)(struct damon_ctx *context, struct damon_target *t, + struct damon_region *r, struct damos *scheme); bool (*target_valid)(void *target); void (*cleanup)(struct damon_ctx *context); }; @@ -205,12 +253,13 @@ enum damon_target_type { * @min_nr_regions: The minimum number of adaptive monitoring regions. * @max_nr_regions: The maximum number of adaptive monitoring regions. * @adaptive_targets: Head of monitoring targets (&damon_target) list. + * @schemes: Head of schemes (&damos) list. * * @arbitrary_target: Pointer to arbitrary type target. * - * @min_nr_regions, @max_nr_regions and @adaptive_targets are valid only if - * @target_type is &DAMON_ADAPTIVE_TARGET. @arbitrary_target is valid only if - * @target_type is &DAMON_ARBITRARY_TARGET. + * @min_nr_regions, @max_nr_regions, @adaptive_targets and @schemes are valid + * only if @target_type is &DAMON_ADAPTIVE_TARGET. @arbitrary_target is valid + * only if @target_type is &DAMON_ARBITRARY_TARGET. */ struct damon_ctx { unsigned long sample_interval; @@ -235,6 +284,7 @@ struct damon_ctx { unsigned long min_nr_regions; unsigned long max_nr_regions; struct list_head adaptive_targets; + struct list_head schemes; }; void *arbitrary_target; /* DAMON_ARBITRARY_TARGET */ @@ -259,6 +309,12 @@ struct damon_ctx { #define damon_for_each_target_safe(t, next, ctx) \ list_for_each_entry_safe(t, next, &(ctx)->adaptive_targets, list) +#define damon_for_each_scheme(s, ctx) \ + list_for_each_entry(s, &(ctx)->schemes, list) + +#define damon_for_each_scheme_safe(s, next, ctx) \ + list_for_each_entry_safe(s, next, &(ctx)->schemes, list) + #ifdef CONFIG_DAMON struct damon_region *damon_new_region(unsigned long start, unsigned long end); @@ -267,6 +323,14 @@ inline void damon_insert_region(struct damon_region *r, void damon_add_region(struct damon_region *r, struct damon_target *t); void damon_destroy_region(struct damon_region *r); +struct damos *damon_new_scheme( + unsigned long min_sz_region, unsigned long max_sz_region, + unsigned int min_nr_accesses, unsigned int max_nr_accesses, + unsigned int min_age_region, unsigned int max_age_region, + enum damos_action action); +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); void damon_add_target(struct damon_ctx *ctx, struct damon_target *t); void damon_free_target(struct damon_target *t); @@ -280,6 +344,8 @@ int damon_set_targets(struct damon_ctx *ctx, 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_set_schemes(struct damon_ctx *ctx, + struct damos **schemes, ssize_t nr_schemes); int damon_nr_running_ctxs(void); int damon_start(struct damon_ctx **ctxs, int nr_ctxs); diff --git a/mm/damon/core.c b/mm/damon/core.c index c4d4114a7545..a4d33970ba4c 100644 --- a/mm/damon/core.c +++ b/mm/damon/core.c @@ -81,6 +81,50 @@ void damon_destroy_region(struct damon_region *r) damon_free_region(r); } +struct damos *damon_new_scheme( + unsigned long min_sz_region, unsigned long max_sz_region, + unsigned int min_nr_accesses, unsigned int max_nr_accesses, + unsigned int min_age_region, unsigned int max_age_region, + enum damos_action action) +{ + struct damos *scheme; + + scheme = kmalloc(sizeof(*scheme), GFP_KERNEL); + if (!scheme) + return NULL; + scheme->min_sz_region = min_sz_region; + scheme->max_sz_region = max_sz_region; + scheme->min_nr_accesses = min_nr_accesses; + scheme->max_nr_accesses = max_nr_accesses; + scheme->min_age_region = min_age_region; + scheme->max_age_region = max_age_region; + scheme->action = action; + INIT_LIST_HEAD(&scheme->list); + + return scheme; +} + +void damon_add_scheme(struct damon_ctx *ctx, struct damos *s) +{ + list_add_tail(&s->list, &ctx->schemes); +} + +static void damon_del_scheme(struct damos *s) +{ + list_del(&s->list); +} + +static void damon_free_scheme(struct damos *s) +{ + kfree(s); +} + +void damon_destroy_scheme(struct damos *s) +{ + damon_del_scheme(s); + damon_free_scheme(s); +} + /* * Construct a damon_target struct * @@ -159,6 +203,7 @@ struct damon_ctx *damon_new_ctx(enum damon_target_type type) ctx->max_nr_regions = 1000; INIT_LIST_HEAD(&ctx->adaptive_targets); + INIT_LIST_HEAD(&ctx->schemes); } return ctx; @@ -167,10 +212,14 @@ struct damon_ctx *damon_new_ctx(enum damon_target_type type) void damon_destroy_ctx(struct damon_ctx *ctx) { struct damon_target *t, *next_t; + struct damos *s, *next_s; damon_for_each_target_safe(t, next_t, ctx) damon_destroy_target(t); + damon_for_each_scheme_safe(s, next_s, ctx) + damon_destroy_scheme(s); + kfree(ctx); } @@ -245,6 +294,30 @@ int damon_set_attrs(struct damon_ctx *ctx, unsigned long sample_int, return 0; } +/** + * damon_set_schemes() - Set data access monitoring based operation schemes. + * @ctx: monitoring context + * @schemes: array of the schemes + * @nr_schemes: number of entries in @schemes + * + * This function should not be called while the kdamond of the context is + * running. + * + * Return: 0 if success, or negative error code otherwise. + */ +int damon_set_schemes(struct damon_ctx *ctx, struct damos **schemes, + ssize_t nr_schemes) +{ + struct damos *s, *next; + ssize_t i; + + damon_for_each_scheme_safe(s, next, ctx) + damon_destroy_scheme(s); + for (i = 0; i < nr_schemes; i++) + damon_add_scheme(ctx, schemes[i]); + return 0; +} + /** * damon_nr_running_ctxs() - Return number of currently running contexts. */ @@ -448,6 +521,39 @@ static void kdamond_reset_aggregated(struct damon_ctx *c) } } +static void damon_do_apply_schemes(struct damon_ctx *c, + struct damon_target *t, + struct damon_region *r) +{ + struct damos *s; + unsigned long sz; + + damon_for_each_scheme(s, c) { + sz = r->ar.end - r->ar.start; + if (sz < s->min_sz_region || s->max_sz_region < sz) + continue; + if (r->nr_accesses < s->min_nr_accesses || + s->max_nr_accesses < r->nr_accesses) + continue; + if (r->age < s->min_age_region || s->max_age_region < r->age) + continue; + if (c->primitive.apply_scheme) + c->primitive.apply_scheme(c, t, r, s); + r->age = 0; + } +} + +static void kdamond_apply_schemes(struct damon_ctx *c) +{ + struct damon_target *t; + struct damon_region *r; + + damon_for_each_target(t, c) { + damon_for_each_region(r, t) + damon_do_apply_schemes(c, t, r); + } +} + #define sz_damon_region(r) (r->ar.end - r->ar.start) /* @@ -689,6 +795,7 @@ static int kdamond_fn(void *data) ctx->callback.after_aggregation(ctx)) set_kdamond_stop(ctx); if (ctx->target_type != DAMON_ARBITRARY_TARGET) { + kdamond_apply_schemes(ctx); kdamond_reset_aggregated(ctx); kdamond_split_regions(ctx); } From patchwork Wed Dec 16 08:43:59 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: SeongJae Park X-Patchwork-Id: 11976963 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-18.8 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3B774C4361B for ; Wed, 16 Dec 2020 08:45:48 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id ACCEE208DB for ; Wed, 16 Dec 2020 08:45:47 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org ACCEE208DB Authentication-Results: mail.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=amazon.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=owner-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix) id 3DCA16B006E; Wed, 16 Dec 2020 03:45:47 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 38A596B0070; Wed, 16 Dec 2020 03:45:47 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 279DB6B0071; Wed, 16 Dec 2020 03:45:47 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0215.hostedemail.com [216.40.44.215]) by kanga.kvack.org (Postfix) with ESMTP id 0E80E6B006E for ; Wed, 16 Dec 2020 03:45:47 -0500 (EST) Received: from smtpin14.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay04.hostedemail.com (Postfix) with ESMTP id CED0F1F06 for ; Wed, 16 Dec 2020 08:45:46 +0000 (UTC) X-FDA: 77598512292.14.run54_1a0ba8d2742a Received: from filter.hostedemail.com (10.5.16.251.rfc1918.com [10.5.16.251]) by smtpin14.hostedemail.com (Postfix) with ESMTP id ADC7418229818 for ; Wed, 16 Dec 2020 08:45:46 +0000 (UTC) X-HE-Tag: run54_1a0ba8d2742a X-Filterd-Recvd-Size: 6568 Received: from smtp-fw-6002.amazon.com (smtp-fw-6002.amazon.com [52.95.49.90]) by imf03.hostedemail.com (Postfix) with ESMTP for ; Wed, 16 Dec 2020 08:45:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.com; i=@amazon.com; q=dns/txt; s=amazon201209; t=1608108347; x=1639644347; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=d5Dwu12G70RPXtr6ZcK3mCRob0N4SZzNNQ50Ho7aEBg=; b=JSY25dMUQwigjVp0oUpPIbiHHiggCTJKFpJYFqg0eyQBQuc1RJTad+EK TgY8CJP7uJXsAhHsu3xFO5j3XpfsQROpnCLssjp1ijyXOlWCMNhu6vNqM +2vCfNeE8dh5WWL0Axn6FqY5A5UGhOcwz80Cr+0butTOJP/rd5e90D7PH Y=; X-IronPort-AV: E=Sophos;i="5.78,424,1599523200"; d="scan'208";a="71553003" Received: from iad12-co-svc-p1-lb1-vlan2.amazon.com (HELO email-inbound-relay-1a-67b371d8.us-east-1.amazon.com) ([10.43.8.2]) by smtp-border-fw-out-6002.iad6.amazon.com with ESMTP; 16 Dec 2020 08:45:46 +0000 Received: from EX13D31EUA001.ant.amazon.com (iad12-ws-svc-p26-lb9-vlan3.iad.amazon.com [10.40.163.38]) by email-inbound-relay-1a-67b371d8.us-east-1.amazon.com (Postfix) with ESMTPS id E8813A1E86; Wed, 16 Dec 2020 08:45:33 +0000 (UTC) Received: from u3f2cd687b01c55.ant.amazon.com (10.43.161.102) by EX13D31EUA001.ant.amazon.com (10.43.165.15) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 16 Dec 2020 08:45:17 +0000 From: SeongJae Park To: CC: SeongJae Park , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [RFC v15.1 3/8] mm/damon/vaddr: Support DAMON-based Operation Schemes Date: Wed, 16 Dec 2020 09:43:59 +0100 Message-ID: <20201216084404.23183-4-sjpark@amazon.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201216084404.23183-1-sjpark@amazon.com> References: <20201216084404.23183-1-sjpark@amazon.com> MIME-Version: 1.0 X-Originating-IP: [10.43.161.102] X-ClientProxiedBy: EX13D22UWB003.ant.amazon.com (10.43.161.76) To EX13D31EUA001.ant.amazon.com (10.43.165.15) X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: From: SeongJae Park This commit makes DAMON's default primitives for virtual address spaces to support DAMON-based Operation Schemes (DAMOS) by implementing actions application functions and registering it to the monitoring context. The implementation simply links 'madvise()' for related DAMOS actions. That is, 'madvise(MADV_WILLNEED)' is called for 'WILLNEED' DAMOS action and similar for other actions ('COLD', 'PAGEOUT', 'HUGEPAGE', 'NOHUGEPAGE'). So, the kernel space DAMON users can now use the DAMON-based optimizations with only small amount of code. Signed-off-by: SeongJae Park --- include/linux/damon.h | 2 ++ mm/damon/vaddr.c | 56 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/include/linux/damon.h b/include/linux/damon.h index cfcd399da134..8988238cb29e 100644 --- a/include/linux/damon.h +++ b/include/linux/damon.h @@ -362,6 +362,8 @@ void damon_va_prepare_access_checks(struct damon_ctx *ctx); unsigned int damon_va_check_accesses(struct damon_ctx *ctx); bool damon_va_target_valid(void *t); void damon_va_cleanup(struct damon_ctx *ctx); +int damon_va_apply_scheme(struct damon_ctx *context, struct damon_target *t, + struct damon_region *r, struct damos *scheme); void damon_va_set_primitives(struct damon_ctx *ctx); #endif /* CONFIG_DAMON_VADDR */ diff --git a/mm/damon/vaddr.c b/mm/damon/vaddr.c index 8ee48a4abc17..ebf4720c057a 100644 --- a/mm/damon/vaddr.c +++ b/mm/damon/vaddr.c @@ -7,6 +7,7 @@ #define pr_fmt(fmt) "damon-va: " fmt +#include #include #include #include @@ -572,6 +573,60 @@ void damon_va_cleanup(struct damon_ctx *ctx) } } +#ifndef CONFIG_ADVISE_SYSCALLS +static int damos_madvise(struct damon_target *target, struct damon_region *r, + int behavior) +{ + return -EINVAL; +} +#else +static int damos_madvise(struct damon_target *target, struct damon_region *r, + int behavior) +{ + struct mm_struct *mm; + int ret = -ENOMEM; + + mm = damon_get_mm(target); + if (!mm) + goto out; + + ret = do_madvise(mm, PAGE_ALIGN(r->ar.start), + PAGE_ALIGN(r->ar.end - r->ar.start), behavior); + mmput(mm); +out: + return ret; +} +#endif /* CONFIG_ADVISE_SYSCALLS */ + +int damon_va_apply_scheme(struct damon_ctx *ctx, struct damon_target *t, + struct damon_region *r, struct damos *scheme) +{ + int madv_action; + + switch (scheme->action) { + case DAMOS_WILLNEED: + madv_action = MADV_WILLNEED; + break; + case DAMOS_COLD: + madv_action = MADV_COLD; + break; + case DAMOS_PAGEOUT: + madv_action = MADV_PAGEOUT; + break; + case DAMOS_HUGEPAGE: + madv_action = MADV_HUGEPAGE; + break; + case DAMOS_NOHUGEPAGE: + madv_action = MADV_NOHUGEPAGE; + break; + default: + pr_warn("Wrong action %d\n", scheme->action); + return -EINVAL; + } + + return damos_madvise(t, r, madv_action); +} + void damon_va_set_primitives(struct damon_ctx *ctx) { ctx->primitive.init_target_regions = damon_va_init_regions; @@ -581,6 +636,7 @@ void damon_va_set_primitives(struct damon_ctx *ctx) ctx->primitive.reset_aggregated = NULL; ctx->primitive.target_valid = damon_va_target_valid; ctx->primitive.cleanup = damon_va_cleanup; + ctx->primitive.apply_scheme = damon_va_apply_scheme; } #include "vaddr-test.h" From patchwork Wed Dec 16 08:44:00 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: SeongJae Park X-Patchwork-Id: 11976965 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-18.8 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1FC58C4361B for ; Wed, 16 Dec 2020 08:46:15 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id 9FB3B207BC for ; Wed, 16 Dec 2020 08:46:14 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 9FB3B207BC Authentication-Results: mail.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=amazon.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=owner-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix) id 190066B005D; Wed, 16 Dec 2020 03:46:14 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 13FB66B0070; Wed, 16 Dec 2020 03:46:14 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 02E8A6B0071; Wed, 16 Dec 2020 03:46:13 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0184.hostedemail.com [216.40.44.184]) by kanga.kvack.org (Postfix) with ESMTP id D9F486B005D for ; Wed, 16 Dec 2020 03:46:13 -0500 (EST) Received: from smtpin01.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay05.hostedemail.com (Postfix) with ESMTP id 9CD00181AEF1D for ; Wed, 16 Dec 2020 08:46:13 +0000 (UTC) X-FDA: 77598513426.01.sheet26_3d0b3432742a Received: from filter.hostedemail.com (10.5.16.251.rfc1918.com [10.5.16.251]) by smtpin01.hostedemail.com (Postfix) with ESMTP id 6E48D1004EF56 for ; Wed, 16 Dec 2020 08:46:13 +0000 (UTC) X-HE-Tag: sheet26_3d0b3432742a X-Filterd-Recvd-Size: 8571 Received: from smtp-fw-33001.amazon.com (smtp-fw-33001.amazon.com [207.171.190.10]) by imf35.hostedemail.com (Postfix) with ESMTP for ; Wed, 16 Dec 2020 08:46:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.com; i=@amazon.com; q=dns/txt; s=amazon201209; t=1608108373; x=1639644373; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=AbHpAGQAnrRMIFfbdBebCNKso7ZqXpgX9fMoeo77wAo=; b=WoT/57AQ9GaQyz/7jJi5qSLgPC+kPsYFyDYRiZXVIzbbmezsRG+BV9uA iPMWZMc9lq99I/W0sP99WRYDrp4feCJxs7xVyEVvUF4dpbid7qSoIJdgF A7Bw64tX+yV1R2AyortLmFtHB2X12Ajc0pMdpd6A/aCARI/7xbaL0f5zh 8=; X-IronPort-AV: E=Sophos;i="5.78,424,1599523200"; d="scan'208";a="103481045" Received: from sea32-co-svc-lb4-vlan3.sea.corp.amazon.com (HELO email-inbound-relay-1d-e69428c4.us-east-1.amazon.com) ([10.47.23.38]) by smtp-border-fw-out-33001.sea14.amazon.com with ESMTP; 16 Dec 2020 08:46:02 +0000 Received: from EX13D31EUA001.ant.amazon.com (iad12-ws-svc-p26-lb9-vlan2.iad.amazon.com [10.40.163.34]) by email-inbound-relay-1d-e69428c4.us-east-1.amazon.com (Postfix) with ESMTPS id 4F3A0C1E2C; Wed, 16 Dec 2020 08:45:50 +0000 (UTC) Received: from u3f2cd687b01c55.ant.amazon.com (10.43.161.102) by EX13D31EUA001.ant.amazon.com (10.43.165.15) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 16 Dec 2020 08:45:34 +0000 From: SeongJae Park To: CC: SeongJae Park , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [RFC v15.1 4/8] mm/damon/dbgfs: Support DAMON-based Operation Schemes Date: Wed, 16 Dec 2020 09:44:00 +0100 Message-ID: <20201216084404.23183-5-sjpark@amazon.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201216084404.23183-1-sjpark@amazon.com> References: <20201216084404.23183-1-sjpark@amazon.com> MIME-Version: 1.0 X-Originating-IP: [10.43.161.102] X-ClientProxiedBy: EX13D22UWB003.ant.amazon.com (10.43.161.76) To EX13D31EUA001.ant.amazon.com (10.43.165.15) X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: From: SeongJae Park This commit makes 'damon-dbgfs' to support the data access monitoring oriented memory management schemes. Users can read and update the schemes using ``/damon/schemes`` file. The format is:: Signed-off-by: SeongJae Park --- mm/damon/dbgfs.c | 169 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 165 insertions(+), 4 deletions(-) diff --git a/mm/damon/dbgfs.c b/mm/damon/dbgfs.c index 7380c6502f3d..10ce8e8786cb 100644 --- a/mm/damon/dbgfs.c +++ b/mm/damon/dbgfs.c @@ -219,6 +219,159 @@ static ssize_t dbgfs_record_write(struct file *file, return ret; } +static ssize_t sprint_schemes(struct damon_ctx *c, char *buf, ssize_t len) +{ + struct damos *s; + int written = 0; + int rc; + + damon_for_each_scheme(s, c) { + rc = scnprintf(&buf[written], len - written, + "%lu %lu %u %u %u %u %d\n", + s->min_sz_region, s->max_sz_region, + s->min_nr_accesses, s->max_nr_accesses, + s->min_age_region, s->max_age_region, + s->action); + if (!rc) + return -ENOMEM; + + written += rc; + } + return written; +} + +static ssize_t dbgfs_schemes_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct damon_ctx *ctx = file->private_data; + char *kbuf; + ssize_t len; + + kbuf = kmalloc(count, GFP_KERNEL); + if (!kbuf) + return -ENOMEM; + + mutex_lock(&ctx->kdamond_lock); + len = sprint_schemes(ctx, kbuf, count); + mutex_unlock(&ctx->kdamond_lock); + if (len < 0) + goto out; + len = simple_read_from_buffer(buf, count, ppos, kbuf, len); + +out: + kfree(kbuf); + return len; +} + +static void free_schemes_arr(struct damos **schemes, ssize_t nr_schemes) +{ + ssize_t i; + + for (i = 0; i < nr_schemes; i++) + kfree(schemes[i]); + kfree(schemes); +} + +static bool damos_action_valid(int action) +{ + switch (action) { + case DAMOS_WILLNEED: + case DAMOS_COLD: + case DAMOS_PAGEOUT: + case DAMOS_HUGEPAGE: + case DAMOS_NOHUGEPAGE: + return true; + default: + return false; + } +} + +/* + * Converts a string into an array of struct damos pointers + * + * Returns an array of struct damos pointers that converted if the conversion + * success, or NULL otherwise. + */ +static struct damos **str_to_schemes(const char *str, ssize_t len, + ssize_t *nr_schemes) +{ + struct damos *scheme, **schemes; + const int max_nr_schemes = 256; + int pos = 0, parsed, ret; + unsigned long min_sz, max_sz; + unsigned int min_nr_a, max_nr_a, min_age, max_age; + unsigned int action; + + schemes = kmalloc_array(max_nr_schemes, sizeof(scheme), + GFP_KERNEL); + if (!schemes) + return NULL; + + *nr_schemes = 0; + while (pos < len && *nr_schemes < max_nr_schemes) { + ret = sscanf(&str[pos], "%lu %lu %u %u %u %u %u%n", + &min_sz, &max_sz, &min_nr_a, &max_nr_a, + &min_age, &max_age, &action, &parsed); + if (ret != 7) + break; + if (!damos_action_valid(action)) { + pr_err("wrong action %d\n", action); + goto fail; + } + + pos += parsed; + scheme = damon_new_scheme(min_sz, max_sz, min_nr_a, max_nr_a, + min_age, max_age, action); + if (!scheme) + goto fail; + + schemes[*nr_schemes] = scheme; + *nr_schemes += 1; + } + return schemes; +fail: + free_schemes_arr(schemes, *nr_schemes); + return NULL; +} + +static ssize_t dbgfs_schemes_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct damon_ctx *ctx = file->private_data; + char *kbuf; + struct damos **schemes; + ssize_t nr_schemes = 0, ret = count; + int err; + + kbuf = user_input_str(buf, count, ppos); + if (IS_ERR(kbuf)) + return PTR_ERR(kbuf); + + schemes = str_to_schemes(kbuf, ret, &nr_schemes); + if (!schemes) { + ret = -EINVAL; + goto out; + } + + mutex_lock(&ctx->kdamond_lock); + if (ctx->kdamond) { + ret = -EBUSY; + goto unlock_out; + } + + err = damon_set_schemes(ctx, schemes, nr_schemes); + if (err) + ret = err; + else + nr_schemes = 0; +unlock_out: + mutex_unlock(&ctx->kdamond_lock); + free_schemes_arr(schemes, nr_schemes); +out: + kfree(kbuf); + return ret; +} + #define targetid_is_pid(ctx) \ (ctx->primitive.target_valid == damon_va_target_valid) @@ -385,6 +538,13 @@ static const struct file_operations record_fops = { .write = dbgfs_record_write, }; +static const struct file_operations schemes_fops = { + .owner = THIS_MODULE, + .open = damon_dbgfs_open, + .read = dbgfs_schemes_read, + .write = dbgfs_schemes_write, +}; + static const struct file_operations target_ids_fops = { .owner = THIS_MODULE, .open = damon_dbgfs_open, @@ -400,10 +560,11 @@ static const struct file_operations kdamond_pid_fops = { static int dbgfs_fill_ctx_dir(struct dentry *dir, struct damon_ctx *ctx) { - const char * const file_names[] = {"attrs", "record", "target_ids", - "kdamond_pid"}; - const struct file_operations *fops[] = {&attrs_fops, &record_fops, - &target_ids_fops, &kdamond_pid_fops}; + const char * const file_names[] = {"attrs", "record", "schemes", + "target_ids", "kdamond_pid"}; + const struct file_operations *fops[] = {&attrs_fops, + &record_fops, &schemes_fops, &target_ids_fops, + &kdamond_pid_fops}; int i; for (i = 0; i < ARRAY_SIZE(file_names); i++) { From patchwork Wed Dec 16 08:44:01 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: SeongJae Park X-Patchwork-Id: 11976967 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-18.8 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4E570C4361B for ; Wed, 16 Dec 2020 08:46:29 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id C474023104 for ; Wed, 16 Dec 2020 08:46:28 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org C474023104 Authentication-Results: mail.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=amazon.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=owner-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix) id 4C36B6B006C; Wed, 16 Dec 2020 03:46:28 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 472D56B0070; Wed, 16 Dec 2020 03:46:28 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 363A26B0071; Wed, 16 Dec 2020 03:46:28 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0178.hostedemail.com [216.40.44.178]) by kanga.kvack.org (Postfix) with ESMTP id 20AB46B006C for ; Wed, 16 Dec 2020 03:46:28 -0500 (EST) Received: from smtpin13.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay01.hostedemail.com (Postfix) with ESMTP id E1C66180AD81D for ; Wed, 16 Dec 2020 08:46:27 +0000 (UTC) X-FDA: 77598514014.13.money89_2b0864d2742a Received: from filter.hostedemail.com (10.5.16.251.rfc1918.com [10.5.16.251]) by smtpin13.hostedemail.com (Postfix) with ESMTP id BCCF118140B69 for ; Wed, 16 Dec 2020 08:46:27 +0000 (UTC) X-HE-Tag: money89_2b0864d2742a X-Filterd-Recvd-Size: 7980 Received: from smtp-fw-4101.amazon.com (smtp-fw-4101.amazon.com [72.21.198.25]) by imf02.hostedemail.com (Postfix) with ESMTP for ; Wed, 16 Dec 2020 08:46:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.com; i=@amazon.com; q=dns/txt; s=amazon201209; t=1608108387; x=1639644387; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=XjeBo2gMgqfsA58xk8AYpaU10qYvS6C/KzZVyieNY3A=; b=YuV+35iQ5wmsm3clT4hQOlpWkXyFZ3uJzvZA9wR+d8SjA+qBC4d6+bJZ J8GoQoJh3PYdrZl4opaJ/cRz1XT+4GjyLfY1mV++5TLD3AFEP7xLNAa86 qCCfwihPUV3KfmkaE0q0i/wdiezMHqwxx1xJnzvGuKU0bIPnjbQVNnWqO I=; X-IronPort-AV: E=Sophos;i="5.78,424,1599523200"; d="scan'208";a="69693730" Received: from iad12-co-svc-p1-lb1-vlan2.amazon.com (HELO email-inbound-relay-1d-2c665b5d.us-east-1.amazon.com) ([10.43.8.2]) by smtp-border-fw-out-4101.iad4.amazon.com with ESMTP; 16 Dec 2020 08:46:19 +0000 Received: from EX13D31EUA001.ant.amazon.com (iad12-ws-svc-p26-lb9-vlan3.iad.amazon.com [10.40.163.38]) by email-inbound-relay-1d-2c665b5d.us-east-1.amazon.com (Postfix) with ESMTPS id DB1C6A1CE0; Wed, 16 Dec 2020 08:46:06 +0000 (UTC) Received: from u3f2cd687b01c55.ant.amazon.com (10.43.161.102) by EX13D31EUA001.ant.amazon.com (10.43.165.15) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 16 Dec 2020 08:45:50 +0000 From: SeongJae Park To: CC: SeongJae Park , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [RFC v15.1 5/8] mm/damon/schemes: Implement statistics feature Date: Wed, 16 Dec 2020 09:44:01 +0100 Message-ID: <20201216084404.23183-6-sjpark@amazon.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201216084404.23183-1-sjpark@amazon.com> References: <20201216084404.23183-1-sjpark@amazon.com> MIME-Version: 1.0 X-Originating-IP: [10.43.161.102] X-ClientProxiedBy: EX13D22UWB003.ant.amazon.com (10.43.161.76) To EX13D31EUA001.ant.amazon.com (10.43.165.15) X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: From: SeongJae Park To tune the DAMON-based operation schemes, knowing how many and how large regions are affected by each of the schemes will be helful. Those stats could be used for not only the tuning, but also monitoring of the working set size and the number of regions, if the scheme does not change the program behavior too much. For the reason, this commit implements the statistics for the schemes. The total number and size of the regions that each scheme is applied are exported to users via '->stat_count' and '->stat_sz' of 'struct damos'. Admins can also check the number by reading 'schemes' debugfs file. The last two integers now represents the stats. To allow collecting the stats without changing the program behavior, this commit also adds new scheme action, 'DAMOS_STAT'. Note that 'DAMOS_STAT' is not only making no memory operation actions, but also does not reset the age of regions. Signed-off-by: SeongJae Park --- include/linux/damon.h | 10 +++++++++- mm/damon/core.c | 7 ++++++- mm/damon/dbgfs.c | 5 +++-- mm/damon/vaddr.c | 2 ++ 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/include/linux/damon.h b/include/linux/damon.h index 8988238cb29e..ed7e86207e53 100644 --- a/include/linux/damon.h +++ b/include/linux/damon.h @@ -76,6 +76,7 @@ struct damon_target { * @DAMOS_PAGEOUT: Call ``madvise()`` for the region with MADV_PAGEOUT. * @DAMOS_HUGEPAGE: Call ``madvise()`` for the region with MADV_HUGEPAGE. * @DAMOS_NOHUGEPAGE: Call ``madvise()`` for the region with MADV_NOHUGEPAGE. + * @DAMOS_STAT: Do nothing but count the stat. */ enum damos_action { DAMOS_WILLNEED, @@ -83,6 +84,7 @@ enum damos_action { DAMOS_PAGEOUT, DAMOS_HUGEPAGE, DAMOS_NOHUGEPAGE, + DAMOS_STAT, /* Do nothing but only record the stat */ }; /** @@ -94,9 +96,13 @@ enum damos_action { * @min_age_region: Minimum age of target regions. * @max_age_region: Maximum age of target regions. * @action: &damo_action to be applied to the target regions. + * @stat_count: Total number of regions that this scheme is applied. + * @stat_sz: Total size of regions that this scheme is applied. * @list: List head for siblings. * - * Note that both the minimums and the maximums are inclusive. + * For each aggregation interval, DAMON applies @action to monitoring target + * regions fit in the condition and updates the statistics. Note that both + * the minimums and the maximums are inclusive. */ struct damos { unsigned long min_sz_region; @@ -106,6 +112,8 @@ struct damos { unsigned int min_age_region; unsigned int max_age_region; enum damos_action action; + unsigned long stat_count; + unsigned long stat_sz; struct list_head list; }; diff --git a/mm/damon/core.c b/mm/damon/core.c index a4d33970ba4c..e339b79b23c7 100644 --- a/mm/damon/core.c +++ b/mm/damon/core.c @@ -99,6 +99,8 @@ struct damos *damon_new_scheme( scheme->min_age_region = min_age_region; scheme->max_age_region = max_age_region; scheme->action = action; + scheme->stat_count = 0; + scheme->stat_sz = 0; INIT_LIST_HEAD(&scheme->list); return scheme; @@ -537,9 +539,12 @@ static void damon_do_apply_schemes(struct damon_ctx *c, continue; if (r->age < s->min_age_region || s->max_age_region < r->age) continue; + s->stat_count++; + s->stat_sz += sz; if (c->primitive.apply_scheme) c->primitive.apply_scheme(c, t, r, s); - r->age = 0; + if (s->action != DAMOS_STAT) + r->age = 0; } } diff --git a/mm/damon/dbgfs.c b/mm/damon/dbgfs.c index 10ce8e8786cb..06295c986dc3 100644 --- a/mm/damon/dbgfs.c +++ b/mm/damon/dbgfs.c @@ -227,11 +227,11 @@ static ssize_t sprint_schemes(struct damon_ctx *c, char *buf, ssize_t len) damon_for_each_scheme(s, c) { rc = scnprintf(&buf[written], len - written, - "%lu %lu %u %u %u %u %d\n", + "%lu %lu %u %u %u %u %d %lu %lu\n", s->min_sz_region, s->max_sz_region, s->min_nr_accesses, s->max_nr_accesses, s->min_age_region, s->max_age_region, - s->action); + s->action, s->stat_count, s->stat_sz); if (!rc) return -ENOMEM; @@ -280,6 +280,7 @@ static bool damos_action_valid(int action) case DAMOS_PAGEOUT: case DAMOS_HUGEPAGE: case DAMOS_NOHUGEPAGE: + case DAMOS_STAT: return true; default: return false; diff --git a/mm/damon/vaddr.c b/mm/damon/vaddr.c index ebf4720c057a..2075f07f728b 100644 --- a/mm/damon/vaddr.c +++ b/mm/damon/vaddr.c @@ -619,6 +619,8 @@ int damon_va_apply_scheme(struct damon_ctx *ctx, struct damon_target *t, case DAMOS_NOHUGEPAGE: madv_action = MADV_NOHUGEPAGE; break; + case DAMOS_STAT: + return 0; default: pr_warn("Wrong action %d\n", scheme->action); return -EINVAL; From patchwork Wed Dec 16 08:44:02 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: SeongJae Park X-Patchwork-Id: 11976969 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-18.8 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 98582C4361B for ; Wed, 16 Dec 2020 08:46:38 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id 0993A230FA for ; Wed, 16 Dec 2020 08:46:37 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 0993A230FA Authentication-Results: mail.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=amazon.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=owner-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix) id 5FCE86B0070; Wed, 16 Dec 2020 03:46:37 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 5ACA86B0071; Wed, 16 Dec 2020 03:46:37 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 44E6E6B0072; Wed, 16 Dec 2020 03:46:37 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0248.hostedemail.com [216.40.44.248]) by kanga.kvack.org (Postfix) with ESMTP id 28AFF6B0070 for ; Wed, 16 Dec 2020 03:46:37 -0500 (EST) Received: from smtpin24.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay01.hostedemail.com (Postfix) with ESMTP id E5708180AD820 for ; Wed, 16 Dec 2020 08:46:36 +0000 (UTC) X-FDA: 77598514392.24.bells98_520b9212742a Received: from filter.hostedemail.com (10.5.16.251.rfc1918.com [10.5.16.251]) by smtpin24.hostedemail.com (Postfix) with ESMTP id CDB351A4A0 for ; Wed, 16 Dec 2020 08:46:36 +0000 (UTC) X-HE-Tag: bells98_520b9212742a X-Filterd-Recvd-Size: 4268 Received: from smtp-fw-9101.amazon.com (smtp-fw-9101.amazon.com [207.171.184.25]) by imf45.hostedemail.com (Postfix) with ESMTP for ; Wed, 16 Dec 2020 08:46:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.com; i=@amazon.com; q=dns/txt; s=amazon201209; t=1608108396; x=1639644396; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=y54T24GyHij+L4YlC4ErOhrawn7/T9RzI2P4TOBHFCI=; b=MJj39BUo3oUp6YfMGPXJ9ygT/Jt0TkBPOzm15F/7zM2TKz/lQCcSXxiD wPTXVE6Y66Tsmk2RsO+ufNJTyUuwm1VlXM0rHn6JWXDfUmqRs0ovNGDgM qo+2LYmuAzmJN9GZquUKQpILae1mprQNsNejJAWRnEFvlyStnU9jtGpv9 k=; X-IronPort-AV: E=Sophos;i="5.78,424,1599523200"; d="scan'208";a="96460580" Received: from sea32-co-svc-lb4-vlan3.sea.corp.amazon.com (HELO email-inbound-relay-1d-474bcd9f.us-east-1.amazon.com) ([10.47.23.38]) by smtp-border-fw-out-9101.sea19.amazon.com with ESMTP; 16 Dec 2020 08:46:26 +0000 Received: from EX13D31EUA001.ant.amazon.com (iad12-ws-svc-p26-lb9-vlan2.iad.amazon.com [10.40.163.34]) by email-inbound-relay-1d-474bcd9f.us-east-1.amazon.com (Postfix) with ESMTPS id 67F5DA1890; Wed, 16 Dec 2020 08:46:23 +0000 (UTC) Received: from u3f2cd687b01c55.ant.amazon.com (10.43.161.102) by EX13D31EUA001.ant.amazon.com (10.43.165.15) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 16 Dec 2020 08:46:06 +0000 From: SeongJae Park To: CC: SeongJae Park , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [RFC v15.1 6/8] selftests/damon: Add 'schemes' debugfs tests Date: Wed, 16 Dec 2020 09:44:02 +0100 Message-ID: <20201216084404.23183-7-sjpark@amazon.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201216084404.23183-1-sjpark@amazon.com> References: <20201216084404.23183-1-sjpark@amazon.com> MIME-Version: 1.0 X-Originating-IP: [10.43.161.102] X-ClientProxiedBy: EX13D22UWB003.ant.amazon.com (10.43.161.76) To EX13D31EUA001.ant.amazon.com (10.43.165.15) X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: From: SeongJae Park This commit adds simple selftets for 'schemes' debugfs file of DAMON. Signed-off-by: SeongJae Park --- .../testing/selftests/damon/debugfs_attrs.sh | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tools/testing/selftests/damon/debugfs_attrs.sh b/tools/testing/selftests/damon/debugfs_attrs.sh index c75557e8ba58..61fd3e5598e9 100755 --- a/tools/testing/selftests/damon/debugfs_attrs.sh +++ b/tools/testing/selftests/damon/debugfs_attrs.sh @@ -97,6 +97,35 @@ fi echo $ORIG_CONTENT > $file +# Test schemes file +file="$DBGFS/schemes" + +ORIG_CONTENT=$(cat $file) +echo "1 2 3 4 5 6 3" > $file +if [ $? -ne 0 ] +then + echo "$file write fail" + echo $ORIG_CONTENT > $file + exit 1 +fi + +echo "1 2 +3 4 5 6 3" > $file +if [ $? -eq 0 ] +then + echo "$file multi line write success (expected fail)" + echo $ORIG_CONTENT > $file + exit 1 +fi + +echo > $file +if [ $? -ne 0 ] +then + echo "$file empty string writing fail" + echo $ORIG_CONTENT > $file + exit 1 +fi + # Test target_ids file file="$DBGFS/target_ids" From patchwork Wed Dec 16 08:44:03 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: SeongJae Park X-Patchwork-Id: 11976971 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-18.8 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7A2D2C4361B for ; Wed, 16 Dec 2020 08:46:56 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id ECE78207BC for ; Wed, 16 Dec 2020 08:46:55 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org ECE78207BC Authentication-Results: mail.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=amazon.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=owner-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix) id 4E9FF6B0071; Wed, 16 Dec 2020 03:46:55 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 49BCF8D0003; Wed, 16 Dec 2020 03:46:55 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 3628C8D0002; Wed, 16 Dec 2020 03:46:55 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0125.hostedemail.com [216.40.44.125]) by kanga.kvack.org (Postfix) with ESMTP id 193936B0071 for ; Wed, 16 Dec 2020 03:46:55 -0500 (EST) Received: from smtpin17.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay02.hostedemail.com (Postfix) with ESMTP id C2AB4362A for ; Wed, 16 Dec 2020 08:46:54 +0000 (UTC) X-FDA: 77598515148.17.heart28_2f0b0282742a Received: from filter.hostedemail.com (10.5.16.251.rfc1918.com [10.5.16.251]) by smtpin17.hostedemail.com (Postfix) with ESMTP id A9FF7180D0197 for ; Wed, 16 Dec 2020 08:46:54 +0000 (UTC) X-HE-Tag: heart28_2f0b0282742a X-Filterd-Recvd-Size: 17646 Received: from smtp-fw-9102.amazon.com (smtp-fw-9102.amazon.com [207.171.184.29]) by imf42.hostedemail.com (Postfix) with ESMTP for ; Wed, 16 Dec 2020 08:46:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.com; i=@amazon.com; q=dns/txt; s=amazon201209; t=1608108414; x=1639644414; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=czGye8axcUyfOtwbxYSRSPH9eKKo4KKk+rXiw8OIDcw=; b=kMumnAdICq5aG2MhsKrx7u7jrQzTLH5Oo4vaGldo56mJqGcY85HtvkOy dGA9SJi/67RPwMGRTimRgcSn5XS7GjnSWDX5pgMW8eroGvJ7RqoYS3AdU qEBFEZQbuxwFzsRffBxDpkWjoki78dxaJ/J1/gGocfmjOEE8bi//ohhHN w=; X-IronPort-AV: E=Sophos;i="5.78,424,1599523200"; d="scan'208";a="104752585" Received: from sea32-co-svc-lb4-vlan3.sea.corp.amazon.com (HELO email-inbound-relay-1d-474bcd9f.us-east-1.amazon.com) ([10.47.23.38]) by smtp-border-fw-out-9102.sea19.amazon.com with ESMTP; 16 Dec 2020 08:46:43 +0000 Received: from EX13D31EUA001.ant.amazon.com (iad12-ws-svc-p26-lb9-vlan2.iad.amazon.com [10.40.163.34]) by email-inbound-relay-1d-474bcd9f.us-east-1.amazon.com (Postfix) with ESMTPS id 67F5BA1A79; Wed, 16 Dec 2020 08:46:40 +0000 (UTC) Received: from u3f2cd687b01c55.ant.amazon.com (10.43.161.102) by EX13D31EUA001.ant.amazon.com (10.43.165.15) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 16 Dec 2020 08:46:24 +0000 From: SeongJae Park To: CC: SeongJae Park , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [RFC v15.1 7/8] tools/damon: Support more human friendly 'schemes' control Date: Wed, 16 Dec 2020 09:44:03 +0100 Message-ID: <20201216084404.23183-8-sjpark@amazon.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201216084404.23183-1-sjpark@amazon.com> References: <20201216084404.23183-1-sjpark@amazon.com> MIME-Version: 1.0 X-Originating-IP: [10.43.161.102] X-ClientProxiedBy: EX13D22UWB003.ant.amazon.com (10.43.161.76) To EX13D31EUA001.ant.amazon.com (10.43.165.15) X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: From: SeongJae Park This commit implements 'schemes' subcommand of the damon userspace tool. It can be used to describe and apply the data access monitoring-based operation schemes in more human friendly fashion. Signed-off-by: SeongJae Park --- tools/damon/_convert_damos.py | 141 ++++++++++++++++++++++++++++++++++ tools/damon/_damon.py | 28 +++++-- tools/damon/damo | 7 ++ tools/damon/schemes.py | 110 ++++++++++++++++++++++++++ 4 files changed, 280 insertions(+), 6 deletions(-) create mode 100755 tools/damon/_convert_damos.py create mode 100644 tools/damon/schemes.py diff --git a/tools/damon/_convert_damos.py b/tools/damon/_convert_damos.py new file mode 100755 index 000000000000..0fd84b3701c9 --- /dev/null +++ b/tools/damon/_convert_damos.py @@ -0,0 +1,141 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0 + +""" +Change human readable data access monitoring-based operation schemes to the low +level input for the '/damon/schemes' file. Below is an example of the +schemes written in the human readable format: + + # format is: + # + # + # B/K/M/G/T for Bytes/KiB/MiB/GiB/TiB + # us/ms/s/m/h/d for micro-seconds/milli-seconds/seconds/minutes/hours/days + # 'min/max' for possible min/max value. + + # if a region keeps a high access frequency for >=100ms, put the region on + # the head of the LRU list (call madvise() with MADV_WILLNEED). + min max 80 max 100ms max willneed + + # if a region keeps a low access frequency for >=200ms and <=one hour, put + # the region on the tail of the LRU list (call madvise() with MADV_COLD). + min max 10 20 200ms 1h cold + + # if a region keeps a very low access frequency for >=60 seconds, swap out + # the region immediately (call madvise() with MADV_PAGEOUT). + min max 0 10 60s max pageout + + # if a region of a size >=2MiB keeps a very high access frequency for + # >=100ms, let the region to use huge pages (call madvise() with + # MADV_HUGEPAGE). + 2M max 90 100 100ms max hugepage + + # If a regions of a size >=2MiB keeps small access frequency for >=100ms, + # avoid the region using huge pages (call madvise() with MADV_NOHUGEPAGE). + 2M max 0 25 100ms max nohugepage +""" + +import argparse +import platform + +uint_max = 2**32 - 1 +ulong_max = 2**64 - 1 +if platform.architecture()[0] != '64bit': + ulong_max = 2**32 - 1 + +unit_to_bytes = {'B': 1, 'K': 1024, 'M': 1024 * 1024, 'G': 1024 * 1024 * 1024, + 'T': 1024 * 1024 * 1024 * 1024} + +def text_to_bytes(txt): + if txt == 'min': + return 0 + if txt == 'max': + return ulong_max + + unit = txt[-1] + number = float(txt[:-1]) + return int(number * unit_to_bytes[unit]) + +unit_to_usecs = {'us': 1, 'ms': 1000, 's': 1000 * 1000, 'm': 60 * 1000 * 1000, + 'h': 60 * 60 * 1000 * 1000, 'd': 24 * 60 * 60 * 1000 * 1000} + +def text_to_aggr_intervals(txt, aggr_interval): + if txt == 'min': + return 0 + if txt == 'max': + return uint_max + + unit = txt[-2:] + if unit in ['us', 'ms']: + number = float(txt[:-2]) + else: + unit = txt[-1] + number = float(txt[:-1]) + return int(number * unit_to_usecs[unit]) / aggr_interval + +damos_action_to_int = {'DAMOS_WILLNEED': 0, 'DAMOS_COLD': 1, + 'DAMOS_PAGEOUT': 2, 'DAMOS_HUGEPAGE': 3, 'DAMOS_NOHUGEPAGE': 4, + 'DAMOS_STAT': 5} + +def text_to_damos_action(txt): + return damos_action_to_int['DAMOS_' + txt.upper()] + +def text_to_nr_accesses(txt, max_nr_accesses): + if txt == 'min': + return 0 + if txt == 'max': + return max_nr_accesses + + return int(float(txt) * max_nr_accesses / 100) + +def debugfs_scheme(line, sample_interval, aggr_interval): + fields = line.split() + if len(fields) != 7: + print('wrong input line: %s' % line) + exit(1) + + limit_nr_accesses = aggr_interval / sample_interval + try: + min_sz = text_to_bytes(fields[0]) + max_sz = text_to_bytes(fields[1]) + min_nr_accesses = text_to_nr_accesses(fields[2], limit_nr_accesses) + max_nr_accesses = text_to_nr_accesses(fields[3], limit_nr_accesses) + min_age = text_to_aggr_intervals(fields[4], aggr_interval) + max_age = text_to_aggr_intervals(fields[5], aggr_interval) + action = text_to_damos_action(fields[6]) + except: + print('wrong input field') + raise + return '%d\t%d\t%d\t%d\t%d\t%d\t%d' % (min_sz, max_sz, min_nr_accesses, + max_nr_accesses, min_age, max_age, action) + +def convert(schemes_file, sample_interval, aggr_interval): + lines = [] + with open(schemes_file, 'r') as f: + for line in f: + if line.startswith('#'): + continue + line = line.strip() + if line == '': + continue + lines.append(debugfs_scheme(line, sample_interval, aggr_interval)) + return '\n'.join(lines) + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('input', metavar='', + help='input file describing the schemes') + parser.add_argument('-s', '--sample', metavar='', type=int, + default=5000, help='sampling interval (us)') + parser.add_argument('-a', '--aggr', metavar='', type=int, + default=100000, help='aggregation interval (us)') + args = parser.parse_args() + + schemes_file = args.input + sample_interval = args.sample + aggr_interval = args.aggr + + print(convert(schemes_file, sample_interval, aggr_interval)) + +if __name__ == '__main__': + main() diff --git a/tools/damon/_damon.py b/tools/damon/_damon.py index 1f6a292e8c25..a4f6c03c23e4 100644 --- a/tools/damon/_damon.py +++ b/tools/damon/_damon.py @@ -10,6 +10,7 @@ import subprocess debugfs_attrs = None debugfs_record = None +debugfs_schemes = None debugfs_target_ids = None debugfs_monitor_on = None @@ -33,8 +34,9 @@ class Attrs: max_nr_regions = None rbuf_len = None rfile_path = None + schemes = None - def __init__(self, s, a, r, n, x, l, f): + def __init__(self, s, a, r, n, x, l, f, c): self.sample_interval = s self.aggr_interval = a self.regions_update_interval = r @@ -42,12 +44,13 @@ class Attrs: self.max_nr_regions = x self.rbuf_len = l self.rfile_path = f + self.schemes = c def __str__(self): - return "%s %s %s %s %s %s %s" % (self.sample_interval, + return "%s %s %s %s %s %s %s\n%s" % (self.sample_interval, self.aggr_interval, self.regions_update_interval, self.min_nr_regions, self.max_nr_regions, self.rbuf_len, - self.rfile_path) + self.rfile_path, self.schemes) def attr_str(self): return "%s %s %s %s %s " % (self.sample_interval, self.aggr_interval, @@ -66,6 +69,9 @@ class Attrs: debugfs_record), shell=True, executable='/bin/bash') if ret: return ret + return subprocess.call('echo %s > %s' % ( + self.schemes.replace('\n', ' '), debugfs_schemes), shell=True, + executable='/bin/bash') def current_attrs(): with open(debugfs_attrs, 'r') as f: @@ -77,17 +83,26 @@ def current_attrs(): attrs.append(int(rattrs[0])) attrs.append(rattrs[1]) + with open(debugfs_schemes, 'r') as f: + schemes = f.read() + + # The last two fields in each line are statistics. Remove those. + schemes = [' '.join(x.split()[:-2]) for x in schemes.strip().split('\n')] + attrs.append('\n'.join(schemes)) + return Attrs(*attrs) def chk_update_debugfs(debugfs): global debugfs_attrs global debugfs_record + global debugfs_schemes global debugfs_target_ids global debugfs_monitor_on debugfs_damon = os.path.join(debugfs, 'damon') debugfs_attrs = os.path.join(debugfs_damon, 'attrs') debugfs_record = os.path.join(debugfs_damon, 'record') + debugfs_schemes = os.path.join(debugfs_damon, 'schemes') debugfs_target_ids = os.path.join(debugfs_damon, 'target_ids') debugfs_monitor_on = os.path.join(debugfs_damon, 'monitor_on') @@ -95,8 +110,8 @@ def chk_update_debugfs(debugfs): print("damon debugfs dir (%s) not found", debugfs_damon) exit(1) - for f in [debugfs_attrs, debugfs_record, debugfs_target_ids, - debugfs_monitor_on]: + for f in [debugfs_attrs, debugfs_record, debugfs_schemes, + debugfs_target_ids, debugfs_monitor_on]: if not os.path.isfile(f): print("damon debugfs file (%s) not found" % f) exit(1) @@ -112,8 +127,9 @@ def cmd_args_to_attrs(args): if not os.path.isabs(args.out): args.out = os.path.join(os.getcwd(), args.out) rfile_path = args.out + schemes = args.schemes return Attrs(sample_interval, aggr_interval, regions_update_interval, - min_nr_regions, max_nr_regions, rbuf_len, rfile_path) + min_nr_regions, max_nr_regions, rbuf_len, rfile_path, schemes) def set_attrs_argparser(parser): parser.add_argument('-d', '--debugfs', metavar='', type=str, diff --git a/tools/damon/damo b/tools/damon/damo index 58e1099ae5fc..ce7180069bef 100755 --- a/tools/damon/damo +++ b/tools/damon/damo @@ -5,6 +5,7 @@ import argparse import record import report +import schemes class SubCmdHelpFormatter(argparse.RawDescriptionHelpFormatter): def _format_action(self, action): @@ -25,6 +26,10 @@ parser_record = subparser.add_parser('record', help='record data accesses of the given target processes') record.set_argparser(parser_record) +parser_schemes = subparser.add_parser('schemes', + help='apply operation schemes to the given target process') +schemes.set_argparser(parser_schemes) + parser_report = subparser.add_parser('report', help='report the recorded data accesses in the specified form') report.set_argparser(parser_report) @@ -33,5 +38,7 @@ args = parser.parse_args() if args.command == 'record': record.main(args) +elif args.command == 'schemes': + schemes.main(args) elif args.command == 'report': report.main(args) diff --git a/tools/damon/schemes.py b/tools/damon/schemes.py new file mode 100644 index 000000000000..9095835f6133 --- /dev/null +++ b/tools/damon/schemes.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0 + +""" +Apply given operation schemes to the target process. +""" + +import argparse +import os +import signal +import subprocess +import time + +import _convert_damos +import _damon + +def run_damon(target, is_target_cmd, attrs, old_attrs): + if os.path.isfile(attrs.rfile_path): + os.rename(attrs.rfile_path, attrs.rfile_path + '.old') + + if attrs.apply(): + print('attributes (%s) failed to be applied' % attrs) + cleanup_exit(old_attrs, -1) + print('# damon attrs: %s %s' % (attrs.attr_str(), attrs.record_str())) + for line in attrs.schemes.split('\n'): + print('# scheme: %s' % line) + if is_target_cmd: + p = subprocess.Popen(target, shell=True, executable='/bin/bash') + target = p.pid + if _damon.set_target_pid(target): + print('pid setting (%s) failed' % target) + cleanup_exit(old_attrs, -2) + if _damon.turn_damon('on'): + print('could not turn on damon' % target) + cleanup_exit(old_attrs, -3) + while not _damon.is_damon_running(): + sleep(1) + print('Press Ctrl+C to stop') + if is_target_cmd: + p.wait() + while True: + # damon will turn it off by itself if the target tasks are terminated. + if not _damon.is_damon_running(): + break + time.sleep(1) + + cleanup_exit(old_attrs, 0) + +def cleanup_exit(orig_attrs, exit_code): + if _damon.is_damon_running(): + if _damon.turn_damon('off'): + print('failed to turn damon off!') + while _damon.is_damon_running(): + sleep(1) + if orig_attrs: + if orig_attrs.apply(): + print('original attributes (%s) restoration failed!' % orig_attrs) + exit(exit_code) + +def sighandler(signum, frame): + print('\nsignal %s received' % signum) + cleanup_exit(orig_attrs, signum) + +def chk_permission(): + if os.geteuid() != 0: + print("Run as root") + exit(1) + +def set_argparser(parser): + _damon.set_attrs_argparser(parser) + parser.add_argument('target', type=str, metavar='', + help='the target command or the pid to record') + parser.add_argument('-c', '--schemes', metavar='', type=str, + default='damon.schemes', + help='data access monitoring-based operation schemes') + +def main(args=None): + global orig_attrs + if not args: + parser = argparse.ArgumentParser() + set_argparser(parser) + args = parser.parse_args() + + chk_permission() + _damon.chk_update_debugfs(args.debugfs) + + signal.signal(signal.SIGINT, sighandler) + signal.signal(signal.SIGTERM, sighandler) + orig_attrs = _damon.current_attrs() + + args.rbuf = 0 + args.out = 'null' + args.schemes = _convert_damos.convert(args.schemes, args.sample, args.aggr) + new_attrs = _damon.cmd_args_to_attrs(args) + target = args.target + + target_fields = target.split() + if not subprocess.call('which %s &> /dev/null' % target_fields[0], + shell=True, executable='/bin/bash'): + run_damon(target, True, new_attrs, orig_attrs) + else: + try: + pid = int(target) + except: + print('target \'%s\' is neither a command, nor a pid' % target) + exit(1) + run_damon(target, False, new_attrs, orig_attrs) + +if __name__ == '__main__': + main() From patchwork Wed Dec 16 08:44:04 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: SeongJae Park X-Patchwork-Id: 11976973 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-18.8 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7D02EC4361B for ; Wed, 16 Dec 2020 08:47:15 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id DE29521D81 for ; Wed, 16 Dec 2020 08:47:14 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org DE29521D81 Authentication-Results: mail.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=amazon.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=owner-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix) id 6BE406B0073; Wed, 16 Dec 2020 03:47:14 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 648D58D0003; Wed, 16 Dec 2020 03:47:14 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 51A998D0002; Wed, 16 Dec 2020 03:47:14 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0112.hostedemail.com [216.40.44.112]) by kanga.kvack.org (Postfix) with ESMTP id 351F66B0073 for ; Wed, 16 Dec 2020 03:47:14 -0500 (EST) Received: from smtpin07.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay04.hostedemail.com (Postfix) with ESMTP id F1B9A363D for ; Wed, 16 Dec 2020 08:47:13 +0000 (UTC) X-FDA: 77598515946.07.men95_571725a2742a Received: from filter.hostedemail.com (10.5.16.251.rfc1918.com [10.5.16.251]) by smtpin07.hostedemail.com (Postfix) with ESMTP id D53AF1803F9A1 for ; Wed, 16 Dec 2020 08:47:13 +0000 (UTC) X-HE-Tag: men95_571725a2742a X-Filterd-Recvd-Size: 14921 Received: from smtp-fw-33001.amazon.com (smtp-fw-33001.amazon.com [207.171.190.10]) by imf26.hostedemail.com (Postfix) with ESMTP for ; Wed, 16 Dec 2020 08:47:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.com; i=@amazon.com; q=dns/txt; s=amazon201209; t=1608108433; x=1639644433; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=XEjhfcWOE6sCpVcYRXwQLFfPVP/yv/3hCxGv89889MM=; b=hc0YDLtdV9PHvin1axr7dj9dKkAjWGKWrhUJPTf5XqgJnvu1zIjsN+G9 npBCRBfbOSicI91H+vo9912beAPNKZ/2yfeclSbudquEqWMb0zacAVWm+ +PboMqEDWOYbJFQlgJAlb1ARehGKU8BBCjcnCSwlSQ1vx1SWS3gXxyPr3 k=; X-IronPort-AV: E=Sophos;i="5.78,424,1599523200"; d="scan'208";a="103481231" Received: from sea32-co-svc-lb4-vlan3.sea.corp.amazon.com (HELO email-inbound-relay-1e-a70de69e.us-east-1.amazon.com) ([10.47.23.38]) by smtp-border-fw-out-33001.sea14.amazon.com with ESMTP; 16 Dec 2020 08:47:09 +0000 Received: from EX13D31EUA001.ant.amazon.com (iad12-ws-svc-p26-lb9-vlan2.iad.amazon.com [10.40.163.34]) by email-inbound-relay-1e-a70de69e.us-east-1.amazon.com (Postfix) with ESMTPS id 75544A1EE6; Wed, 16 Dec 2020 08:46:57 +0000 (UTC) Received: from u3f2cd687b01c55.ant.amazon.com (10.43.161.102) by EX13D31EUA001.ant.amazon.com (10.43.165.15) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 16 Dec 2020 08:46:41 +0000 From: SeongJae Park To: CC: SeongJae Park , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [RFC v15.1 8/8] Docs/admin-guide/mm/damon: Document DAMON-based Operation Schemes Date: Wed, 16 Dec 2020 09:44:04 +0100 Message-ID: <20201216084404.23183-9-sjpark@amazon.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201216084404.23183-1-sjpark@amazon.com> References: <20201216084404.23183-1-sjpark@amazon.com> MIME-Version: 1.0 X-Originating-IP: [10.43.161.102] X-ClientProxiedBy: EX13D22UWB003.ant.amazon.com (10.43.161.76) To EX13D31EUA001.ant.amazon.com (10.43.165.15) X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: From: SeongJae Park This commit add description of DAMON-based operation schemes in the DAMON documents. Signed-off-by: SeongJae Park --- Documentation/admin-guide/mm/damon/guide.rst | 41 ++++++- Documentation/admin-guide/mm/damon/start.rst | 11 ++ Documentation/admin-guide/mm/damon/usage.rst | 109 ++++++++++++++++++- Documentation/vm/damon/index.rst | 1 - 4 files changed, 156 insertions(+), 6 deletions(-) diff --git a/Documentation/admin-guide/mm/damon/guide.rst b/Documentation/admin-guide/mm/damon/guide.rst index c51fb843efaa..1f9aa2ebbdb6 100644 --- a/Documentation/admin-guide/mm/damon/guide.rst +++ b/Documentation/admin-guide/mm/damon/guide.rst @@ -53,6 +53,11 @@ heats``. If it shows a simple pattern consists of a small number of memory regions having high contrast of access temperature, you could consider manual `Program Modification`_. +If the access pattern is very frequently changing so that you cannot figure out +what is the performance important region using your human eye, `Automated +DAMON-based Memory Operations`_ might help the case owing to its machine-level +microscope view. + If you still want to absorb more benefits, you should develop `Personalized DAMON Application`_ for your special case. @@ -120,6 +125,36 @@ shows the visualized access patterns of streamcluster workload in PARSEC3 benchmark suite. We can easily identify the 100 MiB sized hot object. +Automated DAMON-based Memory Operations +--------------------------------------- + +Though `Manual Program Optimization` works well in many cases and DAMON can +help it, modifying the source code is not a good option in many cases. First +of all, the source code could be too old or unavailable. And, many workloads +will have complex data access patterns that even hard to distinguish hot memory +objects and cold memory objects with the human eye. Finding the mapping from +the visualized access pattern to the source code and injecting the hinting +system calls inside the code will also be quite challenging. + +By using DAMON-based operation schemes (DAMOS) via ``damo schemes``, you will +be able to easily optimize your workload in such a case. Our example schemes +called 'efficient THP' and 'proactive reclamation' achieved significant speedup +and memory space saves against 25 realistic workloads [2]_. + +That said, note that you need careful tune of the schemes (e.g., target region +size and age) and monitoring attributes for the successful use of this +approach. Because the optimal values of the parameters will be dependent on +each system and workload, misconfiguring the parameters could result in worse +memory management. + +For the tuning, you could measure the performance metrics such as IPC, TLB +misses, and swap in/out events and adjusts the parameters based on their +changes. The total number and the total size of the regions that each scheme +is applied, which are provided via the debugfs interface and the programming +interface can also be useful. Writing a program automating this optimal +parameter could be an option. + + Personalized DAMON Application ------------------------------ @@ -146,9 +181,9 @@ Referencing previously done successful practices could help you getting the sense for this kind of optimizations. There is an academic paper [1]_ reporting the visualized access pattern and manual `Program Modification`_ results for a number of realistic workloads. You can also get -the visualized access patterns [3]_ [4]_ [5]_ and automated DAMON-based memory -operations results for other realistic workloads that collected with latest -version of DAMON [2]_ . +the visualized access patterns [3]_ [4]_ [5]_ and +`Automated DAMON-based Memory Operations`_ results for other realistic +workloads that collected with latest version of DAMON [2]_ . .. [1] https://dl.acm.org/doi/10.1145/3366626.3368125 .. [2] https://damonitor.github.io/test/result/perf/latest/html/ diff --git a/Documentation/admin-guide/mm/damon/start.rst b/Documentation/admin-guide/mm/damon/start.rst index deed2ea2321e..35cf4e4ca6aa 100644 --- a/Documentation/admin-guide/mm/damon/start.rst +++ b/Documentation/admin-guide/mm/damon/start.rst @@ -90,6 +90,17 @@ image files. :: You can show the images in a web page [1]_ . Those made with other realistic workloads are also available [2]_ [3]_ [4]_. + +Data Access Pattern Aware Memory Management +=========================================== + +Below three commands make every memory region of size >=4K that doesn't +accessed for >=60 seconds in your workload to be swapped out. :: + + $ echo "#min-size max-size min-acc max-acc min-age max-age action" > scheme + $ echo "4K max 0 0 60s max pageout" >> scheme + $ damo schemes -c my_thp_scheme + .. [1] https://damonitor.github.io/doc/html/v17/admin-guide/mm/damon/start.html#visualizing-recorded-patterns .. [2] https://damonitor.github.io/test/result/visual/latest/rec.heatmap.1.png.html .. [3] https://damonitor.github.io/test/result/visual/latest/rec.wss_sz.png.html diff --git a/Documentation/admin-guide/mm/damon/usage.rst b/Documentation/admin-guide/mm/damon/usage.rst index a6606d27a559..96278227f925 100644 --- a/Documentation/admin-guide/mm/damon/usage.rst +++ b/Documentation/admin-guide/mm/damon/usage.rst @@ -219,11 +219,70 @@ Similar to that of ``heats --heatmap``, it also supports 'gnuplot' based simple visualization of the distribution via ``--plot`` option. +DAMON-based Operation Schemes +----------------------------- + +The ``schemes`` subcommand allows users to do DAMON-based memory management +optimizations in a few seconds. Similar to ``record``, it receives monitoring +attributes and target. However, in addition to those, ``schemes`` receives +data access pattern-based memory operation schemes, which describes what memory +operation action should be applied to memory regions showing specific data +access pattern. Then, it starts the data access monitoring and automatically +applies the schemes to the targets. + +The operation schemes should be saved in a text file in below format and passed +to ``schemes`` subcommand via ``--schemes`` option. :: + + min-size max-size min-acc max-acc min-age max-age action + +The format also supports comments, several units for size and age of regions, +and human readable action names. Currently supported operation actions are +``willneed``, ``cold``, ``pageout``, ``hugepage`` and ``nohugepage``. Each of +the actions works same to the madvise() system call hints having the name. +Please also note that the range is inclusive (closed interval), and ``0`` for +max values means infinite. Below example schemes are possible. :: + + # format is: + # + # + # B/K/M/G/T for Bytes/KiB/MiB/GiB/TiB + # us/ms/s/m/h/d for micro-seconds/milli-seconds/seconds/minutes/hours/days + # 'min/max' for possible min/max value. + + # if a region keeps a high access frequency for >=100ms, put the region on + # the head of the LRU list (call madvise() with MADV_WILLNEED). + min max 80 max 100ms max willneed + + # if a region keeps a low access frequency for >=200ms and <=one hour, put + # the region on the tail of the LRU list (call madvise() with MADV_COLD). + min max 10 20 200ms 1h cold + + # if a region keeps a very low access frequency for >=60 seconds, swap out + # the region immediately (call madvise() with MADV_PAGEOUT). + min max 0 10 60s max pageout + + # if a region of a size >=2MiB keeps a very high access frequency for + # >=100ms, let the region to use huge pages (call madvise() with + # MADV_HUGEPAGE). + 2M max 90 100 100ms max hugepage + + # If a regions of a size >=2MiB keeps small access frequency for >=100ms, + # avoid the region using huge pages (call madvise() with MADV_NOHUGEPAGE). + 2M max 0 25 100ms max nohugepage + +For example, you can make a running process named 'foo' to use huge pages for +memory regions keeping 2MB or larger size and having very high access frequency +for at least 100 milliseconds using below commands:: + + $ echo "2M max 90 max 100ms max hugepage" > my_thp_scheme + $ ./damo schemes --schemes my_thp_scheme `pidof foo` + + debugfs Interface ================= -DAMON exports four files, ``attrs``, ``target_ids``, ``record``, and -``monitor_on`` under its debugfs directory, ``/damon/``. +DAMON exports five files, ``attrs``, ``target_ids``, ``record``, ``schemes`` +and ``monitor_on`` under its debugfs directory, ``/damon/``. Attributes @@ -280,6 +339,52 @@ saved in ``/damon.data``. :: The recording can be disabled by setting the buffer size zero. +Schemes +------- + +For usual DAMON-based data access aware memory management optimizations, users +would simply want the system to apply a memory management action to a memory +region of a specific size having a specific access frequency for a specific +time. DAMON receives such formalized operation schemes from the user and +applies those to the target processes. It also counts the total number and +size of regions that each scheme is applied. This statistics can be used for +online analysis or tuning of the schemes. + +Users can get and set the schemes by reading from and writing to ``schemes`` +debugfs file. Reading the file also shows the statistics of each scheme. To +the file, each of the schemes should be represented in each line in below form: + + min-size max-size min-acc max-acc min-age max-age action + +Note that the ranges are closed interval. Bytes for the size of regions +(``min-size`` and ``max-size``), number of monitored accesses per aggregate +interval for access frequency (``min-acc`` and ``max-acc``), number of +aggregate intervals for the age of regions (``min-age`` and ``max-age``), and a +predefined integer for memory management actions should be used. The supported +numbers and their meanings are as below. + + - 0: Call ``madvise()`` for the region with ``MADV_WILLNEED`` + - 1: Call ``madvise()`` for the region with ``MADV_COLD`` + - 2: Call ``madvise()`` for the region with ``MADV_PAGEOUT`` + - 3: Call ``madvise()`` for the region with ``MADV_HUGEPAGE`` + - 4: Call ``madvise()`` for the region with ``MADV_NOHUGEPAGE`` + - 5: Do nothing but count the statistics + +You can disable schemes by simply writing an empty string to the file. For +example, below commands applies a scheme saying "If a memory region of size in +[4KiB, 8KiB] is showing accesses per aggregate interval in [0, 5] for aggregate +interval in [10, 20], page out the region", check the entered scheme again, and +finally remove the scheme. :: + + # cd /damon + # echo "4096 8192 0 5 10 20 2" > schemes + # cat schemes + 4096 8192 0 5 10 20 2 0 0 + # echo > schemes + +The last two integers in the 4th line of above example is the total number and +the total size of the regions that the scheme is applied. + Turning On/Off -------------- diff --git a/Documentation/vm/damon/index.rst b/Documentation/vm/damon/index.rst index 17dca3c12aad..69aec1287aaf 100644 --- a/Documentation/vm/damon/index.rst +++ b/Documentation/vm/damon/index.rst @@ -28,4 +28,3 @@ workloads and systems. design eval api - plans