From patchwork Wed Jun 3 07:11:31 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: SeongJae Park X-Patchwork-Id: 11585175 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7F6541392 for ; Wed, 3 Jun 2020 07:13:11 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id 4C82220679 for ; Wed, 3 Jun 2020 07:13:11 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=amazon.com header.i=@amazon.com header.b="SpbxWH2f" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 4C82220679 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 8685A80008; Wed, 3 Jun 2020 03:13:10 -0400 (EDT) Delivered-To: linux-mm-outgoing@kvack.org Received: by kanga.kvack.org (Postfix, from userid 40) id 8174280007; Wed, 3 Jun 2020 03:13:10 -0400 (EDT) X-Original-To: int-list-linux-mm@kvack.org X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 706C480008; Wed, 3 Jun 2020 03:13:10 -0400 (EDT) X-Original-To: linux-mm@kvack.org X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0087.hostedemail.com [216.40.44.87]) by kanga.kvack.org (Postfix) with ESMTP id 556E080007 for ; Wed, 3 Jun 2020 03:13:10 -0400 (EDT) Received: from smtpin24.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay02.hostedemail.com (Postfix) with ESMTP id 0D438442A for ; Wed, 3 Jun 2020 07:13:10 +0000 (UTC) X-FDA: 76887034140.24.bait13_38b2f86ca5c2f Received: from filter.hostedemail.com (10.5.16.251.rfc1918.com [10.5.16.251]) by smtpin24.hostedemail.com (Postfix) with ESMTP id E7B5A1A4AA for ; Wed, 3 Jun 2020 07:13:09 +0000 (UTC) X-Spam-Summary: 1,0,0,,d41d8cd98f00b204,prvs=416e8e2f5=sjpark@amazon.com,,RULES_HIT:30054:30064,0,RBL:52.95.49.90:@amazon.com:.lbl8.mailshell.net-62.18.0.100 64.10.201.10,CacheIP:none,Bayesian:0.5,0.5,0.5,Netcheck:none,DomainCache:0,MSF:not bulk,SPF:fp,MSBL:0,DNSBL:neutral,Custom_rules:0:0:0,LFtime:22,LUA_SUMMARY:none X-HE-Tag: bait13_38b2f86ca5c2f X-Filterd-Recvd-Size: 3912 Received: from smtp-fw-6002.amazon.com (smtp-fw-6002.amazon.com [52.95.49.90]) by imf01.hostedemail.com (Postfix) with ESMTP for ; Wed, 3 Jun 2020 07:13:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.com; i=@amazon.com; q=dns/txt; s=amazon201209; t=1591168389; x=1622704389; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=lNFxVu5oHwO1aOURXAUvUJJi5lK2SkZMFrjh4Wym42s=; b=SpbxWH2fw+duj0UY9nzktm5w4M/1ZwN77XNppN0JUFjvXjUJN//Ixdmi fgozhH87/MBN8zJoUEeu6fvqIOmW7sLFtuEm0Kurm2Aczs2Py2R9wotuP MMQVE7VvLki4axiG3F5MLt33FhM78btANBMQ2ZZ3TbLejs/DFa9eLYfzx k=; IronPort-SDR: YTb1zGhebK0YF8XKZG+sGwMlQwqKPLhAuzZHlNyFY7Dr2gZv/c82KfRvUbip+O5rgupPQKEKPt w7kI9jtL5aug== X-IronPort-AV: E=Sophos;i="5.73,467,1583193600"; d="scan'208";a="34063678" Received: from iad12-co-svc-p1-lb1-vlan3.amazon.com (HELO email-inbound-relay-1e-303d0b0e.us-east-1.amazon.com) ([10.43.8.6]) by smtp-border-fw-out-6002.iad6.amazon.com with ESMTP; 03 Jun 2020 07:12:58 +0000 Received: from EX13MTAUEA002.ant.amazon.com (iad55-ws-svc-p15-lb9-vlan3.iad.amazon.com [10.40.159.166]) by email-inbound-relay-1e-303d0b0e.us-east-1.amazon.com (Postfix) with ESMTPS id 759B3A2A37; Wed, 3 Jun 2020 07:12:46 +0000 (UTC) Received: from EX13D31EUA001.ant.amazon.com (10.43.165.15) by EX13MTAUEA002.ant.amazon.com (10.43.61.77) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 3 Jun 2020 07:12:45 +0000 Received: from u886c93fd17d25d.ant.amazon.com (10.43.160.26) by EX13D31EUA001.ant.amazon.com (10.43.165.15) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 3 Jun 2020 07:12:29 +0000 From: SeongJae Park To: CC: SeongJae Park , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [RFC v10 1/8] mm/madvise: Export do_madvise() to external GPL modules Date: Wed, 3 Jun 2020 09:11:31 +0200 Message-ID: <20200603071138.8152-2-sjpark@amazon.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200603071138.8152-1-sjpark@amazon.com> References: <20200603071138.8152-1-sjpark@amazon.com> MIME-Version: 1.0 X-Originating-IP: [10.43.160.26] X-ClientProxiedBy: EX13D10UWB003.ant.amazon.com (10.43.161.106) To EX13D31EUA001.ant.amazon.com (10.43.165.15) X-Rspamd-Queue-Id: E7B5A1A4AA X-Spamd-Result: default: False [0.00 / 100.00] X-Rspamd-Server: rspam05 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 exports 'do_madvise()' to external GPL modules, so that other modules including DAMON could use the function. Signed-off-by: SeongJae Park --- mm/madvise.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mm/madvise.c b/mm/madvise.c index 1ad7522567d4..fcd951694ebc 100644 --- a/mm/madvise.c +++ b/mm/madvise.c @@ -1171,6 +1171,7 @@ int do_madvise(struct task_struct *target_task, struct mm_struct *mm, return error; } +EXPORT_SYMBOL_GPL(do_madvise); SYSCALL_DEFINE3(madvise, unsigned long, start, size_t, len_in, int, behavior) { From patchwork Wed Jun 3 07:11:32 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: SeongJae Park X-Patchwork-Id: 11585177 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 5C3EB1392 for ; Wed, 3 Jun 2020 07:14:26 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id 1D0D02077D for ; Wed, 3 Jun 2020 07:14:26 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=amazon.com header.i=@amazon.com header.b="RdQiG7Vd" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 1D0D02077D 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 5A8CC80007; Wed, 3 Jun 2020 03:14:25 -0400 (EDT) Delivered-To: linux-mm-outgoing@kvack.org Received: by kanga.kvack.org (Postfix, from userid 40) id 55B558E0006; Wed, 3 Jun 2020 03:14:25 -0400 (EDT) X-Original-To: int-list-linux-mm@kvack.org X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 446F980007; Wed, 3 Jun 2020 03:14:25 -0400 (EDT) X-Original-To: linux-mm@kvack.org X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0234.hostedemail.com [216.40.44.234]) by kanga.kvack.org (Postfix) with ESMTP id 2C2288E0006 for ; Wed, 3 Jun 2020 03:14:25 -0400 (EDT) Received: from smtpin17.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay05.hostedemail.com (Postfix) with ESMTP id DA6BA181AEF07 for ; Wed, 3 Jun 2020 07:14:24 +0000 (UTC) X-FDA: 76887037248.17.jail08_438e1f884ce63 Received: from filter.hostedemail.com (10.5.16.251.rfc1918.com [10.5.16.251]) by smtpin17.hostedemail.com (Postfix) with ESMTP id BA950180D0181 for ; Wed, 3 Jun 2020 07:14:24 +0000 (UTC) X-Spam-Summary: 1,0,0,,d41d8cd98f00b204,prvs=416e8e2f5=sjpark@amazon.com,,RULES_HIT:30001:30003:30004:30054:30064:30070,0,RBL:72.21.196.25:@amazon.com:.lbl8.mailshell.net-62.18.0.100 66.10.201.10,CacheIP:none,Bayesian:0.5,0.5,0.5,Netcheck:none,DomainCache:0,MSF:not bulk,SPF:fp,MSBL:0,DNSBL:neutral,Custom_rules:0:0:0,LFtime:0,LUA_SUMMARY:none X-HE-Tag: jail08_438e1f884ce63 X-Filterd-Recvd-Size: 8033 Received: from smtp-fw-2101.amazon.com (smtp-fw-2101.amazon.com [72.21.196.25]) by imf47.hostedemail.com (Postfix) with ESMTP for ; Wed, 3 Jun 2020 07:14:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.com; i=@amazon.com; q=dns/txt; s=amazon201209; t=1591168464; x=1622704464; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=/kfAd1XjpVq3L6on7njk4xOmlv6uR7G/4ENC2AijgCU=; b=RdQiG7Vdl8D5xvsi4n96Yh1ugUgMFNQ/puFth7mfc9IOGOA8JNstucit Udhkw21D8PAjMZmI0ZShS91T5SBYlXs/Ox89R78yvKw9brW8bWvqKwl+/ m7rpIkHNAI36Y4GIUDdnIAATPgzUN7e1f/tD7nLvx4qg7Mf4oSI6BtLJZ k=; IronPort-SDR: LhSGDLBJ5HRtVy36/p0AM84Q0ZyaoUHX9GeokDN4aqmODKjlWYoEc4DZSi3kurv3yCs3RClP3u 0+OXVumWR8oQ== X-IronPort-AV: E=Sophos;i="5.73,467,1583193600"; d="scan'208";a="34199761" Received: from iad12-co-svc-p1-lb1-vlan2.amazon.com (HELO email-inbound-relay-1e-c7c08562.us-east-1.amazon.com) ([10.43.8.2]) by smtp-border-fw-out-2101.iad2.amazon.com with ESMTP; 03 Jun 2020 07:14:24 +0000 Received: from EX13MTAUEA002.ant.amazon.com (iad55-ws-svc-p15-lb9-vlan2.iad.amazon.com [10.40.159.162]) by email-inbound-relay-1e-c7c08562.us-east-1.amazon.com (Postfix) with ESMTPS id CE219243DF4; Wed, 3 Jun 2020 07:14:21 +0000 (UTC) Received: from EX13D31EUA001.ant.amazon.com (10.43.165.15) by EX13MTAUEA002.ant.amazon.com (10.43.61.77) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 3 Jun 2020 07:14:21 +0000 Received: from u886c93fd17d25d.ant.amazon.com (10.43.160.26) by EX13D31EUA001.ant.amazon.com (10.43.165.15) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 3 Jun 2020 07:14:06 +0000 From: SeongJae Park To: CC: SeongJae Park , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [RFC v10 2/8] mm/damon: Account age of target regions Date: Wed, 3 Jun 2020 09:11:32 +0200 Message-ID: <20200603071138.8152-3-sjpark@amazon.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200603071138.8152-1-sjpark@amazon.com> References: <20200603071138.8152-1-sjpark@amazon.com> MIME-Version: 1.0 X-Originating-IP: [10.43.160.26] X-ClientProxiedBy: EX13D10UWB003.ant.amazon.com (10.43.161.106) To EX13D31EUA001.ant.amazon.com (10.43.165.15) X-Rspamd-Queue-Id: BA950180D0181 X-Spamd-Result: default: False [0.00 / 100.00] X-Rspamd-Server: rspam05 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 as a primitive for data access pattern aware memory management optimizations. However, users who want such optimizations 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 optimizations, 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.c | 29 +++++++++++++++++++++-------- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/include/linux/damon.h b/include/linux/damon.h index c4796a10cb1a..6a8ff2c63c2a 100644 --- a/include/linux/damon.h +++ b/include/linux/damon.h @@ -24,6 +24,13 @@ * @sampling_addr: Address of the sample for the next access check. * @nr_accesses: Access frequency of this region. * @list: List head for siblings. + * @age: Age of this region. + * @last_nr_accesses: Internal value for age calculation. + * + * @age is initially zero, increased for each aggregation interval, and reset + * to zero again if the access frequency is significantly changed. If two + * regions are merged into a new region, both @nr_accesses and @age of the new + * region are set as region size-weighted average of those of the two regions. */ struct damon_region { unsigned long vm_start; @@ -31,6 +38,9 @@ struct damon_region { unsigned long sampling_addr; unsigned int nr_accesses; struct list_head list; + + unsigned int age; + unsigned int last_nr_accesses; }; /** diff --git a/mm/damon.c b/mm/damon.c index 2c44e0860672..6e9cc3330589 100644 --- a/mm/damon.c +++ b/mm/damon.c @@ -86,6 +86,9 @@ static struct damon_region *damon_new_region(struct damon_ctx *ctx, region->nr_accesses = 0; INIT_LIST_HEAD(®ion->list); + region->age = 0; + region->last_nr_accesses = 0; + return region; } @@ -659,6 +662,7 @@ static void kdamond_reset_aggregated(struct damon_ctx *c) sizeof(r->nr_accesses)); trace_damon_aggregated(t->pid, nr, r->vm_start, r->vm_end, r->nr_accesses); + r->last_nr_accesses = r->nr_accesses; r->nr_accesses = 0; } } @@ -672,9 +676,11 @@ static void kdamond_reset_aggregated(struct damon_ctx *c) static void damon_merge_two_regions(struct damon_region *l, struct damon_region *r) { - l->nr_accesses = (l->nr_accesses * sz_damon_region(l) + - r->nr_accesses * sz_damon_region(r)) / - (sz_damon_region(l) + sz_damon_region(r)); + unsigned long sz_l = sz_damon_region(l), sz_r = sz_damon_region(r); + + l->nr_accesses = (l->nr_accesses * sz_l + r->nr_accesses * sz_r) / + (sz_l + sz_r); + l->age = (l->age * sz_l + r->age * sz_r) / (sz_l + sz_r); l->vm_end = r->vm_end; damon_destroy_region(r); } @@ -692,12 +698,16 @@ static void damon_merge_regions_of(struct damon_task *t, unsigned int thres) struct damon_region *r, *prev = NULL, *next; damon_for_each_region_safe(r, next, t) { - if (!prev || prev->vm_end != r->vm_start || - diff_of(prev->nr_accesses, r->nr_accesses) > thres) { + if (diff_of(r->nr_accesses, r->last_nr_accesses) > thres) + r->age = 0; + else + r->age++; + + if (prev && prev->vm_end == r->vm_start && + diff_of(prev->nr_accesses, r->nr_accesses) <= thres) + damon_merge_two_regions(prev, r); + else prev = r; - continue; - } - damon_merge_two_regions(prev, r); } } @@ -733,6 +743,9 @@ static void damon_split_region_at(struct damon_ctx *ctx, new = damon_new_region(ctx, r->vm_start + sz_r, r->vm_end); r->vm_end = new->vm_start; + new->age = r->age; + new->last_nr_accesses = r->last_nr_accesses; + damon_insert_region(new, r, damon_next_region(r)); } From patchwork Wed Jun 3 07:11:33 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: SeongJae Park X-Patchwork-Id: 11585179 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 241B21392 for ; Wed, 3 Jun 2020 07:15:11 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id D8A7E206E6 for ; Wed, 3 Jun 2020 07:15:10 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=amazon.com header.i=@amazon.com header.b="BeOC0Ko5" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org D8A7E206E6 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 13B1880008; Wed, 3 Jun 2020 03:15:10 -0400 (EDT) Delivered-To: linux-mm-outgoing@kvack.org Received: by kanga.kvack.org (Postfix, from userid 40) id 0C7098E0007; Wed, 3 Jun 2020 03:15:10 -0400 (EDT) X-Original-To: int-list-linux-mm@kvack.org X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id EDC398E0006; Wed, 3 Jun 2020 03:15:09 -0400 (EDT) X-Original-To: linux-mm@kvack.org X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0210.hostedemail.com [216.40.44.210]) by kanga.kvack.org (Postfix) with ESMTP id D2D6C8E0006 for ; Wed, 3 Jun 2020 03:15:09 -0400 (EDT) Received: from smtpin19.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay01.hostedemail.com (Postfix) with ESMTP id 8BAE5180AD804 for ; Wed, 3 Jun 2020 07:15:09 +0000 (UTC) X-FDA: 76887039138.19.ocean61_4a14aa345015c Received: from filter.hostedemail.com (10.5.16.251.rfc1918.com [10.5.16.251]) by smtpin19.hostedemail.com (Postfix) with ESMTP id 70C9F1AD1B0 for ; Wed, 3 Jun 2020 07:15:09 +0000 (UTC) X-Spam-Summary: 1,0,0,,d41d8cd98f00b204,prvs=416e8e2f5=sjpark@amazon.com,,RULES_HIT:30004:30012:30034:30054:30064:30070,0,RBL:52.95.48.154:@amazon.com:.lbl8.mailshell.net-62.18.0.100 64.10.201.10,CacheIP:none,Bayesian:0.5,0.5,0.5,Netcheck:none,DomainCache:0,MSF:not bulk,SPF:fp,MSBL:0,DNSBL:neutral,Custom_rules:0:0:0,LFtime:23,LUA_SUMMARY:none X-HE-Tag: ocean61_4a14aa345015c X-Filterd-Recvd-Size: 13327 Received: from smtp-fw-6001.amazon.com (smtp-fw-6001.amazon.com [52.95.48.154]) by imf36.hostedemail.com (Postfix) with ESMTP for ; Wed, 3 Jun 2020 07:15:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.com; i=@amazon.com; q=dns/txt; s=amazon201209; t=1591168509; x=1622704509; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=w/wvWrpld90pNUq9YxCX8KV2wshZFfoHjwL1rl4YxuM=; b=BeOC0Ko51zCjYhh+R5CyKsW/TCivEPt6PKLVYx4KmrEkdUUsXomZDEiv b5ZUVQ+0pE+w49e7ibR+yWDU1+9jeECgS6UsLFynajpAr88FX4jYB0Qxa K84uVF2TaKNLcEUJRToOy7Vl3PwBCy1Lu9lwvoCaeWwfjrzF/wr/eXQle k=; IronPort-SDR: kInXsENdARxxwjlItmKKuj8Nc+0nf+H4kepBVOcWIymkojSsnUXVjXKGb8foYTTy0Nr5KCFjGU 65I6FbxKGFEA== X-IronPort-AV: E=Sophos;i="5.73,467,1583193600"; d="scan'208";a="35493853" Received: from iad12-co-svc-p1-lb1-vlan3.amazon.com (HELO email-inbound-relay-1d-9ec21598.us-east-1.amazon.com) ([10.43.8.6]) by smtp-border-fw-out-6001.iad6.amazon.com with ESMTP; 03 Jun 2020 07:14:55 +0000 Received: from EX13MTAUEA002.ant.amazon.com (iad55-ws-svc-p15-lb9-vlan3.iad.amazon.com [10.40.159.166]) by email-inbound-relay-1d-9ec21598.us-east-1.amazon.com (Postfix) with ESMTPS id EAE8BA18B2; Wed, 3 Jun 2020 07:14:43 +0000 (UTC) Received: from EX13D31EUA001.ant.amazon.com (10.43.165.15) by EX13MTAUEA002.ant.amazon.com (10.43.61.77) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 3 Jun 2020 07:14:43 +0000 Received: from u886c93fd17d25d.ant.amazon.com (10.43.160.26) by EX13D31EUA001.ant.amazon.com (10.43.165.15) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 3 Jun 2020 07:14:26 +0000 From: SeongJae Park To: CC: SeongJae Park , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [RFC v10 3/8] mm/damon: Implement data access monitoring-based operation schemes Date: Wed, 3 Jun 2020 09:11:33 +0200 Message-ID: <20200603071138.8152-4-sjpark@amazon.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200603071138.8152-1-sjpark@amazon.com> References: <20200603071138.8152-1-sjpark@amazon.com> MIME-Version: 1.0 X-Originating-IP: [10.43.160.26] X-ClientProxiedBy: EX13D10UWB003.ant.amazon.com (10.43.161.106) To EX13D31EUA001.ant.amazon.com (10.43.165.15) X-Rspamd-Queue-Id: 70C9F1AD1B0 X-Spamd-Result: default: False [0.00 / 100.00] X-Rspamd-Server: rspam03 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". To minimize users from 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. 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 only a few of madvise() hints, ``MADV_WILLNEED``, ``MADV_COLD``, ``MADV_PAGEOUT``, ``MADV_HUGEPAGE``, and ``MADV_NOHUGEPAGE``. Signed-off-by: SeongJae Park --- include/linux/damon.h | 50 ++++++++++++++ mm/damon.c | 149 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 199 insertions(+) diff --git a/include/linux/damon.h b/include/linux/damon.h index 6a8ff2c63c2a..842a01e80c6e 100644 --- a/include/linux/damon.h +++ b/include/linux/damon.h @@ -55,6 +55,52 @@ struct damon_task { 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. + * @DAMOS_ACTION_LEN: Number of supported actions. + */ +enum damos_action { + DAMOS_WILLNEED, + DAMOS_COLD, + DAMOS_PAGEOUT, + DAMOS_HUGEPAGE, + DAMOS_NOHUGEPAGE, + DAMOS_ACTION_LEN, +}; + +/** + * 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. + * + * 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 int min_sz_region; + unsigned int 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 - Represents a context for each monitoring. This is the * main interface that allows users to set the attributes and get the results @@ -98,6 +144,7 @@ struct damon_task { * @kdamond_lock. Accesses to other fields must be protected by themselves. * * @tasks_list: Head of monitoring target tasks (&damon_task) list. + * @schemes_list: Head of schemes (&damos) list. * * @sample_cb: Called for each sampling interval. * @aggregate_cb: Called for each aggregation interval. @@ -128,6 +175,7 @@ struct damon_ctx { struct mutex kdamond_lock; struct list_head tasks_list; /* 'damon_task' objects */ + struct list_head schemes_list; /* 'damos' objects */ /* callbacks */ void (*sample_cb)(struct damon_ctx *context); @@ -138,6 +186,8 @@ int damon_set_pids(struct damon_ctx *ctx, int *pids, ssize_t nr_pids); int damon_set_attrs(struct damon_ctx *ctx, unsigned long sample_int, unsigned long aggr_int, 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_set_recording(struct damon_ctx *ctx, unsigned int rbuf_len, char *rfile_path); int damon_start(struct damon_ctx *ctx); diff --git a/mm/damon.c b/mm/damon.c index 6e9cc3330589..ffb755a14447 100644 --- a/mm/damon.c +++ b/mm/damon.c @@ -11,6 +11,7 @@ #define CREATE_TRACE_POINTS +#include #include #include #include @@ -52,6 +53,12 @@ #define damon_for_each_task_safe(t, next, ctx) \ list_for_each_entry_safe(t, next, &(ctx)->tasks_list, list) +#define damon_for_each_scheme(s, ctx) \ + list_for_each_entry(s, &(ctx)->schemes_list, list) + +#define damon_for_each_scheme_safe(s, next, ctx) \ + list_for_each_entry_safe(s, next, &(ctx)->schemes_list, list) + #define MAX_RECORD_BUFFER_LEN (4 * 1024 * 1024) #define MAX_RFILE_PATH_LEN 256 @@ -166,6 +173,27 @@ static void damon_destroy_task(struct damon_task *t) damon_free_task(t); } +static void damon_add_scheme(struct damon_ctx *ctx, struct damos *s) +{ + list_add_tail(&s->list, &ctx->schemes_list); +} + +static void damon_del_scheme(struct damos *s) +{ + list_del(&s->list); +} + +static void damon_free_scheme(struct damos *s) +{ + kfree(s); +} + +static void damon_destroy_scheme(struct damos *s) +{ + damon_del_scheme(s); + damon_free_scheme(s); +} + static unsigned int nr_damon_tasks(struct damon_ctx *ctx) { struct damon_task *t; @@ -668,6 +696,101 @@ static void kdamond_reset_aggregated(struct damon_ctx *c) } } +#ifndef CONFIG_ADVISE_SYSCALLS +static int damos_madvise(struct damon_task *task, struct damon_region *r, + int behavior) +{ + return -EINVAL; +} +#else +static int damos_madvise(struct damon_task *task, struct damon_region *r, + int behavior) +{ + struct task_struct *t; + struct mm_struct *mm; + int ret = -ENOMEM; + + t = damon_get_task_struct(task); + if (!t) + goto out; + mm = damon_get_mm(task); + if (!mm) + goto put_task_out; + + ret = do_madvise(t, mm, PAGE_ALIGN(r->vm_start), + PAGE_ALIGN(r->vm_end - r->vm_start), behavior); + mmput(mm); +put_task_out: + put_task_struct(t); +out: + return ret; +} +#endif /* CONFIG_ADVISE_SYSCALLS */ + +static int damos_do_action(struct damon_task *task, struct damon_region *r, + enum damos_action action) +{ + int madv_action; + + switch (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", action); + return -EINVAL; + } + + return damos_madvise(task, r, madv_action); +} + +static void damon_do_apply_schemes(struct damon_ctx *c, struct damon_task *t, + struct damon_region *r) +{ + struct damos *s; + unsigned long sz; + + damon_for_each_scheme(s, c) { + sz = r->vm_end - r->vm_start; + if ((s->min_sz_region && sz < s->min_sz_region) || + (s->max_sz_region && s->max_sz_region < sz)) + continue; + if ((s->min_nr_accesses && r->nr_accesses < s->min_nr_accesses) + || (s->max_nr_accesses && + s->max_nr_accesses < r->nr_accesses)) + continue; + if ((s->min_age_region && r->age < s->min_age_region) || + (s->max_age_region && + s->max_age_region < r->age)) + continue; + damos_do_action(t, r, s->action); + r->age = 0; + } +} + +static void kdamond_apply_schemes(struct damon_ctx *c) +{ + struct damon_task *t; + struct damon_region *r; + + damon_for_each_task(t, c) { + damon_for_each_region(r, t) + damon_do_apply_schemes(c, t, r); + } +} + #define sz_damon_region(r) (r->vm_end - r->vm_start) /* @@ -971,6 +1094,7 @@ static int kdamond_fn(void *data) kdamond_merge_regions(ctx, max_nr_accesses / 10); if (ctx->aggregate_cb) ctx->aggregate_cb(ctx); + kdamond_apply_schemes(ctx); kdamond_reset_aggregated(ctx); kdamond_split_regions(ctx); } @@ -1051,6 +1175,30 @@ int damon_stop(struct damon_ctx *ctx) return -EPERM; } +/** + * 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_set_pids() - Set monitoring target processes. * @ctx: monitoring context @@ -1491,6 +1639,7 @@ static int __init damon_init_user_ctx(void) mutex_init(&ctx->kdamond_lock); INIT_LIST_HEAD(&ctx->tasks_list); + INIT_LIST_HEAD(&ctx->schemes_list); return 0; } From patchwork Wed Jun 3 07:11:34 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: SeongJae Park X-Patchwork-Id: 11585181 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C0612618 for ; Wed, 3 Jun 2020 07:15:33 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id 7DDD2207D3 for ; Wed, 3 Jun 2020 07:15:33 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=amazon.com header.i=@amazon.com header.b="sJBOEfXa" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 7DDD2207D3 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 AB1B180007; Wed, 3 Jun 2020 03:15:32 -0400 (EDT) Delivered-To: linux-mm-outgoing@kvack.org Received: by kanga.kvack.org (Postfix, from userid 40) id A894A8E0006; Wed, 3 Jun 2020 03:15:32 -0400 (EDT) X-Original-To: int-list-linux-mm@kvack.org X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 978F580007; Wed, 3 Jun 2020 03:15:32 -0400 (EDT) X-Original-To: linux-mm@kvack.org X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0116.hostedemail.com [216.40.44.116]) by kanga.kvack.org (Postfix) with ESMTP id 8017D8E0006 for ; Wed, 3 Jun 2020 03:15:32 -0400 (EDT) Received: from smtpin04.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay04.hostedemail.com (Postfix) with ESMTP id 30A1A40FB for ; Wed, 3 Jun 2020 07:15:31 +0000 (UTC) X-FDA: 76887040062.04.river49_4d3556120040c Received: from filter.hostedemail.com (10.5.16.251.rfc1918.com [10.5.16.251]) by smtpin04.hostedemail.com (Postfix) with ESMTP id 1A46A80081D1 for ; Wed, 3 Jun 2020 07:15:31 +0000 (UTC) X-Spam-Summary: 1,0,0,,d41d8cd98f00b204,prvs=416e8e2f5=sjpark@amazon.com,,RULES_HIT:30004:30051:30054:30064:30070,0,RBL:207.171.184.29:@amazon.com:.lbl8.mailshell.net-66.10.201.10 62.18.0.100,CacheIP:none,Bayesian:0.5,0.5,0.5,Netcheck:none,DomainCache:0,MSF:not bulk,SPF:fp,MSBL:0,DNSBL:neutral,Custom_rules:0:0:0,LFtime:24,LUA_SUMMARY:none X-HE-Tag: river49_4d3556120040c X-Filterd-Recvd-Size: 9378 Received: from smtp-fw-9102.amazon.com (smtp-fw-9102.amazon.com [207.171.184.29]) by imf49.hostedemail.com (Postfix) with ESMTP for ; Wed, 3 Jun 2020 07:15:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.com; i=@amazon.com; q=dns/txt; s=amazon201209; t=1591168530; x=1622704530; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=X6i6w4308U7MssGOPnWQCHrHplMgVvfXOTZA9gwf2cg=; b=sJBOEfXaySUC2HAwePQdtjA7+x6U4zS7KvkfxBdhC+4fpn9QjuniJQXA 794BYYXuBNqBYftD+/nWh2JRqYG6YFbBXNBACJiXO1HPcrutIa8hOCPLx UNAJIOsrVa6FrTJDIe6WwLkp2Cemut9Ub2vsj1zzHdwAHzeqGvhJRhWht M=; IronPort-SDR: JihEk3tq+L/k3x8K4/LXkgaonWgVC1AK9wdZnbsingnf+fkoKZSA+hRyss0GeRA7I4Ik+FihAp zHW/JgQPkQNA== X-IronPort-AV: E=Sophos;i="5.73,467,1583193600"; d="scan'208";a="49422701" Received: from sea32-co-svc-lb4-vlan3.sea.corp.amazon.com (HELO email-inbound-relay-1e-c7c08562.us-east-1.amazon.com) ([10.47.23.38]) by smtp-border-fw-out-9102.sea19.amazon.com with ESMTP; 03 Jun 2020 07:15:25 +0000 Received: from EX13MTAUEA002.ant.amazon.com (iad55-ws-svc-p15-lb9-vlan2.iad.amazon.com [10.40.159.162]) by email-inbound-relay-1e-c7c08562.us-east-1.amazon.com (Postfix) with ESMTPS id EB6DF24252F; Wed, 3 Jun 2020 07:15:22 +0000 (UTC) Received: from EX13D31EUA001.ant.amazon.com (10.43.165.15) by EX13MTAUEA002.ant.amazon.com (10.43.61.77) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 3 Jun 2020 07:15:22 +0000 Received: from u886c93fd17d25d.ant.amazon.com (10.43.160.26) by EX13D31EUA001.ant.amazon.com (10.43.165.15) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 3 Jun 2020 07:15:06 +0000 From: SeongJae Park To: CC: SeongJae Park , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [RFC v10 4/8] mm/damon/schemes: Implement a debugfs interface Date: Wed, 3 Jun 2020 09:11:34 +0200 Message-ID: <20200603071138.8152-5-sjpark@amazon.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200603071138.8152-1-sjpark@amazon.com> References: <20200603071138.8152-1-sjpark@amazon.com> MIME-Version: 1.0 X-Originating-IP: [10.43.160.26] X-ClientProxiedBy: EX13D10UWB003.ant.amazon.com (10.43.161.106) To EX13D31EUA001.ant.amazon.com (10.43.165.15) X-Rspamd-Queue-Id: 1A46A80081D1 X-Spamd-Result: default: False [0.00 / 100.00] X-Rspamd-Server: rspam03 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 a debugfs interface for the data access monitoring oriented memory management schemes. It is supposed to be used by administrators and/or privileged user space programs. Users can read and update the rules using ``/damon/schemes`` file. The format is:: Signed-off-by: SeongJae Park --- mm/damon.c | 176 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 174 insertions(+), 2 deletions(-) diff --git a/mm/damon.c b/mm/damon.c index ffb755a14447..909599e6e5bc 100644 --- a/mm/damon.c +++ b/mm/damon.c @@ -173,6 +173,29 @@ static void damon_destroy_task(struct damon_task *t) damon_free_task(t); } +static struct damos *damon_new_scheme( + unsigned int min_sz_region, unsigned int 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; +} + static void damon_add_scheme(struct damon_ctx *ctx, struct damos *s) { list_add_tail(&s->list, &ctx->schemes_list); @@ -1353,6 +1376,149 @@ static ssize_t debugfs_monitor_on_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 = snprintf(&buf[written], len - written, + "%u %u %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 debugfs_schemes_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct damon_ctx *ctx = &damon_user_ctx; + 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); +} + +/* + * 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 int min_sz, max_sz, 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], "%u %u %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 (action >= DAMOS_ACTION_LEN) { + 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; + } + if (!*nr_schemes) + goto fail; + return schemes; +fail: + free_schemes_arr(schemes, *nr_schemes); + return NULL; +} + +static ssize_t debugfs_schemes_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct damon_ctx *ctx = &damon_user_ctx; + char *kbuf; + struct damos **schemes; + ssize_t nr_schemes = 0, ret; + int err; + + if (*ppos) + return -EINVAL; + + kbuf = kmalloc(count, GFP_KERNEL); + if (!kbuf) + return -ENOMEM; + + ret = simple_write_to_buffer(kbuf, count, ppos, buf, count); + if (ret < 0) + goto out; + + schemes = str_to_schemes(kbuf, ret, &nr_schemes); + + 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; +} + static ssize_t damon_sprint_pids(struct damon_ctx *ctx, char *buf, ssize_t len) { struct damon_task *t; @@ -1584,6 +1750,12 @@ static const struct file_operations pids_fops = { .write = debugfs_pids_write, }; +static const struct file_operations schemes_fops = { + .owner = THIS_MODULE, + .read = debugfs_schemes_read, + .write = debugfs_schemes_write, +}; + static const struct file_operations record_fops = { .owner = THIS_MODULE, .read = debugfs_record_read, @@ -1600,10 +1772,10 @@ static struct dentry *debugfs_root; static int __init damon_debugfs_init(void) { - const char * const file_names[] = {"attrs", "record", + const char * const file_names[] = {"attrs", "record", "schemes", "pids", "monitor_on"}; const struct file_operations *fops[] = {&attrs_fops, &record_fops, - &pids_fops, &monitor_on_fops}; + &schemes_fops, &pids_fops, &monitor_on_fops}; int i; debugfs_root = debugfs_create_dir("damon", NULL); From patchwork Wed Jun 3 07:11:35 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: SeongJae Park X-Patchwork-Id: 11585183 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D9DF1618 for ; Wed, 3 Jun 2020 07:16:02 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id 9D7DA206E6 for ; Wed, 3 Jun 2020 07:16:02 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=amazon.com header.i=@amazon.com header.b="BRHMLM4W" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 9D7DA206E6 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 DE6CC80009; Wed, 3 Jun 2020 03:16:01 -0400 (EDT) Delivered-To: linux-mm-outgoing@kvack.org Received: by kanga.kvack.org (Postfix, from userid 40) id D96F08E0006; Wed, 3 Jun 2020 03:16:01 -0400 (EDT) X-Original-To: int-list-linux-mm@kvack.org X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id C0DDC80009; Wed, 3 Jun 2020 03:16:01 -0400 (EDT) X-Original-To: linux-mm@kvack.org X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0058.hostedemail.com [216.40.44.58]) by kanga.kvack.org (Postfix) with ESMTP id A243B8E0006 for ; Wed, 3 Jun 2020 03:16:01 -0400 (EDT) Received: from smtpin16.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay03.hostedemail.com (Postfix) with ESMTP id 4E202824556B for ; Wed, 3 Jun 2020 07:16:01 +0000 (UTC) X-FDA: 76887041322.16.heat17_5194950220e2c Received: from filter.hostedemail.com (10.5.16.251.rfc1918.com [10.5.16.251]) by smtpin16.hostedemail.com (Postfix) with ESMTP id 2A93C100E690C for ; Wed, 3 Jun 2020 07:16:01 +0000 (UTC) X-Spam-Summary: 1,0,0,,d41d8cd98f00b204,prvs=416e8e2f5=sjpark@amazon.com,,RULES_HIT:30004:30034:30054:30056:30064:30070,0,RBL:207.171.190.10:@amazon.com:.lbl8.mailshell.net-66.10.201.10 62.18.0.100,CacheIP:none,Bayesian:0.5,0.5,0.5,Netcheck:none,DomainCache:0,MSF:not bulk,SPF:fp,MSBL:0,DNSBL:neutral,Custom_rules:0:0:0,LFtime:29,LUA_SUMMARY:none X-HE-Tag: heat17_5194950220e2c X-Filterd-Recvd-Size: 7348 Received: from smtp-fw-33001.amazon.com (smtp-fw-33001.amazon.com [207.171.190.10]) by imf16.hostedemail.com (Postfix) with ESMTP for ; Wed, 3 Jun 2020 07:16:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.com; i=@amazon.com; q=dns/txt; s=amazon201209; t=1591168561; x=1622704561; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=ep+MdSv8eQP3ckds5U0F+W6+o9V8F3cfwHm67gssntY=; b=BRHMLM4WxylQrWLEBv5ejiw+3Mj1mZetGtojQvNEK4ahB7jNrsCbpcb9 N6A6WmGtwNO5essxLdKXPUttnuLnt4OyrAQ3wA1mfBBpd7I9ykldyvkeG 4GKPsjq+64EvU6ihzxiwsa3y5zJqA3WGKcBfiYnZmwj9ogLdi0BWUTGNa Y=; IronPort-SDR: KjSI6WhbtiAd87PusXIS49PaAJPWCoIBu+1+a9ZWxF2V5uyIbiF9K6dnsnVCVzKw13MB4P3Q8M t/xJORm2aYzg== X-IronPort-AV: E=Sophos;i="5.73,467,1583193600"; d="scan'208";a="48089333" Received: from sea32-co-svc-lb4-vlan2.sea.corp.amazon.com (HELO email-inbound-relay-1a-67b371d8.us-east-1.amazon.com) ([10.47.23.34]) by smtp-border-fw-out-33001.sea14.amazon.com with ESMTP; 03 Jun 2020 07:15:56 +0000 Received: from EX13MTAUEA002.ant.amazon.com (iad55-ws-svc-p15-lb9-vlan3.iad.amazon.com [10.40.159.166]) by email-inbound-relay-1a-67b371d8.us-east-1.amazon.com (Postfix) with ESMTPS id 8BB75A21DB; Wed, 3 Jun 2020 07:15:44 +0000 (UTC) Received: from EX13D31EUA001.ant.amazon.com (10.43.165.15) by EX13MTAUEA002.ant.amazon.com (10.43.61.77) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 3 Jun 2020 07:15:43 +0000 Received: from u886c93fd17d25d.ant.amazon.com (10.43.160.26) by EX13D31EUA001.ant.amazon.com (10.43.165.15) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 3 Jun 2020 07:15:27 +0000 From: SeongJae Park To: CC: SeongJae Park , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [RFC v10 5/8] mm/damon/schemes: Implement statistics feature Date: Wed, 3 Jun 2020 09:11:35 +0200 Message-ID: <20200603071138.8152-6-sjpark@amazon.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200603071138.8152-1-sjpark@amazon.com> References: <20200603071138.8152-1-sjpark@amazon.com> MIME-Version: 1.0 X-Originating-IP: [10.43.160.26] X-ClientProxiedBy: EX13D10UWB003.ant.amazon.com (10.43.161.106) To EX13D31EUA001.ant.amazon.com (10.43.165.15) X-Rspamd-Queue-Id: 2A93C100E690C X-Spamd-Result: default: False [0.00 / 100.00] X-Rspamd-Server: rspam05 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 | 6 ++++++ mm/damon.c | 13 ++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/include/linux/damon.h b/include/linux/damon.h index 842a01e80c6e..e77256cf30dd 100644 --- a/include/linux/damon.h +++ b/include/linux/damon.h @@ -64,6 +64,7 @@ struct damon_task { * @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. * @DAMOS_ACTION_LEN: Number of supported actions. */ enum damos_action { @@ -72,6 +73,7 @@ enum damos_action { DAMOS_PAGEOUT, DAMOS_HUGEPAGE, DAMOS_NOHUGEPAGE, + DAMOS_STAT, /* Do nothing but only record the stat */ DAMOS_ACTION_LEN, }; @@ -84,6 +86,8 @@ 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. * * For each aggregation interval, DAMON applies @action to monitoring target @@ -98,6 +102,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.c b/mm/damon.c index 909599e6e5bc..ea6a8b6886b8 100644 --- a/mm/damon.c +++ b/mm/damon.c @@ -191,6 +191,8 @@ static 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; @@ -771,6 +773,8 @@ static int damos_do_action(struct damon_task *task, struct damon_region *r, case DAMOS_NOHUGEPAGE: madv_action = MADV_NOHUGEPAGE; break; + case DAMOS_STAT: + return 0; default: pr_warn("Wrong action %d\n", action); return -EINVAL; @@ -798,8 +802,11 @@ static void damon_do_apply_schemes(struct damon_ctx *c, struct damon_task *t, (s->max_age_region && s->max_age_region < r->age)) continue; + s->stat_count++; + s->stat_sz += sz; damos_do_action(t, r, s->action); - r->age = 0; + if (s->action != DAMOS_STAT) + r->age = 0; } } @@ -1384,11 +1391,11 @@ static ssize_t sprint_schemes(struct damon_ctx *c, char *buf, ssize_t len) damon_for_each_scheme(s, c) { rc = snprintf(&buf[written], len - written, - "%u %u %u %u %u %u %d\n", + "%u %u %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; From patchwork Wed Jun 3 07:11:36 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: SeongJae Park X-Patchwork-Id: 11585185 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id BFA521392 for ; Wed, 3 Jun 2020 07:16:39 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id 8CB01207DA for ; Wed, 3 Jun 2020 07:16:39 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=amazon.com header.i=@amazon.com header.b="D8zNBCyy" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 8CB01207DA 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 CAC0880007; Wed, 3 Jun 2020 03:16:38 -0400 (EDT) Delivered-To: linux-mm-outgoing@kvack.org Received: by kanga.kvack.org (Postfix, from userid 40) id C85458E0006; Wed, 3 Jun 2020 03:16:38 -0400 (EDT) X-Original-To: int-list-linux-mm@kvack.org X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id B72E080007; Wed, 3 Jun 2020 03:16:38 -0400 (EDT) X-Original-To: linux-mm@kvack.org X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0253.hostedemail.com [216.40.44.253]) by kanga.kvack.org (Postfix) with ESMTP id 9FAA98E0006 for ; Wed, 3 Jun 2020 03:16:38 -0400 (EDT) Received: from smtpin18.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay05.hostedemail.com (Postfix) with ESMTP id 63156181AEF07 for ; Wed, 3 Jun 2020 07:16:38 +0000 (UTC) X-FDA: 76887042876.18.crate39_5701f325cfa61 Received: from filter.hostedemail.com (10.5.16.251.rfc1918.com [10.5.16.251]) by smtpin18.hostedemail.com (Postfix) with ESMTP id 48304100ED0D2 for ; Wed, 3 Jun 2020 07:16:38 +0000 (UTC) X-Spam-Summary: 1,0,0,,d41d8cd98f00b204,prvs=416e8e2f5=sjpark@amazon.com,,RULES_HIT:30054:30056:30064,0,RBL:207.171.184.25:@amazon.com:.lbl8.mailshell.net-62.18.0.100 66.10.201.10,CacheIP:none,Bayesian:0.5,0.5,0.5,Netcheck:none,DomainCache:0,MSF:not bulk,SPF:fp,MSBL:0,DNSBL:neutral,Custom_rules:0:0:0,LFtime:24,LUA_SUMMARY:none X-HE-Tag: crate39_5701f325cfa61 X-Filterd-Recvd-Size: 4418 Received: from smtp-fw-9101.amazon.com (smtp-fw-9101.amazon.com [207.171.184.25]) by imf06.hostedemail.com (Postfix) with ESMTP for ; Wed, 3 Jun 2020 07:16:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.com; i=@amazon.com; q=dns/txt; s=amazon201209; t=1591168598; x=1622704598; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=b5EEY//uUmxww4MeXLoOfsSYKFHirbB/BqQ/qTWvUzg=; b=D8zNBCyyodtsCS/0Xplfb3QcEXN/2uugHVgbMuw2jURapSOUnf3MSUVg NcCVBQRA/Cw1/42joyxU+7DMkBnJpH08mql1YFBVDt/tz5xVY7qxKoDJZ aGQknEFJrHwN6b84IFyiZlYAP390Ylayg73k/ddK0JizD8DjryrLfytTS s=; IronPort-SDR: /k0QNW6GRPzb8OtPKZHEuh76x8xYBrNQC11dfck1XE1vsqINY3dtEni+N4FDMfQIwaCrbaB9MX W+dmU762QwWQ== X-IronPort-AV: E=Sophos;i="5.73,467,1583193600"; d="scan'208";a="41160802" Received: from sea32-co-svc-lb4-vlan3.sea.corp.amazon.com (HELO email-inbound-relay-1d-98acfc19.us-east-1.amazon.com) ([10.47.23.38]) by smtp-border-fw-out-9101.sea19.amazon.com with ESMTP; 03 Jun 2020 07:16:33 +0000 Received: from EX13MTAUEA002.ant.amazon.com (iad55-ws-svc-p15-lb9-vlan3.iad.amazon.com [10.40.159.166]) by email-inbound-relay-1d-98acfc19.us-east-1.amazon.com (Postfix) with ESMTPS id 7019EA184B; Wed, 3 Jun 2020 07:16:20 +0000 (UTC) Received: from EX13D31EUA001.ant.amazon.com (10.43.165.15) by EX13MTAUEA002.ant.amazon.com (10.43.61.77) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 3 Jun 2020 07:16:19 +0000 Received: from u886c93fd17d25d.ant.amazon.com (10.43.160.26) by EX13D31EUA001.ant.amazon.com (10.43.165.15) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 3 Jun 2020 07:16:03 +0000 From: SeongJae Park To: CC: SeongJae Park , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [RFC v10 6/8] mm/damon/selftests: Add 'schemes' debugfs tests Date: Wed, 3 Jun 2020 09:11:36 +0200 Message-ID: <20200603071138.8152-7-sjpark@amazon.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200603071138.8152-1-sjpark@amazon.com> References: <20200603071138.8152-1-sjpark@amazon.com> MIME-Version: 1.0 X-Originating-IP: [10.43.160.26] X-ClientProxiedBy: EX13D10UWB003.ant.amazon.com (10.43.161.106) To EX13D31EUA001.ant.amazon.com (10.43.165.15) X-Rspamd-Queue-Id: 48304100ED0D2 X-Spamd-Result: default: False [0.00 / 100.00] X-Rspamd-Server: rspam02 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 d5188b0f71b1..4aeb2037a67e 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 pids file file="$DBGFS/pids" From patchwork Wed Jun 3 07:11:37 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: SeongJae Park X-Patchwork-Id: 11585187 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 9E4B014F6 for ; Wed, 3 Jun 2020 07:16:55 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id 4380B206E6 for ; Wed, 3 Jun 2020 07:16:55 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=amazon.com header.i=@amazon.com header.b="UB6YJ5IR" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 4380B206E6 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 61D1F80008; Wed, 3 Jun 2020 03:16:54 -0400 (EDT) Delivered-To: linux-mm-outgoing@kvack.org Received: by kanga.kvack.org (Postfix, from userid 40) id 5CB9F8E0006; Wed, 3 Jun 2020 03:16:54 -0400 (EDT) X-Original-To: int-list-linux-mm@kvack.org X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 46BDF80008; Wed, 3 Jun 2020 03:16:54 -0400 (EDT) X-Original-To: linux-mm@kvack.org X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0162.hostedemail.com [216.40.44.162]) by kanga.kvack.org (Postfix) with ESMTP id 2BBA28E0006 for ; Wed, 3 Jun 2020 03:16:54 -0400 (EDT) Received: from smtpin26.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay02.hostedemail.com (Postfix) with ESMTP id E02722C94 for ; Wed, 3 Jun 2020 07:16:53 +0000 (UTC) X-FDA: 76887043506.26.rail08_59188ab387d51 Received: from filter.hostedemail.com (10.5.16.251.rfc1918.com [10.5.16.251]) by smtpin26.hostedemail.com (Postfix) with ESMTP id B0F2F1804B3A0 for ; Wed, 3 Jun 2020 07:16:52 +0000 (UTC) X-Spam-Summary: 1,0,0,,d41d8cd98f00b204,prvs=416e8e2f5=sjpark@amazon.com,,RULES_HIT:30004:30029:30034:30054:30064:30070:30079:30091,0,RBL:72.21.196.25:@amazon.com:.lbl8.mailshell.net-66.10.201.10 62.18.0.100,CacheIP:none,Bayesian:0.5,0.5,0.5,Netcheck:none,DomainCache:0,MSF:not bulk,SPF:fp,MSBL:0,DNSBL:none,Custom_rules:0:0:0,LFtime:23,LUA_SUMMARY:none X-HE-Tag: rail08_59188ab387d51 X-Filterd-Recvd-Size: 26671 Received: from smtp-fw-2101.amazon.com (smtp-fw-2101.amazon.com [72.21.196.25]) by imf07.hostedemail.com (Postfix) with ESMTP for ; Wed, 3 Jun 2020 07:16:52 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.com; i=@amazon.com; q=dns/txt; s=amazon201209; t=1591168612; x=1622704612; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=y54FAGw4Y+hLggKCc15IeRYf7UGRlRoCBLlCsLSOMKI=; b=UB6YJ5IRj2LALK7q+KnIhW0o1lXpSzdpFovYp/R5EMxD2gfOlyBOXNkD 4IiZ/g09a1cdYWSt+mhcrXjbkhPUEesXzyRHkXs7jB6VnIeanmpljtj/F OOHl04QbbDTOpHnocrZmj2M4z5e6cNTTOJuMVIV46+aYtpSJ6OahyFSUd k=; IronPort-SDR: ETfr/QstDIeGNf2ViUpqS3o7ghj59qFQygq8yeHWNYcJcgufkaA409UFa56EKxx+gEDfiYXypa HtQPKVkotcjg== X-IronPort-AV: E=Sophos;i="5.73,467,1583193600"; d="scan'208";a="34200096" Received: from iad12-co-svc-p1-lb1-vlan2.amazon.com (HELO email-inbound-relay-1d-474bcd9f.us-east-1.amazon.com) ([10.43.8.2]) by smtp-border-fw-out-2101.iad2.amazon.com with ESMTP; 03 Jun 2020 07:16:52 +0000 Received: from EX13MTAUEA002.ant.amazon.com (iad55-ws-svc-p15-lb9-vlan2.iad.amazon.com [10.40.159.162]) by email-inbound-relay-1d-474bcd9f.us-east-1.amazon.com (Postfix) with ESMTPS id 2AF37A2747; Wed, 3 Jun 2020 07:16:40 +0000 (UTC) Received: from EX13D31EUA001.ant.amazon.com (10.43.165.15) by EX13MTAUEA002.ant.amazon.com (10.43.61.77) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 3 Jun 2020 07:16:40 +0000 Received: from u886c93fd17d25d.ant.amazon.com (10.43.160.26) by EX13D31EUA001.ant.amazon.com (10.43.165.15) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 3 Jun 2020 07:16:24 +0000 From: SeongJae Park To: CC: SeongJae Park , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [RFC v10 7/8] damon/tools: Support more human friendly 'schemes' control Date: Wed, 3 Jun 2020 09:11:37 +0200 Message-ID: <20200603071138.8152-8-sjpark@amazon.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200603071138.8152-1-sjpark@amazon.com> References: <20200603071138.8152-1-sjpark@amazon.com> MIME-Version: 1.0 X-Originating-IP: [10.43.160.26] X-ClientProxiedBy: EX13D10UWB003.ant.amazon.com (10.43.161.106) To EX13D31EUA001.ant.amazon.com (10.43.165.15) X-Rspamd-Queue-Id: B0F2F1804B3A0 X-Spamd-Result: default: False [0.00 / 100.00] X-Rspamd-Server: rspam02 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 | 128 ++++++++++++++++++++++++++++++ tools/damon/_damon.py | 143 ++++++++++++++++++++++++++++++++++ tools/damon/damo | 7 ++ tools/damon/record.py | 135 +++----------------------------- tools/damon/schemes.py | 105 +++++++++++++++++++++++++ 5 files changed, 395 insertions(+), 123 deletions(-) create mode 100755 tools/damon/_convert_damos.py create mode 100644 tools/damon/_damon.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..23cd52980a89 --- /dev/null +++ b/tools/damon/_convert_damos.py @@ -0,0 +1,128 @@ +#!/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 + # 'null' means zero for size and age. + + # if a region keeps a high access frequency for more than 100ms, put the + # region on the head of the LRU list (call madvise() with MADV_WILLNEED). + null null 80 null 100ms 0s willneed + + # if a region keeps a low access frequency for more than 200ms and less + # than one hour, put the # region on the tail of the LRU list (call + # madvise() with MADV_COLD). + 0B 0B 10 20 200ms 1h cold + + # if a region keeps a very low access frequency for more than 1 minute, + # swap out the region immediately (call madvise() with MADV_PAGEOUT). + 0B null 0 10 60s 0s pageout + + # if a region of a size bigger than 2MiB keeps a very high access frequency + # for more than 100ms, let the region to use huge pages (call madvise() + # with MADV_HUGEPAGE). + 2M null 90 99 100ms 0s hugepage + + # If a regions of a size bigger than 2MiB keeps small access frequency for + # more than 100ms, avoid the region using huge pages (call madvise() with + # MADV_NOHUGEPAGE). + 2M null 0 25 100ms 0s nohugepage +""" + +import argparse + +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 == 'null': + return 0 + unit = txt[-1] + number = int(txt[:-1]) + return 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_us(txt): + if txt == 'null': + return 0 + unit = txt[-2:] + if unit in ['us', 'ms']: + number = int(txt[:-2]) + else: + unit = txt[-1] + number = int(txt[:-1]) + return number * unit_to_usecs[unit] + +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 == 'null': + return 0 + return int(int(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_us(fields[4]) / aggr_interval + max_age = text_to_us(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 new file mode 100644 index 000000000000..0a703ec7471a --- /dev/null +++ b/tools/damon/_damon.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0 + +""" +Contains core functions for DAMON debugfs control. +""" + +import os +import subprocess + +debugfs_attrs = None +debugfs_record = None +debugfs_schemes = None +debugfs_pids = None +debugfs_monitor_on = None + +def set_target_pid(pid): + return subprocess.call('echo %s > %s' % (pid, debugfs_pids), shell=True, + executable='/bin/bash') + +def turn_damon(on_off): + return subprocess.call("echo %s > %s" % (on_off, debugfs_monitor_on), + shell=True, executable="/bin/bash") + +def is_damon_running(): + with open(debugfs_monitor_on, 'r') as f: + return f.read().strip() == 'on' + +class Attrs: + sample_interval = None + aggr_interval = None + regions_update_interval = None + min_nr_regions = None + max_nr_regions = None + rbuf_len = None + rfile_path = None + schemes = None + + def __init__(self, s, a, r, n, x, l, f, c): + self.sample_interval = s + self.aggr_interval = a + self.regions_update_interval = r + self.min_nr_regions = n + 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\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.schemes) + + def attr_str(self): + return "%s %s %s %s %s " % (self.sample_interval, self.aggr_interval, + self.regions_update_interval, self.min_nr_regions, + self.max_nr_regions) + + def record_str(self): + return '%s %s ' % (self.rbuf_len, self.rfile_path) + + def apply(self): + ret = subprocess.call('echo %s > %s' % (self.attr_str(), debugfs_attrs), + shell=True, executable='/bin/bash') + if ret: + return ret + ret = subprocess.call('echo %s > %s' % (self.record_str(), + 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: + attrs = f.read().split() + attrs = [int(x) for x in attrs] + + with open(debugfs_record, 'r') as f: + rattrs = f.read().split() + attrs.append(int(rattrs[0])) + attrs.append(rattrs[1]) + + with open(debugfs_schemes, 'r') as f: + schemes = f.read() + attrs.append(schemes) + + return Attrs(*attrs) + +def chk_update_debugfs(debugfs): + global debugfs_attrs + global debugfs_record + global debugfs_schemes + global debugfs_pids + 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_pids = os.path.join(debugfs_damon, 'pids') + debugfs_monitor_on = os.path.join(debugfs_damon, 'monitor_on') + + if not os.path.isdir(debugfs_damon): + print("damon debugfs dir (%s) not found", debugfs_damon) + exit(1) + + for f in [debugfs_attrs, debugfs_record, debugfs_schemes, debugfs_pids, + debugfs_monitor_on]: + if not os.path.isfile(f): + print("damon debugfs file (%s) not found" % f) + exit(1) + +def cmd_args_to_attrs(args): + "Generate attributes with specified arguments" + sample_interval = args.sample + aggr_interval = args.aggr + regions_update_interval = args.updr + min_nr_regions = args.minr + max_nr_regions = args.maxr + rbuf_len = args.rbuf + 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, schemes) + +def set_attrs_argparser(parser): + parser.add_argument('-d', '--debugfs', metavar='', type=str, + default='/sys/kernel/debug', help='debugfs mounted path') + parser.add_argument('-s', '--sample', metavar='', type=int, + default=5000, help='sampling interval') + parser.add_argument('-a', '--aggr', metavar='', type=int, + default=100000, help='aggregate interval') + parser.add_argument('-u', '--updr', metavar='', type=int, + default=1000000, help='regions update interval') + parser.add_argument('-n', '--minr', metavar='<# regions>', type=int, + default=10, help='minimal number of regions') + parser.add_argument('-m', '--maxr', metavar='<# regions>', type=int, + default=1000, help='maximum number of regions') 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/record.py b/tools/damon/record.py index a547d479a103..3bbf7b8359da 100644 --- a/tools/damon/record.py +++ b/tools/damon/record.py @@ -6,28 +6,12 @@ Record data access patterns of the target process. """ import argparse -import copy import os import signal import subprocess import time -debugfs_attrs = None -debugfs_record = None -debugfs_pids = None -debugfs_monitor_on = None - -def set_target_pid(pid): - return subprocess.call('echo %s > %s' % (pid, debugfs_pids), shell=True, - executable='/bin/bash') - -def turn_damon(on_off): - return subprocess.call("echo %s > %s" % (on_off, debugfs_monitor_on), - shell=True, executable="/bin/bash") - -def is_damon_running(): - with open(debugfs_monitor_on, 'r') as f: - return f.read().strip() == 'on' +import _damon def do_record(target, is_target_cmd, attrs, old_attrs): if os.path.isfile(attrs.rfile_path): @@ -36,93 +20,29 @@ def do_record(target, is_target_cmd, attrs, old_attrs): if attrs.apply(): print('attributes (%s) failed to be applied' % attrs) cleanup_exit(old_attrs, -1) - print('# damon attrs: %s' % attrs) + print('# damon attrs: %s %s' % (attrs.attr_str(), attrs.record_str())) if is_target_cmd: p = subprocess.Popen(target, shell=True, executable='/bin/bash') target = p.pid - if set_target_pid(target): + if _damon.set_target_pid(target): print('pid setting (%s) failed' % target) cleanup_exit(old_attrs, -2) - if turn_damon('on'): + if _damon.turn_damon('on'): print('could not turn on damon' % target) cleanup_exit(old_attrs, -3) if is_target_cmd: p.wait() while True: # damon will turn it off by itself if the target tasks are terminated. - if not is_damon_running(): + if not _damon.is_damon_running(): break time.sleep(1) cleanup_exit(old_attrs, 0) -class Attrs: - sample_interval = None - aggr_interval = None - regions_update_interval = None - min_nr_regions = None - max_nr_regions = None - rbuf_len = None - rfile_path = None - - def __init__(self, s, a, r, n, x, l, f): - self.sample_interval = s - self.aggr_interval = a - self.regions_update_interval = r - self.min_nr_regions = n - self.max_nr_regions = x - self.rbuf_len = l - self.rfile_path = f - - def __str__(self): - return "%s %s %s %s %s %s %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) - - def attr_str(self): - return "%s %s %s %s %s " % (self.sample_interval, self.aggr_interval, - self.regions_update_interval, self.min_nr_regions, - self.max_nr_regions) - - def record_str(self): - return '%s %s ' % (self.rbuf_len, self.rfile_path) - - def apply(self): - ret = subprocess.call('echo %s > %s' % (self.attr_str(), debugfs_attrs), - shell=True, executable='/bin/bash') - if ret: - return ret - return subprocess.call('echo %s > %s' % (self.record_str(), - debugfs_record), shell=True, executable='/bin/bash') - -def current_attrs(): - with open(debugfs_attrs, 'r') as f: - attrs = f.read().split() - attrs = [int(x) for x in attrs] - - with open(debugfs_record, 'r') as f: - rattrs = f.read().split() - attrs.append(int(rattrs[0])) - attrs.append(rattrs[1]) - return Attrs(*attrs) - -def cmd_args_to_attrs(args): - "Generate attributes with specified arguments" - sample_interval = args.sample - aggr_interval = args.aggr - regions_update_interval = args.updr - min_nr_regions = args.minr - max_nr_regions = args.maxr - rbuf_len = args.rbuf - if not os.path.isabs(args.out): - args.out = os.path.join(os.getcwd(), args.out) - rfile_path = args.out - return Attrs(sample_interval, aggr_interval, regions_update_interval, - min_nr_regions, max_nr_regions, rbuf_len, rfile_path) - def cleanup_exit(orig_attrs, exit_code): - if is_damon_running(): - if turn_damon('off'): + if _damon.is_damon_running(): + if _damon.turn_damon('off'): print('failed to turn damon off!') if orig_attrs: if orig_attrs.apply(): @@ -133,51 +53,19 @@ def sighandler(signum, frame): print('\nsignal %s received' % signum) cleanup_exit(orig_attrs, signum) -def chk_update_debugfs(debugfs): - global debugfs_attrs - global debugfs_record - global debugfs_pids - 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_pids = os.path.join(debugfs_damon, 'pids') - debugfs_monitor_on = os.path.join(debugfs_damon, 'monitor_on') - - if not os.path.isdir(debugfs_damon): - print("damon debugfs dir (%s) not found", debugfs_damon) - exit(1) - - for f in [debugfs_attrs, debugfs_record, debugfs_pids, debugfs_monitor_on]: - if not os.path.isfile(f): - print("damon debugfs file (%s) not found" % f) - exit(1) - 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('-s', '--sample', metavar='', type=int, - default=5000, help='sampling interval') - parser.add_argument('-a', '--aggr', metavar='', type=int, - default=100000, help='aggregate interval') - parser.add_argument('-u', '--updr', metavar='', type=int, - default=1000000, help='regions update interval') - parser.add_argument('-n', '--minr', metavar='<# regions>', type=int, - default=10, help='minimal number of regions') - parser.add_argument('-m', '--maxr', metavar='<# regions>', type=int, - default=1000, help='maximum number of regions') parser.add_argument('-l', '--rbuf', metavar='', type=int, default=1024*1024, help='length of record result buffer') parser.add_argument('-o', '--out', metavar='', type=str, default='damon.data', help='output file path') - parser.add_argument('-d', '--debugfs', metavar='', type=str, - default='/sys/kernel/debug', help='debugfs mounted path') def main(args=None): global orig_attrs @@ -187,13 +75,14 @@ def main(args=None): args = parser.parse_args() chk_permission() - chk_update_debugfs(args.debugfs) + _damon.chk_update_debugfs(args.debugfs) signal.signal(signal.SIGINT, sighandler) signal.signal(signal.SIGTERM, sighandler) - orig_attrs = current_attrs() + orig_attrs = _damon.current_attrs() - new_attrs = cmd_args_to_attrs(args) + args.schemes = '' + new_attrs = _damon.cmd_args_to_attrs(args) target = args.target target_fields = target.split() diff --git a/tools/damon/schemes.py b/tools/damon/schemes.py new file mode 100644 index 000000000000..ca1551fe5696 --- /dev/null +++ b/tools/damon/schemes.py @@ -0,0 +1,105 @@ +#!/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) + 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!') + 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 Jun 3 07:11:38 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: SeongJae Park X-Patchwork-Id: 11585189 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 034B0618 for ; Wed, 3 Jun 2020 07:17:13 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id B854E2077D for ; Wed, 3 Jun 2020 07:17:12 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=amazon.com header.i=@amazon.com header.b="jTfbjODX" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org B854E2077D 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 E59C780009; Wed, 3 Jun 2020 03:17:11 -0400 (EDT) Delivered-To: linux-mm-outgoing@kvack.org Received: by kanga.kvack.org (Postfix, from userid 40) id E2F598E0006; Wed, 3 Jun 2020 03:17:11 -0400 (EDT) X-Original-To: int-list-linux-mm@kvack.org X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id D45CC80009; Wed, 3 Jun 2020 03:17:11 -0400 (EDT) X-Original-To: linux-mm@kvack.org X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0106.hostedemail.com [216.40.44.106]) by kanga.kvack.org (Postfix) with ESMTP id BC1018E0006 for ; Wed, 3 Jun 2020 03:17:11 -0400 (EDT) Received: from smtpin02.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay01.hostedemail.com (Postfix) with ESMTP id 79593180AD80F for ; Wed, 3 Jun 2020 07:17:11 +0000 (UTC) X-FDA: 76887044262.02.card55_5bcb70811932c Received: from filter.hostedemail.com (10.5.16.251.rfc1918.com [10.5.16.251]) by smtpin02.hostedemail.com (Postfix) with ESMTP id 4467D283C for ; Wed, 3 Jun 2020 07:17:11 +0000 (UTC) X-Spam-Summary: 1,0,0,,d41d8cd98f00b204,prvs=416e8e2f5=sjpark@amazon.com,,RULES_HIT:30004:30012:30029:30030:30034:30046:30051:30054:30064:30070:30091,0,RBL:52.95.49.90:@amazon.com:.lbl8.mailshell.net-62.18.0.100 64.10.201.10,CacheIP:none,Bayesian:0.5,0.5,0.5,Netcheck:none,DomainCache:0,MSF:not bulk,SPF:fp,MSBL:0,DNSBL:neutral,Custom_rules:0:0:0,LFtime:24,LUA_SUMMARY:none X-HE-Tag: card55_5bcb70811932c X-Filterd-Recvd-Size: 13862 Received: from smtp-fw-6002.amazon.com (smtp-fw-6002.amazon.com [52.95.49.90]) by imf06.hostedemail.com (Postfix) with ESMTP for ; Wed, 3 Jun 2020 07:17:10 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.com; i=@amazon.com; q=dns/txt; s=amazon201209; t=1591168630; x=1622704630; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=8jbiJMomd06EaRq+QA8EnTiiCmockST/nj/2ObjvRCs=; b=jTfbjODXLEMJ6RyXk6KV6MmbNmFjsc9aG67Ms/MWtNqiUmIWuRr3jARU HnKRAB2RaLsLwtWR5Vuivw9nABj4N4Y9DWMDtCsga1RtZKV8DeGoK3rDj 7x5pgC5dE+utK5U8uWiAVIxE3yh4S7+ybdT7dg+PRryrEcYPHbjbrGtxJ 0=; IronPort-SDR: FZ8fOzwmmuCWYVLdoTKP4UM8gooSI1cb8padt5Y0GJqfYnMXYeqhksAnxefEFqdUEZlOYp2AmB k1RqTujA2LOw== X-IronPort-AV: E=Sophos;i="5.73,467,1583193600"; d="scan'208";a="34064390" Received: from iad12-co-svc-p1-lb1-vlan3.amazon.com (HELO email-inbound-relay-1a-67b371d8.us-east-1.amazon.com) ([10.43.8.6]) by smtp-border-fw-out-6002.iad6.amazon.com with ESMTP; 03 Jun 2020 07:17:10 +0000 Received: from EX13MTAUEA002.ant.amazon.com (iad55-ws-svc-p15-lb9-vlan3.iad.amazon.com [10.40.159.166]) by email-inbound-relay-1a-67b371d8.us-east-1.amazon.com (Postfix) with ESMTPS id 586EDA245C; Wed, 3 Jun 2020 07:16:59 +0000 (UTC) Received: from EX13D31EUA001.ant.amazon.com (10.43.165.15) by EX13MTAUEA002.ant.amazon.com (10.43.61.77) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 3 Jun 2020 07:16:58 +0000 Received: from u886c93fd17d25d.ant.amazon.com (10.43.160.26) by EX13D31EUA001.ant.amazon.com (10.43.165.15) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 3 Jun 2020 07:16:42 +0000 From: SeongJae Park To: CC: SeongJae Park , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: [RFC v10 8/8] Documentation/admin-guide/mm: Document DAMON-based operation schemes Date: Wed, 3 Jun 2020 09:11:38 +0200 Message-ID: <20200603071138.8152-9-sjpark@amazon.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200603071138.8152-1-sjpark@amazon.com> References: <20200603071138.8152-1-sjpark@amazon.com> MIME-Version: 1.0 X-Originating-IP: [10.43.160.26] X-ClientProxiedBy: EX13D10UWB003.ant.amazon.com (10.43.161.106) To EX13D31EUA001.ant.amazon.com (10.43.165.15) X-Rspamd-Queue-Id: 4467D283C X-Spamd-Result: default: False [0.00 / 100.00] X-Rspamd-Server: rspam01 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 documents DAMON-based operation schemes in the DAMON document. Signed-off-by: SeongJae Park --- Documentation/admin-guide/mm/damon/guide.rst | 35 +++++ Documentation/admin-guide/mm/damon/usage.rst | 127 +++++++++++++++++-- 2 files changed, 152 insertions(+), 10 deletions(-) diff --git a/Documentation/admin-guide/mm/damon/guide.rst b/Documentation/admin-guide/mm/damon/guide.rst index 4a840d1b02d4..c10f65ce721c 100644 --- a/Documentation/admin-guide/mm/damon/guide.rst +++ b/Documentation/admin-guide/mm/damon/guide.rst @@ -55,6 +55,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 Optimization`_. +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. + You don't need to take only one approach among the above plans, but you could use multiple of the above approaches to maximize the benefit. If you still want to absorb more benefits, you should develop `Personalized DAMON @@ -158,6 +163,36 @@ object is the hot object. The chronological changes of working set size. +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]_, [3]_. + +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 ------------------------------ diff --git a/Documentation/admin-guide/mm/damon/usage.rst b/Documentation/admin-guide/mm/damon/usage.rst index 1aa4f66e4320..18a19c35b4f3 100644 --- a/Documentation/admin-guide/mm/damon/usage.rst +++ b/Documentation/admin-guide/mm/damon/usage.rst @@ -228,11 +228,71 @@ 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 + # 'null' means zero for size and age. + + # 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). + null null 80 null 100ms 0s willneed + + # if a region keeps a low access frequency at least 200ms and at most one + # hour, put the region on the tail of the LRU list (call madvise() with + # MADV_COLD). + 0B 0B 10 20 200ms 1h cold + + # if a region keeps a very low access frequency for >=1 minute, swap + # out the region immediately (call madvise() with MADV_PAGEOUT). + 0B null 0 10 60s 0s 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 null 90 99 100ms 0s hugepage + + # If a region of a size >=2MiB keeps small access frequency for >=100ms, + # avoid the region using huge pages (call madvise() with MADV_NOHUGEPAGE). + 2M null 0 25 100ms 0s 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 null 90 99 100ms 0s hugepage" > my_thp_scheme + $ ./damo schemes --schemes my_thp_scheme `pidof foo` + + debugfs Interface ================= -DAMON exports four files, ``attrs``, ``pids``, ``record``, and ``monitor_on`` -under its debugfs directory, ``/damon/``. +DAMON exports five files, ``attrs``, ``pids``, ``record``, ``schemes`` and +``monitor_on`` under its debugfs directory, ``/damon/``. Attributes @@ -282,17 +342,64 @@ saved in ``/damon.data``. :: 4096 /damon.data +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 >=4KiB is +showing <=5 accesses per aggregate interval (0 5) for >=5 aggregate interval (5 +0), page out the region (2)", check the entered scheme again, and finally +remove the scheme. :: + + # cd /damon + # echo "4096 0 0 5 5 0 2" > schemes + # cat schemes + 4096 0 0 5 5 0 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 -------------- -Setting the attributes as described above doesn't incur effect unless you -explicitly start the monitoring. You can start, stop, and check the current -status of the monitoring by writing to and reading from the ``monitor_on`` -file. Writing ``on`` to the file make DAMON start monitoring of the target -processes with the attributes. Recording will also start if requested before. -Writing ``off`` to the file stops those. DAMON also stops if every target -process is terminated. Below example commands turn on, off, and check the -status of DAMON:: +Setting the attributes and schemes as described above doesn't incur effect +unless you explicitly start the monitoring. You can start, stop, and check +the current status of the monitoring by writing to and reading from the +``monitor_on`` file. Writing ``on`` to the file make DAMON start monitoring +of the target processes with the attributes. Recording and schemes applying +will also start if requested before. Writing ``off`` to the file stops those. +DAMON also stops if every target process is terminated. Below example +commands turn on, off, and check the status of DAMON:: # cd /damon # echo on > monitor_on