From: Oscar Salvador <osalvador@suse.de>
To: Andrew Morton <akpm@linux-foundation.org>
Cc: linux-kernel@vger.kernel.org, linux-mm@kvack.org,
Michal Hocko <mhocko@suse.com>, Vlastimil Babka <vbabka@suse.cz>,
Waiman Long <longman@redhat.com>,
Suren Baghdasaryan <surenb@google.com>,
Marco Elver <elver@google.com>,
Andrey Konovalov <andreyknvl@gmail.com>,
Eric Dumazet <edumazet@google.com>,
Alexander Potapenko <glider@google.com>,
Oscar Salvador <osalvador@suse.de>
Subject: [PATCH v6 3/4] mm,page_owner: Add page_owner_stacks file to print out only stacks and their counter
Date: Mon, 20 Nov 2023 09:42:59 +0100 [thread overview]
Message-ID: <20231120084300.4368-4-osalvador@suse.de> (raw)
In-Reply-To: <20231120084300.4368-1-osalvador@suse.de>
We are not interested in the owner of each individual pfn,
but how many outstanding allocations are there for each unique
allocating stack trace.
Right now, getting that information is quite hard as one needs
to fiddle with page_owner output, screen through pfns and make
the links.
So, instead, let us add a new file called 'page_owner_stacks'
that shows just that.
Such file will only show the stacktrace once followed by its
counter, which represents the number of outstanding allocations.
Signed-off-by: Oscar Salvador <osalvador@suse.de>
---
include/linux/stackdepot.h | 2 +
lib/stackdepot.c | 29 +++++++++++++
mm/page_owner.c | 87 ++++++++++++++++++++++++++++++++++++++
3 files changed, 118 insertions(+)
diff --git a/include/linux/stackdepot.h b/include/linux/stackdepot.h
index 269a828a5e94..09c478b1bf73 100644
--- a/include/linux/stackdepot.h
+++ b/include/linux/stackdepot.h
@@ -146,6 +146,8 @@ void stack_depot_dec_count(depot_stack_handle_t handle);
depot_stack_handle_t stack_depot_save(unsigned long *entries,
unsigned int nr_entries, gfp_t gfp_flags);
+struct stack_record *stack_depot_get_next_stack(unsigned long *table,
+ struct stack_record *curr_stack);
/**
* stack_depot_fetch - Fetch a stack trace from stack depot
*
diff --git a/lib/stackdepot.c b/lib/stackdepot.c
index 1343d3095bc1..65708c0c1e50 100644
--- a/lib/stackdepot.c
+++ b/lib/stackdepot.c
@@ -452,6 +452,35 @@ static struct stack_record *stack_depot_getstack(depot_stack_handle_t handle)
return stack;
}
+struct stack_record *stack_depot_get_next_stack(unsigned long *table,
+ struct stack_record *curr_stack)
+{
+ unsigned long nr_table = *table;
+ struct stack_record *next = NULL, **stacks;
+ unsigned long stack_table_entries = stack_hash_mask + 1;
+
+ if (!curr_stack) {
+ if (nr_table) {
+new_table:
+ nr_table++;
+ if (nr_table >= stack_table_entries)
+ goto out;
+ }
+ stacks = &stack_table[nr_table];
+ curr_stack = (struct stack_record *)stacks;
+ next = curr_stack;
+ } else {
+ next = curr_stack->next;
+ }
+
+ if (!next)
+ goto new_table;
+
+out:
+ *table = nr_table;
+ return next;
+}
+
unsigned int stack_depot_fetch(depot_stack_handle_t handle,
unsigned long **entries)
{
diff --git a/mm/page_owner.c b/mm/page_owner.c
index d53316d0d9be..509c11e506db 100644
--- a/mm/page_owner.c
+++ b/mm/page_owner.c
@@ -719,6 +719,91 @@ static const struct file_operations proc_page_owner_operations = {
.llseek = lseek_page_owner,
};
+static void *stack_start(struct seq_file *m, loff_t *ppos)
+{
+ unsigned long *nr_table = m->private;
+ void *stack;
+
+ /* First time */
+ if (*ppos == 0)
+ *nr_table = 0;
+
+ if (*ppos == -1UL)
+ return NULL;
+
+ stack = stack_depot_get_next_stack(nr_table, NULL);
+
+ return stack;
+}
+
+static void *stack_next(struct seq_file *m, void *v, loff_t *ppos)
+{
+ unsigned long *nr_table = m->private;
+ void *next_stack;
+
+ next_stack = stack_depot_get_next_stack(nr_table, v);
+ *ppos = next_stack ? *ppos + 1 : -1UL;
+
+ return next_stack;
+}
+
+static int stack_depot_get_stack_info(struct stack_record *stack, char *buf)
+{
+ if (!stack->size || stack->size < 0 ||
+ stack->size > PAGE_SIZE || stack->handle.valid != 1 ||
+ refcount_read(&stack->count) < 1)
+ return 0;
+
+ return stack_trace_snprint(buf, PAGE_SIZE, stack->entries, stack->size, 0);
+}
+
+static int stack_print(struct seq_file *m, void *v)
+{
+ char *buf;
+ int ret = 0;
+ struct stack_record *stack = (struct stack_record *)v;
+
+ buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+
+ ret += stack_depot_get_stack_info(stack, buf);
+ if (!ret)
+ goto out;
+
+ scnprintf(buf + ret, PAGE_SIZE - ret, "stack_count: %d\n\n",
+ refcount_read(&stack->count));
+
+ seq_printf(m, buf);
+ seq_puts(m, "\n\n");
+out:
+ kfree(buf);
+
+ return 0;
+}
+
+static void stack_stop(struct seq_file *m, void *v)
+{
+}
+
+static const struct seq_operations page_owner_stack_op = {
+ .start = stack_start,
+ .next = stack_next,
+ .stop = stack_stop,
+ .show = stack_print
+};
+
+static int page_owner_stack_open(struct inode *inode, struct file *file)
+{
+ return seq_open_private(file, &page_owner_stack_op,
+ sizeof(unsigned long));
+}
+
+const struct file_operations page_owner_stack_operations = {
+ .open = page_owner_stack_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
static int __init pageowner_init(void)
{
if (!static_branch_unlikely(&page_owner_inited)) {
@@ -728,6 +813,8 @@ static int __init pageowner_init(void)
debugfs_create_file("page_owner", 0400, NULL, NULL,
&proc_page_owner_operations);
+ debugfs_create_file("page_owner_stacks", 0400, NULL, NULL,
+ &page_owner_stack_operations);
return 0;
}
--
2.42.0
next prev parent reply other threads:[~2023-11-20 8:43 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-11-20 8:42 [PATCH v6 0/4] page_owner: print " Oscar Salvador
2023-11-20 8:42 ` [PATCH v6 1/4] lib/stackdepot: Add a refcount field in stack_record Oscar Salvador
2023-11-20 8:42 ` [PATCH v6 2/4] lib/stackdepot: Move stack_record struct definition into the header Oscar Salvador
2023-11-20 8:42 ` Oscar Salvador [this message]
2023-11-20 8:43 ` [PATCH v6 4/4] mm,page_owner: Filter out stacks by a threshold counter Oscar Salvador
2023-11-20 14:17 ` kernel test robot
2023-11-20 19:52 ` kernel test robot
2023-11-20 9:07 ` [PATCH v6 0/4] page_owner: print stacks and their counter Vlastimil Babka
2023-11-20 17:54 ` Andrey Konovalov
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=20231120084300.4368-4-osalvador@suse.de \
--to=osalvador@suse.de \
--cc=akpm@linux-foundation.org \
--cc=andreyknvl@gmail.com \
--cc=edumazet@google.com \
--cc=elver@google.com \
--cc=glider@google.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=longman@redhat.com \
--cc=mhocko@suse.com \
--cc=surenb@google.com \
--cc=vbabka@suse.cz \
/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