From: Roman Gushchin <roman.gushchin@linux.dev>
To: Hillf Danton <hdanton@sina.com>
Cc: Andrew Morton <akpm@linux-foundation.org>,
linux-mm@kvack.org, Dave Chinner <dchinner@redhat.com>,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH v2 3/7] mm: introduce memcg interfaces for shrinker debugfs
Date: Fri, 22 Apr 2022 18:29:34 -0700 [thread overview]
Message-ID: <YmNWfgh5/WEwUkFi@carbon> (raw)
In-Reply-To: <20220423003552.2914-1-hdanton@sina.com>
On Sat, Apr 23, 2022 at 08:35:52AM +0800, Hillf Danton wrote:
> On Fri, 22 Apr 2022 13:26:40 -0700 Roman Gushchin wrote:
> > This commit introduces "count_memcg" and "scan_memcg" interfaces
> > for memcg-aware shrinkers.
> >
> > Count_memcg using the following format:
> > <cgroup inode number1> <count2>
> > <cgroup inode number2> <count2>
> > ...
> >
> > Memory cgroups with 0 associated objects are skipped.
> >
> > Signed-off-by: Roman Gushchin <roman.gushchin@linux.dev>
> > ---
> > mm/shrinker_debug.c | 186 +++++++++++++++++++++++++++++++++-----------
> > 1 file changed, 139 insertions(+), 47 deletions(-)
> >
> > diff --git a/mm/shrinker_debug.c b/mm/shrinker_debug.c
> > index 4df7382a0737..002d44d6ad56 100644
> > --- a/mm/shrinker_debug.c
> > +++ b/mm/shrinker_debug.c
> > @@ -1,8 +1,10 @@
> > // SPDX-License-Identifier: GPL-2.0
> > #include <linux/idr.h>
> > +#include <linux/slab.h>
> > #include <linux/debugfs.h>
> > #include <linux/seq_file.h>
> > #include <linux/shrinker.h>
> > +#include <linux/memcontrol.h>
> >
> > /* defined in vmscan.c */
> > extern struct rw_semaphore shrinker_rwsem;
> > @@ -11,25 +13,25 @@ extern struct list_head shrinker_list;
> > static DEFINE_IDA(shrinker_debugfs_ida);
> > static struct dentry *shrinker_debugfs_root;
> >
> > -static int shrinker_debugfs_count_show(struct seq_file *m, void *v)
> > +static unsigned long shrinker_count_objects(struct shrinker *shrinker,
> > + struct mem_cgroup *memcg,
> > + unsigned long *count_per_node)
> > {
> > - struct shrinker *shrinker = (struct shrinker *)m->private;
> > unsigned long nr, total = 0;
> > - int ret, nid;
> > -
> > - ret = down_read_killable(&shrinker_rwsem);
> > - if (ret)
> > - return ret;
> > + int nid;
> >
> > for_each_node(nid) {
> > struct shrink_control sc = {
> > .gfp_mask = GFP_KERNEL,
> > .nid = nid,
> > + .memcg = memcg,
> > };
> >
> > nr = shrinker->count_objects(shrinker, &sc);
> > if (nr == SHRINK_EMPTY)
> > nr = 0;
> > + if (count_per_node)
> > + count_per_node[nid] = nr;
> > total += nr;
> >
> > if (!(shrinker->flags & SHRINKER_NUMA_AWARE))
> > @@ -37,32 +39,17 @@ static int shrinker_debugfs_count_show(struct seq_file *m, void *v)
> >
> > cond_resched();
>
> Nit, add a line in response to signal before schedule, given the
> killable above.
Good point, thanks!
>
> > }
> > - up_read(&shrinker_rwsem);
> > -
> > - seq_printf(m, "%lu\n", total);
> >
> > - return ret;
> > + return total;
> > }
> > -DEFINE_SHOW_ATTRIBUTE(shrinker_debugfs_count);
> >
> > -static ssize_t shrinker_debugfs_scan_write(struct file *file,
> > - const char __user *buf,
> > - size_t size, loff_t *pos)
> > +static int shrinker_scan_objects(struct shrinker *shrinker,
> > + struct mem_cgroup *memcg,
> > + unsigned long nr_to_scan)
> > {
> > - struct shrinker *shrinker = (struct shrinker *)file->private_data;
> > - unsigned long nr, total = 0, nr_to_scan;
> > - unsigned long *count_per_node = NULL;
> > - int nid;
> > - char kbuf[24];
> > - int read_len = size < (sizeof(kbuf) - 1) ? size : (sizeof(kbuf) - 1);
> > - ssize_t ret;
> > -
> > - if (copy_from_user(kbuf, buf, read_len))
> > - return -EFAULT;
> > - kbuf[read_len] = '\0';
> > -
> > - if (kstrtoul(kbuf, 10, &nr_to_scan))
> > - return -EINVAL;
> > + unsigned long *count_per_node;
> > + unsigned long total, nr;
> > + int ret, nid;
> >
> > ret = down_read_killable(&shrinker_rwsem);
> > if (ret)
> > @@ -80,20 +67,7 @@ static ssize_t shrinker_debugfs_scan_write(struct file *file,
> > goto out;
> > }
> >
> > - for_each_node(nid) {
> > - struct shrink_control sc = {
> > - .gfp_mask = GFP_KERNEL,
> > - .nid = nid,
> > - };
> > -
> > - nr = shrinker->count_objects(shrinker, &sc);
> > - if (nr == SHRINK_EMPTY)
> > - nr = 0;
> > - count_per_node[nid] = nr;
> > - total += nr;
> > -
> > - cond_resched();
> > - }
> > + total = shrinker_count_objects(shrinker, memcg, count_per_node);
> > }
> >
> > for_each_node(nid) {
> > @@ -102,13 +76,13 @@ static ssize_t shrinker_debugfs_scan_write(struct file *file,
> > .nid = nid,
> > };
> >
> > - if (shrinker->flags & SHRINKER_NUMA_AWARE) {
> > + if (count_per_node) {
> > sc.nr_to_scan = nr_to_scan * count_per_node[nid] /
> > (total ? total : 1);
> > sc.nr_scanned = sc.nr_to_scan;
> > } else {
> > sc.nr_to_scan = nr_to_scan;
> > - sc.nr_scanned = sc.nr_to_scan;
> > + sc.nr_scanned = nr_to_scan;
> > }
> >
> > nr = shrinker->scan_objects(shrinker, &sc);
> > @@ -119,15 +93,51 @@ static ssize_t shrinker_debugfs_scan_write(struct file *file,
> > break;
> >
> > cond_resched();
> > -
> > }
> > - ret = size;
> > out:
> > up_read(&shrinker_rwsem);
> > kfree(count_per_node);
> > return ret;
> > }
> >
> > +static int shrinker_debugfs_count_show(struct seq_file *m, void *v)
> > +{
> > + struct shrinker *shrinker = (struct shrinker *)m->private;
> > + int ret;
> > +
> > + ret = down_read_killable(&shrinker_rwsem);
> > + if (!ret) {
> > + unsigned long total = shrinker_count_objects(shrinker, NULL, NULL);
> > +
> > + up_read(&shrinker_rwsem);
> > + seq_printf(m, "%lu\n", total);
> > + }
> > + return ret;
> > +}
> > +DEFINE_SHOW_ATTRIBUTE(shrinker_debugfs_count);
> > +
> > +static ssize_t shrinker_debugfs_scan_write(struct file *file,
> > + const char __user *buf,
> > + size_t size, loff_t *pos)
> > +{
> > + struct shrinker *shrinker = (struct shrinker *)file->private_data;
> > + unsigned long nr_to_scan;
> > + char kbuf[24];
> > + int read_len = size < (sizeof(kbuf) - 1) ? size : (sizeof(kbuf) - 1);
> > + ssize_t ret;
> > +
> > + if (copy_from_user(kbuf, buf, read_len))
> > + return -EFAULT;
> > + kbuf[read_len] = '\0';
> > +
> > + if (kstrtoul(kbuf, 10, &nr_to_scan))
> > + return -EINVAL;
> > +
> > + ret = shrinker_scan_objects(shrinker, NULL, nr_to_scan);
> > +
> > + return ret ? ret : size;
> > +}
> > +
> > static int shrinker_debugfs_scan_open(struct inode *inode, struct file *file)
> > {
> > file->private_data = inode->i_private;
> > @@ -140,6 +150,78 @@ static const struct file_operations shrinker_debugfs_scan_fops = {
> > .write = shrinker_debugfs_scan_write,
> > };
> >
> > +#ifdef CONFIG_MEMCG
> > +static int shrinker_debugfs_count_memcg_show(struct seq_file *m, void *v)
> > +{
> > + struct shrinker *shrinker = (struct shrinker *)m->private;
> > + struct mem_cgroup *memcg;
> > + unsigned long total;
> > + int ret;
> > +
> > + ret = down_read_killable(&shrinker_rwsem);
> > + if (ret)
> > + return ret;
> > + rcu_read_lock();
>
> A minute ... things like cond_resched() or mutex in individual shrinker
> implementation can ruin your nice work within two seconds. The bigger
> pain is can we rule them out from coming shrinkers?
Hm, why? Isn't it the same path as in reclaim? Can you, please, elaborate?
next prev parent reply other threads:[~2022-04-23 1:29 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-04-22 20:26 [PATCH v2 0/7] mm: introduce shrinker debugfs interface Roman Gushchin
2022-04-22 20:26 ` [PATCH v2 1/7] mm: introduce debugfs interface for kernel memory shrinkers Roman Gushchin
2022-04-23 7:51 ` Christophe JAILLET
2022-04-23 7:51 ` Christophe JAILLET
2022-04-22 20:26 ` [PATCH v2 2/7] mm: memcontrol: introduce mem_cgroup_ino() and mem_cgroup_get_from_ino() Roman Gushchin
2022-04-22 20:26 ` [PATCH v2 3/7] mm: introduce memcg interfaces for shrinker debugfs Roman Gushchin
2022-04-23 0:35 ` Hillf Danton
2022-04-23 1:29 ` Roman Gushchin [this message]
2022-04-22 20:26 ` [PATCH v2 4/7] mm: introduce numa " Roman Gushchin
2022-04-22 20:26 ` [PATCH v2 5/7] mm: provide shrinkers with names Roman Gushchin
2022-04-23 7:46 ` Christophe JAILLET
2022-04-23 7:46 ` Christophe JAILLET
2022-04-28 0:25 ` Roman Gushchin
2022-04-22 20:26 ` [PATCH v2 6/7] docs: document shrinker debugfs Roman Gushchin
2022-04-22 20:26 ` [PATCH v2 7/7] tools: add memcg_shrinker.py Roman Gushchin
2022-04-26 6:02 ` [PATCH v2 0/7] mm: introduce shrinker debugfs interface Dave Chinner
2022-04-26 6:45 ` Kent Overstreet
2022-04-26 8:45 ` Hillf Danton
2022-04-26 16:41 ` Roman Gushchin
2022-04-26 18:37 ` Kent Overstreet
2022-04-27 1:22 ` Dave Chinner
2022-04-27 2:18 ` Roman Gushchin
2022-04-26 19:05 ` Roman Gushchin
2022-04-27 1:02 ` Dave Chinner
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=YmNWfgh5/WEwUkFi@carbon \
--to=roman.gushchin@linux.dev \
--cc=akpm@linux-foundation.org \
--cc=dchinner@redhat.com \
--cc=hdanton@sina.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.