MEMORY ALLOCATION PROFILING

Low overhead (suitable for production) accounting of all memory allocations,tracked by file and line number.

Usage:kconfig options:- CONFIG_MEM_ALLOC_PROFILING

  • CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT

  • CONFIG_MEM_ALLOC_PROFILING_DEBUGadds warnings for allocations that weren’t accounted because of amissing annotation

Boot parameter:

sysctl.vm.mem_profiling={0|1|never}[,compressed]

When set to “never”, memory allocation profiling overhead is minimized and itcannot be enabled at runtime (sysctl becomes read-only).When CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT=y, default value is “1”.When CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT=n, default value is “never”.“compressed” optional parameter will try to store page tag references in acompact format, avoiding page extensions. This results in improved performanceand memory consumption, however it might fail depending on system configuration.If compression fails, a warning is issued and memory allocation profiling getsdisabled.

sysctl:

/proc/sys/vm/mem_profiling

1: Enable memory profiling.

0: Disable memory profiling.

The default value depends on CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT.

When CONFIG_MEM_ALLOC_PROFILING_DEBUG=y, this control is read-only to avoidwarnings produced by allocations made while profiling is disabled and freedwhen it’s enabled.

Runtime info:

/proc/allocinfo

Example output:

root@moria-kvm:~# sort -g /proc/allocinfo|tail|numfmt --to=iec      2.8M    22648 fs/kernfs/dir.c:615 func:__kernfs_new_node      3.8M      953 mm/memory.c:4214 func:alloc_anon_folio      4.0M     1010 drivers/staging/ctagmod/ctagmod.c:20 [ctagmod] func:ctagmod_start      4.1M        4 net/netfilter/nf_conntrack_core.c:2567 func:nf_ct_alloc_hashtable      6.0M     1532 mm/filemap.c:1919 func:__filemap_get_folio      8.8M     2785 kernel/fork.c:307 func:alloc_thread_stack_node       13M      234 block/blk-mq.c:3421 func:blk_mq_alloc_rqs       14M     3520 mm/mm_init.c:2530 func:alloc_large_system_hash       15M     3656 mm/readahead.c:247 func:page_cache_ra_unbounded       55M     4887 mm/slub.c:2259 func:alloc_slab_page      122M    31168 mm/page_ext.c:270 func:alloc_page_ext

Theory of operation

Memory allocation profiling builds off of code tagging, which is a library fordeclaring static structs (that typically describe a file and line number insome way, hence code tagging) and then finding and operating on them at runtime,- i.e. iterating over them to print them in debugfs/procfs.

To add accounting for an allocation call, we replace it with a macroinvocation,alloc_hooks(), that- declares a code tag- stashes a pointer to it in task_struct- calls the real allocation function- and finally, restores the task_struct alloc tag pointer to its previous value.

This allows foralloc_hooks() calls to be nested, with the most recent onetaking effect. This is important for allocations internal to the mm/ code thatdo not properly belong to the outer allocation context and should be countedseparately: for example, slab object extension vectors, or when the slaballocates pages from the page allocator.

Thus, proper usage requires determining which function in an allocation callstack should be tagged. There are many helper functions that essentially wrape.g.kmalloc() and do a little more work, then are called in multiple places;we’ll generally want the accounting to happen in the callers of these helpers,not in the helpers themselves.

To fix up a given helper, for examplefoo(), do the following:- switch its allocation call to the_noprof() version, e.g.kmalloc_noprof()

  • rename it tofoo_noprof()

  • define a macro version offoo() like so:

    #define foo(...) alloc_hooks(foo_noprof(__VA_ARGS__))

It’s also possible to stash a pointer to an alloc tag in your own data structures.

Do this when you’re implementing a generic data structure that does allocations“on behalf of” some other code - for example, the rhashtable code. This way,instead of seeing a large line in /proc/allocinfo for rhashtable.c, we canbreak it out by rhashtable type.

To do so:- Hook your data structure’s init function, like any other allocation function.

  • Within your init function, use the convenience macroalloc_tag_record() torecord alloc tag in your data structure.

  • Then, use the following form for your allocations:alloc_hooks_tag(ht->your_saved_tag, kmalloc_noprof(...))