요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
.. SPDX-License-Identifier: GPL-2.0
===========================
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_DEBUG
adds warnings for allocations that weren't accounted because of a
missing annotation
Boot parameter:
sysctl.vm.mem_profiling={0|1|never}[,compressed]
When set to "never", memory allocation profiling overhead is minimized and it
cannot 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 a
compact format, avoiding page extensions. This results in improved performance
and memory consumption, however it might fail depending on system configuration.
If compression fails, a warning is issued and memory allocation profiling gets
disabled.
sysctl:
/proc/sys/vm/mem_profiling
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 for
declaring static structs (that typically describe a file and line number in
some 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 macro
invocation, 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 for alloc_hooks() calls to be nested, with the most recent one
taking effect. This is important for allocations internal to the mm/ code that
do not properly belong to the outer allocation context and should be counted
separately: for example, slab object extension vectors, or when the slab
allocates pages from the page allocator.
Thus, proper usage requires determining which function in an allocation call
stack should be tagged. There are many helper functions that essentially wrap
e.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 example foo(), do the following:
- switch its allocation call to the _noprof() version, e.g. kmalloc_noprof()
- rename it to foo_noprof()
- define a macro version of foo() 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 can
break 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 macro alloc_tag_record() to
record alloc tag in your data structure.
- Then, use the following form for your allocations:
alloc_hooks_tag(ht->your_saved_tag, kmalloc_noprof(...))
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
목적
1-9Memory allocation profiling은 production 환경에도 적합한 낮은 overhead로 모든 memory allocation을 file과 line number별로 accounting합니다.
.. SPDX-License-Identifier: GPL-2.0
===========================
MEMORY ALLOCATION PROFILING
===========================
Low overhead (suitable for production) accounting of all memory allocations,
tracked by file and line number.
Kconfig·boot parameter·runtime interface
10-38관련 Kconfig option은 `CONFIG_MEM_ALLOC_PROFILING`, `CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT`, `CONFIG_MEM_ALLOC_PROFILING_DEBUG`입니다. DEBUG option은 annotation 누락 때문에 accounting되지 않은 allocation을 경고합니다.
Boot parameter는 `sysctl.vm.mem_profiling={0|1|never}[,compressed]`입니다. `never`는 profiling overhead를 최소화하며 runtime enable을 막아 sysctl을 read-only로 만듭니다.
`CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT=y`이면 기본값은 `1`, `n`이면 `never`입니다.
Optional `compressed` parameter는 page-tag reference를 compact format에 저장해 page extension을 피하려 합니다. Performance와 memory consumption이 개선되지만 system configuration에 따라 실패할 수 있습니다. Compression에 실패하면 warning을 내고 allocation profiling을 disable합니다.
Runtime switch는 `/proc/sys/vm/mem_profiling`, profiling 결과는 `/proc/allocinfo`에서 제공합니다.
Usage:
kconfig options:
- CONFIG_MEM_ALLOC_PROFILING
- CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT
- CONFIG_MEM_ALLOC_PROFILING_DEBUG
adds warnings for allocations that weren't accounted because of a
missing annotation
Boot parameter:
sysctl.vm.mem_profiling={0|1|never}[,compressed]
When set to "never", memory allocation profiling overhead is minimized and it
cannot 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 a
compact format, avoiding page extensions. This results in improved performance
and memory consumption, however it might fail depending on system configuration.
If compression fails, a warning is issued and memory allocation profiling gets
disabled.
sysctl:
/proc/sys/vm/mem_profiling
Runtime info:
/proc/allocinfo
`/proc/allocinfo` 예제
39-53예제는 `/proc/allocinfo`를 allocation byte 기준으로 정렬해 가장 큰 항목을 IEC 단위로 표시합니다. 각 행에는 누적 byte, allocation 수, source file과 line, function, 필요한 경우 module이 나옵니다.
2.8M 22648 fs/kernfs/dir.c:615 func:__kernfs_new_node
3.8M 953 mm/memory.c:4214 func:alloc_anon_folio
55M 4887 mm/slub.c:2259 func:alloc_slab_page
122M 31168 mm/page_ext.c:270 func:alloc_page_ext
원문 전체 출력에는 `ctagmod`, netfilter hash table, filemap folio, thread stack, block request, system hash, readahead 등도 포함됩니다.
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
Code tagging과 nested allocation hook
54-79Memory allocation profiling은 code tagging을 기반으로 합니다. Code tagging은 보통 file과 line number를 기술하는 static struct를 선언하고 runtime에 찾아 순회하거나 debugfs/procfs에 출력하는 library입니다.
Allocation call을 accounting하려면 이를 `alloc_hooks()` macro 호출로 바꿉니다. 이 macro는 code tag를 선언하고 그 pointer를 `task_struct`에 저장한 뒤 실제 allocation function을 호출하고, 마지막으로 `task_struct`의 alloc-tag pointer를 이전 값으로 복원합니다.
`alloc_hooks()` 호출은 중첩할 수 있으며 가장 최근 hook이 적용됩니다. Slab object extension vector나 slab이 page allocator에서 page를 할당하는 경우처럼 외부 allocation context에 속하지 않는 MM 내부 allocation을 별도로 집계하는 데 중요합니다.
따라서 allocation call stack에서 어느 function에 tag를 붙일지 정해야 합니다. `kmalloc()`을 감싸 약간의 작업을 더 하고 여러 곳에서 호출되는 helper라면 대개 helper 자체가 아니라 caller에서 accounting하는 것이 바람직합니다.
Theory of operation
===================
Memory allocation profiling builds off of code tagging, which is a library for
declaring static structs (that typically describe a file and line number in
some 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 macro
invocation, 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 for alloc_hooks() calls to be nested, with the most recent one
taking effect. This is important for allocations internal to the mm/ code that
do not properly belong to the outer allocation context and should be counted
separately: for example, slab object extension vectors, or when the slab
allocates pages from the page allocator.
Thus, proper usage requires determining which function in an allocation call
stack should be tagged. There are many helper functions that essentially wrap
e.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.
Helper를 `_noprof` wrapper로 전환
80-89예를 들어 `foo()` helper를 수정하려면 내부 allocation을 `kmalloc_noprof()` 같은 `_noprof()` version으로 바꾸고 function 이름을 `foo_noprof()`로 변경합니다.
그 뒤 원래 이름 `foo()`를 `alloc_hooks(foo_noprof(__VA_ARGS__))`를 호출하는 macro로 정의합니다.
#define foo(...) alloc_hooks(foo_noprof(__VA_ARGS__))
To fix up a given helper, for example foo(), do the following:
- switch its allocation call to the _noprof() version, e.g. kmalloc_noprof()
- rename it to foo_noprof()
- define a macro version of foo() like so:
#define foo(...) alloc_hooks(foo_noprof(__VA_ARGS__))
Generic data structure의 saved alloc tag
90-104자체 data structure에 alloc-tag pointer를 저장할 수도 있습니다. `rhashtable`처럼 다른 code를 대신해 allocation하는 generic data structure에서 사용합니다. 그러면 `/proc/allocinfo`에 `rhashtable.c`의 큰 단일 항목으로 나타나는 대신 rhashtable type별로 나눌 수 있습니다.
먼저 일반 allocation function처럼 data-structure init function에 hook을 겁니다. Init function 안에서 `alloc_tag_record()` convenience macro로 alloc tag를 data structure에 기록합니다.
실제 allocation은 저장한 tag를 지정하는 `alloc_hooks_tag(ht->your_saved_tag, kmalloc_noprof(...))` 형태로 수행합니다.
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 can
break 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 macro alloc_tag_record() to
record alloc tag in your data structure.
- Then, use the following form for your allocations:
alloc_hooks_tag(ht->your_saved_tag, kmalloc_noprof(...))
요약·해설
allocation-profiling.rst:1-104`alloc_hooks()`는 current task에 가장 최근 allocation context를 잠시 기록해 nested allocation을 올바른 source callsite에 집계합니다. Generic container는 tag를 자체 저장해 caller별 비용을 분리할 수 있습니다.
Hook은 tag를 push하고 실제 `_noprof` allocation 뒤 이전 tag를 복원합니다.