From: Roman Gushchin <roman.gushchin@linux.dev>
To: Andrew Morton <akpm@linux-foundation.org>, linux-mm@kvack.org
Cc: Dave Chinner <dchinner@redhat.com>,
linux-kernel@vger.kernel.org, Yang Shi <shy828301@gmail.com>,
Kent Overstreet <kent.overstreet@gmail.com>,
Hillf Danton <hdanton@sina.com>,
Roman Gushchin <roman.gushchin@linux.dev>
Subject: [PATCH v2 4/7] mm: introduce numa interfaces for shrinker debugfs
Date: Fri, 22 Apr 2022 13:26:41 -0700 [thread overview]
Message-ID: <20220422202644.799732-5-roman.gushchin@linux.dev> (raw)
In-Reply-To: <20220422202644.799732-1-roman.gushchin@linux.dev>
This commit introduces "count_node", "scan_node", "count_memcg_node"
and "scan_memcg_node" interfaces for numa-aware and numa- and
memcg-aware shrinkers.
Usage examples:
1) Get per-node and per-memcg per-node counts:
$ cat count_node
209 3
$ cat count_memcg_node
1 209 3
20 96 0
53 810 7
2297 2 0
218 13 0
581 30 0
911 124 0
<CUT>
2) Scan individual node:
$ echo "1 200" > scan_node
$ cat scan_node
2
3) Scan individual memcg and node:
$ echo "1868 0 500" > scan_memcg_node
$ cat scan_memcg_node
435
Signed-off-by: Roman Gushchin <roman.gushchin@linux.dev>
---
mm/shrinker_debug.c | 200 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 200 insertions(+)
diff --git a/mm/shrinker_debug.c b/mm/shrinker_debug.c
index 002d44d6ad56..81350b64bf01 100644
--- a/mm/shrinker_debug.c
+++ b/mm/shrinker_debug.c
@@ -222,6 +222,185 @@ static const struct file_operations shrinker_debugfs_scan_memcg_fops = {
};
#endif
+#ifdef CONFIG_NUMA
+static int shrinker_debugfs_count_node_show(struct seq_file *m, void *v)
+{
+ struct shrinker *shrinker = (struct shrinker *)m->private;
+ unsigned long nr;
+ int ret, nid;
+
+ ret = down_read_killable(&shrinker_rwsem);
+ if (ret)
+ return ret;
+
+ 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;
+
+ seq_printf(m, "%s%lu", nid ? " " : "", nr);
+ cond_resched();
+ }
+ up_read(&shrinker_rwsem);
+ seq_puts(m, "\n");
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(shrinker_debugfs_count_node);
+
+static ssize_t shrinker_debugfs_scan_node_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 = 0;
+ int nid;
+ struct shrink_control sc = {
+ .gfp_mask = GFP_KERNEL,
+ };
+ char kbuf[48];
+ 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 (sscanf(kbuf, "%d %lu", &nid, &nr_to_scan) < 2)
+ return -EINVAL;
+
+ if (nid < 0 || nid >= nr_node_ids)
+ return -EINVAL;
+
+ ret = down_read_killable(&shrinker_rwsem);
+ if (ret)
+ return ret;
+
+ sc.nid = nid;
+ sc.nr_to_scan = nr_to_scan;
+ sc.nr_scanned = nr_to_scan;
+
+ shrinker->scan_objects(shrinker, &sc);
+
+ up_read(&shrinker_rwsem);
+
+ return ret ? ret : size;
+}
+
+static const struct file_operations shrinker_debugfs_scan_node_fops = {
+ .owner = THIS_MODULE,
+ .open = shrinker_debugfs_scan_open,
+ .write = shrinker_debugfs_scan_node_write,
+};
+
+#ifdef CONFIG_MEMCG
+static int shrinker_debugfs_count_memcg_node_show(struct seq_file *m, void *v)
+{
+ struct shrinker *shrinker = (struct shrinker *)m->private;
+ unsigned long *count_per_node = NULL;
+ struct mem_cgroup *memcg;
+ unsigned long total;
+ int ret, nid;
+
+ count_per_node = kcalloc(nr_node_ids, sizeof(unsigned long), GFP_KERNEL);
+ if (!count_per_node)
+ return -ENOMEM;
+
+ ret = down_read_killable(&shrinker_rwsem);
+ if (ret) {
+ kfree(count_per_node);
+ return ret;
+ }
+ rcu_read_lock();
+
+ memcg = mem_cgroup_iter(NULL, NULL, NULL);
+ do {
+ if (!mem_cgroup_online(memcg))
+ continue;
+
+ total = shrinker_count_objects(shrinker, memcg, count_per_node);
+ if (!total)
+ continue;
+
+ seq_printf(m, "%lu", mem_cgroup_ino(memcg));
+ for_each_node(nid)
+ seq_printf(m, " %lu", count_per_node[nid]);
+ seq_puts(m, "\n");
+ } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL)) != NULL);
+
+ rcu_read_unlock();
+ up_read(&shrinker_rwsem);
+
+ kfree(count_per_node);
+ return ret;
+}
+DEFINE_SHOW_ATTRIBUTE(shrinker_debugfs_count_memcg_node);
+
+static ssize_t shrinker_debugfs_scan_memcg_node_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 = 0, ino;
+ struct shrink_control sc = {
+ .gfp_mask = GFP_KERNEL,
+ };
+ struct mem_cgroup *memcg;
+ int nid;
+ char kbuf[72];
+ 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 (sscanf(kbuf, "%lu %d %lu", &ino, &nid, &nr_to_scan) < 2)
+ return -EINVAL;
+
+ if (nid < 0 || nid >= nr_node_ids)
+ return -EINVAL;
+
+ memcg = mem_cgroup_get_from_ino(ino);
+ if (!memcg || IS_ERR(memcg))
+ return -ENOENT;
+
+ if (!mem_cgroup_online(memcg)) {
+ mem_cgroup_put(memcg);
+ return -ENOENT;
+ }
+
+ ret = down_read_killable(&shrinker_rwsem);
+ if (ret) {
+ mem_cgroup_put(memcg);
+ return ret;
+ }
+
+ sc.nid = nid;
+ sc.memcg = memcg;
+ sc.nr_to_scan = nr_to_scan;
+ sc.nr_scanned = nr_to_scan;
+
+ shrinker->scan_objects(shrinker, &sc);
+
+ up_read(&shrinker_rwsem);
+ mem_cgroup_put(memcg);
+
+ return ret ? ret : size;
+}
+
+static const struct file_operations shrinker_debugfs_scan_memcg_node_fops = {
+ .owner = THIS_MODULE,
+ .open = shrinker_debugfs_scan_open,
+ .write = shrinker_debugfs_scan_memcg_node_write,
+};
+#endif /* CONFIG_MEMCG */
+#endif /* CONFIG_NUMA */
+
int shrinker_debugfs_add(struct shrinker *shrinker)
{
struct dentry *entry;
@@ -265,6 +444,27 @@ int shrinker_debugfs_add(struct shrinker *shrinker)
}
#endif
+#ifdef CONFIG_NUMA
+ /* create numa and memcg/numa interfaces */
+ if ((shrinker->flags & SHRINKER_NUMA_AWARE) && nr_node_ids > 1) {
+ debugfs_create_file("count_node", 0220, entry, shrinker,
+ &shrinker_debugfs_count_node_fops);
+ debugfs_create_file("scan_node", 0440, entry, shrinker,
+ &shrinker_debugfs_scan_node_fops);
+
+#ifdef CONFIG_MEMCG
+ if (shrinker->flags & SHRINKER_MEMCG_AWARE) {
+ debugfs_create_file("count_memcg_node", 0220, entry,
+ shrinker,
+ &shrinker_debugfs_count_memcg_node_fops);
+ debugfs_create_file("scan_memcg_node", 0440, entry,
+ shrinker,
+ &shrinker_debugfs_scan_memcg_node_fops);
+ }
+#endif /* CONFIG_MEMCG */
+ }
+#endif /* CONFIG_NUMA */
+
return 0;
}
--
2.35.1
next prev parent reply other threads:[~2022-04-22 20:27 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
2022-04-22 20:26 ` Roman Gushchin [this message]
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=20220422202644.799732-5-roman.gushchin@linux.dev \
--to=roman.gushchin@linux.dev \
--cc=akpm@linux-foundation.org \
--cc=dchinner@redhat.com \
--cc=hdanton@sina.com \
--cc=kent.overstreet@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=shy828301@gmail.com \
/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).