← Documents Documentation/mm/allocation-profiling.rst GitHub 원문 ↗

Linux 6.18.37 · Memory management

Memory Allocation Profiling

File·line별 low-overhead allocation accounting, alloc_hooks 중첩과 generic data-structure tag 저장법을 설명합니다.

Source pathDocumentation/mm/allocation-profiling.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약·해설

allocation-profiling.rst:1-104

`alloc_hooks()`는 current task에 가장 최근 allocation context를 잠시 기록해 nested allocation을 올바른 source callsite에 집계합니다. Generic container는 tag를 자체 저장해 caller별 비용을 분리할 수 있습니다.

Allocation hook scope
alloc_hooks()Code tag 선언task_struct에 저장_noprof allocation이전 tag 복원

Hook은 tag를 push하고 실제 `_noprof` allocation 뒤 이전 tag를 복원합니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 .. SPDX-License-Identifier: GPL-2.0
2
3 ===========================
4 MEMORY ALLOCATION PROFILING
5 ===========================
6
7 Low overhead (suitable for production) accounting of all memory allocations,
8 tracked by file and line number.
9
10 Usage:
11 kconfig options:
12 - CONFIG_MEM_ALLOC_PROFILING
13
14 - CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT
15
16 - CONFIG_MEM_ALLOC_PROFILING_DEBUG
17 adds warnings for allocations that weren't accounted because of a
18 missing annotation
19
20 Boot parameter:
21 sysctl.vm.mem_profiling={0|1|never}[,compressed]
22
23 When set to "never", memory allocation profiling overhead is minimized and it
24 cannot be enabled at runtime (sysctl becomes read-only).
25 When CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT=y, default value is "1".
26 When CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT=n, default value is "never".
27 "compressed" optional parameter will try to store page tag references in a
28 compact format, avoiding page extensions. This results in improved performance
29 and memory consumption, however it might fail depending on system configuration.
30 If compression fails, a warning is issued and memory allocation profiling gets
31 disabled.
32
33 sysctl:
34 /proc/sys/vm/mem_profiling
35
36 Runtime info:
37 /proc/allocinfo
38
39 Example output::
40
41 root@moria-kvm:~# sort -g /proc/allocinfo|tail|numfmt --to=iec
42 2.8M 22648 fs/kernfs/dir.c:615 func:__kernfs_new_node
43 3.8M 953 mm/memory.c:4214 func:alloc_anon_folio
44 4.0M 1010 drivers/staging/ctagmod/ctagmod.c:20 [ctagmod] func:ctagmod_start
45 4.1M 4 net/netfilter/nf_conntrack_core.c:2567 func:nf_ct_alloc_hashtable
46 6.0M 1532 mm/filemap.c:1919 func:__filemap_get_folio
47 8.8M 2785 kernel/fork.c:307 func:alloc_thread_stack_node
48 13M 234 block/blk-mq.c:3421 func:blk_mq_alloc_rqs
49 14M 3520 mm/mm_init.c:2530 func:alloc_large_system_hash
50 15M 3656 mm/readahead.c:247 func:page_cache_ra_unbounded
51 55M 4887 mm/slub.c:2259 func:alloc_slab_page
52 122M 31168 mm/page_ext.c:270 func:alloc_page_ext
53
54 Theory of operation
55 ===================
56
57 Memory allocation profiling builds off of code tagging, which is a library for
58 declaring static structs (that typically describe a file and line number in
59 some way, hence code tagging) and then finding and operating on them at runtime,
60 - i.e. iterating over them to print them in debugfs/procfs.
61
62 To add accounting for an allocation call, we replace it with a macro
63 invocation, alloc_hooks(), that
64 - declares a code tag
65 - stashes a pointer to it in task_struct
66 - calls the real allocation function
67 - and finally, restores the task_struct alloc tag pointer to its previous value.
68
69 This allows for alloc_hooks() calls to be nested, with the most recent one
70 taking effect. This is important for allocations internal to the mm/ code that
71 do not properly belong to the outer allocation context and should be counted
72 separately: for example, slab object extension vectors, or when the slab
73 allocates pages from the page allocator.
74
75 Thus, proper usage requires determining which function in an allocation call
76 stack should be tagged. There are many helper functions that essentially wrap
77 e.g. kmalloc() and do a little more work, then are called in multiple places;
78 we'll generally want the accounting to happen in the callers of these helpers,
79 not in the helpers themselves.
80
81 To fix up a given helper, for example foo(), do the following:
82 - switch its allocation call to the _noprof() version, e.g. kmalloc_noprof()
83
84 - rename it to foo_noprof()
85
86 - define a macro version of foo() like so:
87
88 #define foo(...) alloc_hooks(foo_noprof(__VA_ARGS__))
89
90 It's also possible to stash a pointer to an alloc tag in your own data structures.
91
92 Do this when you're implementing a generic data structure that does allocations
93 "on behalf of" some other code - for example, the rhashtable code. This way,
94 instead of seeing a large line in /proc/allocinfo for rhashtable.c, we can
95 break it out by rhashtable type.
96
97 To do so:
98 - Hook your data structure's init function, like any other allocation function.
99
100 - Within your init function, use the convenience macro alloc_tag_record() to
101 record alloc tag in your data structure.
102
103 - Then, use the following form for your allocations:
104 alloc_hooks_tag(ht->your_saved_tag, kmalloc_noprof(...))
105

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

목적

1-9

Memory 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-79

Memory 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(...))