lib: add version into /proc/allocinfo output
authorSuren Baghdasaryan <surenb@google.com>
Tue, 14 May 2024 16:31:28 +0000 (09:31 -0700)
committerAndrew Morton <akpm@linux-foundation.org>
Fri, 24 May 2024 18:55:05 +0000 (11:55 -0700)
Add version string and a header at the beginning of /proc/allocinfo to
allow later format changes.  Example output:

> head /proc/allocinfo
allocinfo - version: 1.0
#     <size>  <calls> <tag info>
           0        0 init/main.c:1314 func:do_initcalls
           0        0 init/do_mounts.c:353 func:mount_nodev_root
           0        0 init/do_mounts.c:187 func:mount_root_generic
           0        0 init/do_mounts.c:158 func:do_mount_root
           0        0 init/initramfs.c:493 func:unpack_to_rootfs
           0        0 init/initramfs.c:492 func:unpack_to_rootfs
           0        0 init/initramfs.c:491 func:unpack_to_rootfs
         512        1 arch/x86/events/rapl.c:681 func:init_rapl_pmus
         128        1 arch/x86/events/rapl.c:571 func:rapl_cpu_online

[akpm@linux-foundation.org: remove stray newline from struct allocinfo_private]
Link: https://lkml.kernel.org/r/20240514163128.3662251-1-surenb@google.com
Signed-off-by: Suren Baghdasaryan <surenb@google.com>
Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
Cc: Kent Overstreet <kent.overstreet@linux.dev>
Cc: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Documentation/filesystems/proc.rst
lib/alloc_tag.c

index 4d97258a7954f0631084a06161086371d43d319a..7c3a565ffbef3712d525f6a37c77ffd79ea88132 100644 (file)
@@ -961,13 +961,14 @@ Provides information about memory allocations at all locations in the code
 base. Each allocation in the code is identified by its source file, line
 number, module (if originates from a loadable module) and the function calling
 the allocation. The number of bytes allocated and number of calls at each
-location are reported.
+location are reported. The first line indicates the version of the file, the
+second line is the header listing fields in the file.
 
 Example output.
 
 ::
 
-    > sort -rn /proc/allocinfo
+    > tail -n +3 /proc/allocinfo | sort -rn
    127664128    31168 mm/page_ext.c:270 func:alloc_page_ext
     56373248     4737 mm/slub.c:2259 func:alloc_slab_page
     14880768     3633 mm/readahead.c:247 func:page_cache_ra_unbounded
index 531dbe2f545635b97f1a9781dc73610aeb8cb724..11ed973ac359dfa57eb14a6f5b8196ad8ffe102b 100644 (file)
@@ -16,47 +16,60 @@ EXPORT_SYMBOL(_shared_alloc_tag);
 DEFINE_STATIC_KEY_MAYBE(CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT,
                        mem_alloc_profiling_key);
 
+struct allocinfo_private {
+       struct codetag_iterator iter;
+       bool print_header;
+};
+
 static void *allocinfo_start(struct seq_file *m, loff_t *pos)
 {
-       struct codetag_iterator *iter;
+       struct allocinfo_private *priv;
        struct codetag *ct;
        loff_t node = *pos;
 
-       iter = kzalloc(sizeof(*iter), GFP_KERNEL);
-       m->private = iter;
-       if (!iter)
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       m->private = priv;
+       if (!priv)
                return NULL;
 
+       priv->print_header = (node == 0);
        codetag_lock_module_list(alloc_tag_cttype, true);
-       *iter = codetag_get_ct_iter(alloc_tag_cttype);
-       while ((ct = codetag_next_ct(iter)) != NULL && node)
+       priv->iter = codetag_get_ct_iter(alloc_tag_cttype);
+       while ((ct = codetag_next_ct(&priv->iter)) != NULL && node)
                node--;
 
-       return ct ? iter : NULL;
+       return ct ? priv : NULL;
 }
 
 static void *allocinfo_next(struct seq_file *m, void *arg, loff_t *pos)
 {
-       struct codetag_iterator *iter = (struct codetag_iterator *)arg;
-       struct codetag *ct = codetag_next_ct(iter);
+       struct allocinfo_private *priv = (struct allocinfo_private *)arg;
+       struct codetag *ct = codetag_next_ct(&priv->iter);
 
        (*pos)++;
        if (!ct)
                return NULL;
 
-       return iter;
+       return priv;
 }
 
 static void allocinfo_stop(struct seq_file *m, void *arg)
 {
-       struct codetag_iterator *iter = (struct codetag_iterator *)m->private;
+       struct allocinfo_private *priv = (struct allocinfo_private *)m->private;
 
-       if (iter) {
+       if (priv) {
                codetag_lock_module_list(alloc_tag_cttype, false);
-               kfree(iter);
+               kfree(priv);
        }
 }
 
+static void print_allocinfo_header(struct seq_buf *buf)
+{
+       /* Output format version, so we can change it. */
+       seq_buf_printf(buf, "allocinfo - version: 1.0\n");
+       seq_buf_printf(buf, "#     <size>  <calls> <tag info>\n");
+}
+
 static void alloc_tag_to_text(struct seq_buf *out, struct codetag *ct)
 {
        struct alloc_tag *tag = ct_to_alloc_tag(ct);
@@ -71,13 +84,17 @@ static void alloc_tag_to_text(struct seq_buf *out, struct codetag *ct)
 
 static int allocinfo_show(struct seq_file *m, void *arg)
 {
-       struct codetag_iterator *iter = (struct codetag_iterator *)arg;
+       struct allocinfo_private *priv = (struct allocinfo_private *)arg;
        char *bufp;
        size_t n = seq_get_buf(m, &bufp);
        struct seq_buf buf;
 
        seq_buf_init(&buf, bufp, n);
-       alloc_tag_to_text(&buf, iter->ct);
+       if (priv->print_header) {
+               print_allocinfo_header(&buf);
+               priv->print_header = false;
+       }
+       alloc_tag_to_text(&buf, priv->iter.ct);
        seq_commit(m, seq_buf_used(&buf));
        return 0;
 }