linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
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?


  reply	other threads:[~2022-04-23  1:29 UTC|newest]

Thread overview: 22+ 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-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-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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).