1

lib: add version into /proc/allocinfo output

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>
This commit is contained in:
Suren Baghdasaryan 2024-05-14 09:31:28 -07:00 committed by Andrew Morton
parent 8e0545c83d
commit a38568a0b4
2 changed files with 35 additions and 17 deletions

View 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 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 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 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. Example output.
:: ::
> sort -rn /proc/allocinfo > tail -n +3 /proc/allocinfo | sort -rn
127664128 31168 mm/page_ext.c:270 func:alloc_page_ext 127664128 31168 mm/page_ext.c:270 func:alloc_page_ext
56373248 4737 mm/slub.c:2259 func:alloc_slab_page 56373248 4737 mm/slub.c:2259 func:alloc_slab_page
14880768 3633 mm/readahead.c:247 func:page_cache_ra_unbounded 14880768 3633 mm/readahead.c:247 func:page_cache_ra_unbounded

View File

@ -16,47 +16,60 @@ EXPORT_SYMBOL(_shared_alloc_tag);
DEFINE_STATIC_KEY_MAYBE(CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT, DEFINE_STATIC_KEY_MAYBE(CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT,
mem_alloc_profiling_key); 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) static void *allocinfo_start(struct seq_file *m, loff_t *pos)
{ {
struct codetag_iterator *iter; struct allocinfo_private *priv;
struct codetag *ct; struct codetag *ct;
loff_t node = *pos; loff_t node = *pos;
iter = kzalloc(sizeof(*iter), GFP_KERNEL); priv = kzalloc(sizeof(*priv), GFP_KERNEL);
m->private = iter; m->private = priv;
if (!iter) if (!priv)
return NULL; return NULL;
priv->print_header = (node == 0);
codetag_lock_module_list(alloc_tag_cttype, true); codetag_lock_module_list(alloc_tag_cttype, true);
*iter = codetag_get_ct_iter(alloc_tag_cttype); priv->iter = codetag_get_ct_iter(alloc_tag_cttype);
while ((ct = codetag_next_ct(iter)) != NULL && node) while ((ct = codetag_next_ct(&priv->iter)) != NULL && node)
node--; node--;
return ct ? iter : NULL; return ct ? priv : NULL;
} }
static void *allocinfo_next(struct seq_file *m, void *arg, loff_t *pos) static void *allocinfo_next(struct seq_file *m, void *arg, loff_t *pos)
{ {
struct codetag_iterator *iter = (struct codetag_iterator *)arg; struct allocinfo_private *priv = (struct allocinfo_private *)arg;
struct codetag *ct = codetag_next_ct(iter); struct codetag *ct = codetag_next_ct(&priv->iter);
(*pos)++; (*pos)++;
if (!ct) if (!ct)
return NULL; return NULL;
return iter; return priv;
} }
static void allocinfo_stop(struct seq_file *m, void *arg) 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); 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) static void alloc_tag_to_text(struct seq_buf *out, struct codetag *ct)
{ {
struct alloc_tag *tag = ct_to_alloc_tag(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) 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; char *bufp;
size_t n = seq_get_buf(m, &bufp); size_t n = seq_get_buf(m, &bufp);
struct seq_buf buf; struct seq_buf buf;
seq_buf_init(&buf, bufp, n); 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)); seq_commit(m, seq_buf_used(&buf));
return 0; return 0;
} }