aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChun-Kuang Hu <chunkuang.hu@kernel.org>2021-05-04 07:33:29 +0800
committerChun-Kuang Hu <chunkuang.hu@kernel.org>2022-07-13 22:58:48 +0800
commit7b43af7f4b48c1abb6df811dbaa644a0c7800366 (patch)
treeab60a452fbbea3b42cf2560bc8405f71a7d6c445
parent4c94316bc3660946fd42ec2bc6220e0d78c0c83d (diff)
downloadlinux-pagecaller.tar.gz
mm: vmstat: add pagecaller informationpagecaller
cat /proc/pagecaller to show size of memory allocated by each caller. Signed-off-by: Chun-Kuang Hu <chunkuang.hu@kernel.org>
-rw-r--r--mm/vmstat.c98
1 files changed, 98 insertions, 0 deletions
diff --git a/mm/vmstat.c b/mm/vmstat.c
index 373d2730fcf215..f8c26e50401f73 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -23,6 +23,7 @@
#include <linux/debugfs.h>
#include <linux/sched.h>
#include <linux/math64.h>
+#include <linux/memblock.h>
#include <linux/writeback.h>
#include <linux/compaction.h>
#include <linux/mm_inline.h>
@@ -1486,6 +1487,91 @@ static int frag_show(struct seq_file *m, void *arg)
return 0;
}
+#ifdef CONFIG_PAGECALLER
+#define PAGECALLER_MAX 65536
+static unsigned long pagecaller_nr;
+static unsigned long pagecaller[PAGECALLER_MAX];
+static unsigned long pagecaller_cnt[PAGECALLER_MAX];
+
+static void insert_pagecaller(unsigned long caller)
+{
+ unsigned long i;
+
+ for (i = 0; i < pagecaller_nr; i++)
+ if (pagecaller[i] == caller)
+ break;
+
+ if (i == pagecaller_nr) {
+ if (i < PAGECALLER_MAX) {
+ pagecaller[i] = caller;
+ pagecaller_cnt[i] = 1;
+ pagecaller_nr++;
+ }
+ } else {
+ pagecaller_cnt[i]++;
+ }
+}
+
+static void sort_pagecaller(void)
+{
+ unsigned long i, j, tmp;
+
+ for (i = 0; i < (pagecaller_nr - 1); i++)
+ for (j = i + 1; j < pagecaller_nr; j++)
+ if (pagecaller_cnt[i] > pagecaller[j]) {
+ tmp = pagecaller[i];
+ pagecaller[i] = pagecaller[j];
+ pagecaller[j] = tmp;
+
+ tmp = pagecaller_cnt[i];
+ pagecaller_cnt[i] = pagecaller_cnt[j];
+ pagecaller_cnt[j] = tmp;
+ }
+}
+
+static void dump_pagecaller(struct seq_file *m)
+{
+ unsigned long i;
+
+ seq_printf(m, "max_pfn = %lu\n", max_pfn);
+ seq_printf(m, "pagecaller_nr = %lu\n", pagecaller_nr);
+
+ for (i = 0; i < pagecaller_nr; i++)
+ if (pagecaller[i] == 0) {
+ seq_printf(m, "0x%016lx %16lu [Free memory]\n",
+ pagecaller[i], pagecaller_cnt[i] * 4);
+ } else if (pagecaller[i] == 0xffffffffffffffff) {
+ seq_printf(m, "0x%016lx %16lu [Reserved memory]\n",
+ pagecaller[i], pagecaller_cnt[i] * 4);
+ } else {
+#ifdef CONFIG_KALLSYMS
+ char symbol[KSYM_SYMBOL_LEN];
+ kallsyms_lookup(pagecaller[i], NULL, NULL, NULL, symbol);
+ seq_printf(m, "0x%016lx %16lu %s\n", pagecaller[i],
+ pagecaller_cnt[i] * 4, symbol);
+#else
+ seq_printf(m, "0x%016lx %16lu\n", pagecaller[i],
+ pagecaller_cnt[i] * 4);
+#endif
+ }
+}
+
+static int pagecaller_show(struct seq_file *m, void *arg)
+{
+ unsigned long pfn;
+
+ pagecaller_nr = 0;
+
+ for (pfn = 0; pfn < max_pfn; pfn++)
+ insert_pagecaller(pagecaller_get(pfn));
+
+ sort_pagecaller();
+ dump_pagecaller(m);
+
+ return 0;
+}
+#endif
+
static void pagetypeinfo_showfree_print(struct seq_file *m,
pg_data_t *pgdat, struct zone *zone)
{
@@ -1644,6 +1730,15 @@ static const struct seq_operations fragmentation_op = {
.show = frag_show,
};
+#ifdef CONFIG_PAGECALLER
+static const struct seq_operations pagecaller_op = {
+ .start = frag_start,
+ .next = frag_next,
+ .stop = frag_stop,
+ .show = pagecaller_show,
+};
+#endif
+
static const struct seq_operations pagetypeinfo_op = {
.start = frag_start,
.next = frag_next,
@@ -2121,6 +2216,9 @@ void __init init_mm_internals(void)
migrate_on_reclaim_init();
#ifdef CONFIG_PROC_FS
proc_create_seq("buddyinfo", 0444, NULL, &fragmentation_op);
+#ifdef CONFIG_PAGECALLER
+ proc_create_seq("pagecaller", 0444, NULL, &pagecaller_op);
+#endif
proc_create_seq("pagetypeinfo", 0400, NULL, &pagetypeinfo_op);
proc_create_seq("vmstat", 0444, NULL, &vmstat_op);
proc_create_seq("zoneinfo", 0444, NULL, &zoneinfo_op);