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:
parent
8e0545c83d
commit
a38568a0b4
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user