← Documents Documentation/admin-guide/mm/transhuge.rst GitHub 원문 ↗

Linux 6.18.37 · Administration / Memory Management

Transparent Hugepage Support

THP·mTHP의 성능 효과, sysfs·madvise·prctl·boot 제어, khugepaged와 tmpfs/shmem 및 통계를 설명합니다.

Source pathDocumentation/admin-guide/mm/transhuge.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

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

1. 요약·해설

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

운영 핵심

transhuge.rst:1-740

THP는 page size를 자동 승격·강등해 TLB miss와 page fault를 줄이지만 allocation latency와 memory 낭비가 생길 수 있습니다. Size별 enabled·defrag, process prctl, madvise, khugepaged와 shmem policy를 workload에 맞게 조합하고 vmstat·size별 stats로 결과를 검증해야 합니다.

관점핵심
기본 정책PMD size는 inherit, 다른 mTHP size는 never
선택적 사용`madvise(MADV_HUGEPAGE)`와 process `prctl()` 조합
강제 collapse`MADV_COLLAPSE`는 sysfs의 never를 무시할 수 있음
background`khugepaged`가 basic page sequence를 PMD THP로 collapse
관찰`/proc/meminfo`, `/proc/PID/smaps`, `/proc/vmstat`, size별 stats

2. 영어 원문 전체

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

원문 전체 펼치기
1 ============================
2 Transparent Hugepage Support
3 ============================
4
5 Objective
6 =========
7
8 Performance critical computing applications dealing with large memory
9 working sets are already running on top of libhugetlbfs and in turn
10 hugetlbfs. Transparent HugePage Support (THP) is an alternative mean of
11 using huge pages for the backing of virtual memory with huge pages
12 that supports the automatic promotion and demotion of page sizes and
13 without the shortcomings of hugetlbfs.
14
15 Currently THP only works for anonymous memory mappings and tmpfs/shmem.
16 But in the future it can expand to other filesystems.
17
18 .. note::
19 in the examples below we presume that the basic page size is 4K and
20 the huge page size is 2M, although the actual numbers may vary
21 depending on the CPU architecture.
22
23 The reason applications are running faster is because of two
24 factors. The first factor is almost completely irrelevant and it's not
25 of significant interest because it'll also have the downside of
26 requiring larger clear-page copy-page in page faults which is a
27 potentially negative effect. The first factor consists in taking a
28 single page fault for each 2M virtual region touched by userland (so
29 reducing the enter/exit kernel frequency by a 512 times factor). This
30 only matters the first time the memory is accessed for the lifetime of
31 a memory mapping. The second long lasting and much more important
32 factor will affect all subsequent accesses to the memory for the whole
33 runtime of the application. The second factor consist of two
34 components:
35
36 1) the TLB miss will run faster (especially with virtualization using
37 nested pagetables but almost always also on bare metal without
38 virtualization)
39
40 2) a single TLB entry will be mapping a much larger amount of virtual
41 memory in turn reducing the number of TLB misses. With
42 virtualization and nested pagetables the TLB can be mapped of
43 larger size only if both KVM and the Linux guest are using
44 hugepages but a significant speedup already happens if only one of
45 the two is using hugepages just because of the fact the TLB miss is
46 going to run faster.
47
48 Modern kernels support "multi-size THP" (mTHP), which introduces the
49 ability to allocate memory in blocks that are bigger than a base page
50 but smaller than traditional PMD-size (as described above), in
51 increments of a power-of-2 number of pages. mTHP can back anonymous
52 memory (for example 16K, 32K, 64K, etc). These THPs continue to be
53 PTE-mapped, but in many cases can still provide similar benefits to
54 those outlined above: Page faults are significantly reduced (by a
55 factor of e.g. 4, 8, 16, etc), but latency spikes are much less
56 prominent because the size of each page isn't as huge as the PMD-sized
57 variant and there is less memory to clear in each page fault. Some
58 architectures also employ TLB compression mechanisms to squeeze more
59 entries in when a set of PTEs are virtually and physically contiguous
60 and approporiately aligned. In this case, TLB misses will occur less
61 often.
62
63 THP can be enabled system wide or restricted to certain tasks or even
64 memory ranges inside task's address space. Unless THP is completely
65 disabled, there is ``khugepaged`` daemon that scans memory and
66 collapses sequences of basic pages into PMD-sized huge pages.
67
68 The THP behaviour is controlled via :ref:`sysfs <thp_sysfs>`
69 interface and using madvise(2) and prctl(2) system calls.
70
71 Transparent Hugepage Support maximizes the usefulness of free memory
72 if compared to the reservation approach of hugetlbfs by allowing all
73 unused memory to be used as cache or other movable (or even unmovable
74 entities). It doesn't require reservation to prevent hugepage
75 allocation failures to be noticeable from userland. It allows paging
76 and all other advanced VM features to be available on the
77 hugepages. It requires no modifications for applications to take
78 advantage of it.
79
80 Applications however can be further optimized to take advantage of
81 this feature, like for example they've been optimized before to avoid
82 a flood of mmap system calls for every malloc(4k). Optimizing userland
83 is by far not mandatory and khugepaged already can take care of long
84 lived page allocations even for hugepage unaware applications that
85 deals with large amounts of memory.
86
87 In certain cases when hugepages are enabled system wide, application
88 may end up allocating more memory resources. An application may mmap a
89 large region but only touch 1 byte of it, in that case a 2M page might
90 be allocated instead of a 4k page for no good. This is why it's
91 possible to disable hugepages system-wide and to only have them inside
92 MADV_HUGEPAGE madvise regions.
93
94 Embedded systems should enable hugepages only inside madvise regions
95 to eliminate any risk of wasting any precious byte of memory and to
96 only run faster.
97
98 Applications that gets a lot of benefit from hugepages and that don't
99 risk to lose memory by using hugepages, should use
100 madvise(MADV_HUGEPAGE) on their critical mmapped regions.
101
102 .. _thp_sysfs:
103
104 sysfs
105 =====
106
107 Global THP controls
108 -------------------
109
110 Transparent Hugepage Support for anonymous memory can be disabled
111 (mostly for debugging purposes) or only enabled inside MADV_HUGEPAGE
112 regions (to avoid the risk of consuming more memory resources) or enabled
113 system wide. This can be achieved per-supported-THP-size with one of::
114
115 echo always >/sys/kernel/mm/transparent_hugepage/hugepages-<size>kB/enabled
116 echo madvise >/sys/kernel/mm/transparent_hugepage/hugepages-<size>kB/enabled
117 echo never >/sys/kernel/mm/transparent_hugepage/hugepages-<size>kB/enabled
118
119 where <size> is the hugepage size being addressed, the available sizes
120 for which vary by system.
121
122 .. note:: Setting "never" in all sysfs THP controls does **not** disable
123 Transparent Huge Pages globally. This is because ``madvise(...,
124 MADV_COLLAPSE)`` ignores these settings and collapses ranges to
125 PMD-sized huge pages unconditionally.
126
127 For example::
128
129 echo always >/sys/kernel/mm/transparent_hugepage/hugepages-2048kB/enabled
130
131 Alternatively it is possible to specify that a given hugepage size
132 will inherit the top-level "enabled" value::
133
134 echo inherit >/sys/kernel/mm/transparent_hugepage/hugepages-<size>kB/enabled
135
136 For example::
137
138 echo inherit >/sys/kernel/mm/transparent_hugepage/hugepages-2048kB/enabled
139
140 The top-level setting (for use with "inherit") can be set by issuing
141 one of the following commands::
142
143 echo always >/sys/kernel/mm/transparent_hugepage/enabled
144 echo madvise >/sys/kernel/mm/transparent_hugepage/enabled
145 echo never >/sys/kernel/mm/transparent_hugepage/enabled
146
147 By default, PMD-sized hugepages have enabled="inherit" and all other
148 hugepage sizes have enabled="never". If enabling multiple hugepage
149 sizes, the kernel will select the most appropriate enabled size for a
150 given allocation.
151
152 It's also possible to limit defrag efforts in the VM to generate
153 anonymous hugepages in case they're not immediately free to madvise
154 regions or to never try to defrag memory and simply fallback to regular
155 pages unless hugepages are immediately available. Clearly if we spend CPU
156 time to defrag memory, we would expect to gain even more by the fact we
157 use hugepages later instead of regular pages. This isn't always
158 guaranteed, but it may be more likely in case the allocation is for a
159 MADV_HUGEPAGE region.
160
161 ::
162
163 echo always >/sys/kernel/mm/transparent_hugepage/defrag
164 echo defer >/sys/kernel/mm/transparent_hugepage/defrag
165 echo defer+madvise >/sys/kernel/mm/transparent_hugepage/defrag
166 echo madvise >/sys/kernel/mm/transparent_hugepage/defrag
167 echo never >/sys/kernel/mm/transparent_hugepage/defrag
168
169 always
170 means that an application requesting THP will stall on
171 allocation failure and directly reclaim pages and compact
172 memory in an effort to allocate a THP immediately. This may be
173 desirable for virtual machines that benefit heavily from THP
174 use and are willing to delay the VM start to utilise them.
175
176 defer
177 means that an application will wake kswapd in the background
178 to reclaim pages and wake kcompactd to compact memory so that
179 THP is available in the near future. It's the responsibility
180 of khugepaged to then install the THP pages later.
181
182 defer+madvise
183 will enter direct reclaim and compaction like ``always``, but
184 only for regions that have used madvise(MADV_HUGEPAGE); all
185 other regions will wake kswapd in the background to reclaim
186 pages and wake kcompactd to compact memory so that THP is
187 available in the near future.
188
189 madvise
190 will enter direct reclaim like ``always`` but only for regions
191 that are have used madvise(MADV_HUGEPAGE). This is the default
192 behaviour.
193
194 never
195 should be self-explanatory. Note that ``madvise(...,
196 MADV_COLLAPSE)`` can still cause transparent huge pages to be
197 obtained even if this mode is specified everywhere.
198
199 By default kernel tries to use huge, PMD-mappable zero page on read
200 page fault to anonymous mapping. It's possible to disable huge zero
201 page by writing 0 or enable it back by writing 1::
202
203 echo 0 >/sys/kernel/mm/transparent_hugepage/use_zero_page
204 echo 1 >/sys/kernel/mm/transparent_hugepage/use_zero_page
205
206 Some userspace (such as a test program, or an optimized memory
207 allocation library) may want to know the size (in bytes) of a
208 PMD-mappable transparent hugepage::
209
210 cat /sys/kernel/mm/transparent_hugepage/hpage_pmd_size
211
212 All THPs at fault and collapse time will be added to _deferred_list,
213 and will therefore be split under memory presure if they are considered
214 "underused". A THP is underused if the number of zero-filled pages in
215 the THP is above max_ptes_none (see below). It is possible to disable
216 this behaviour by writing 0 to shrink_underused, and enable it by writing
217 1 to it::
218
219 echo 0 > /sys/kernel/mm/transparent_hugepage/shrink_underused
220 echo 1 > /sys/kernel/mm/transparent_hugepage/shrink_underused
221
222 khugepaged will be automatically started when PMD-sized THP is enabled
223 (either of the per-size anon control or the top-level control are set
224 to "always" or "madvise"), and it'll be automatically shutdown when
225 PMD-sized THP is disabled (when both the per-size anon control and the
226 top-level control are "never")
227
228 process THP controls
229 --------------------
230
231 A process can control its own THP behaviour using the ``PR_SET_THP_DISABLE``
232 and ``PR_GET_THP_DISABLE`` pair of prctl(2) calls. The THP behaviour set using
233 ``PR_SET_THP_DISABLE`` is inherited across fork(2) and execve(2). These calls
234 support the following arguments::
235
236 prctl(PR_SET_THP_DISABLE, 1, 0, 0, 0):
237 This will disable THPs completely for the process, irrespective
238 of global THP controls or madvise(..., MADV_COLLAPSE) being used.
239
240 prctl(PR_SET_THP_DISABLE, 1, PR_THP_DISABLE_EXCEPT_ADVISED, 0, 0):
241 This will disable THPs for the process except when the usage of THPs is
242 advised. Consequently, THPs will only be used when:
243 - Global THP controls are set to "always" or "madvise" and
244 madvise(..., MADV_HUGEPAGE) or madvise(..., MADV_COLLAPSE) is used.
245 - Global THP controls are set to "never" and madvise(..., MADV_COLLAPSE)
246 is used. This is the same behavior as if THPs would not be disabled on
247 a process level.
248 Note that MADV_COLLAPSE is currently always rejected if
249 madvise(..., MADV_NOHUGEPAGE) is set on an area.
250
251 prctl(PR_SET_THP_DISABLE, 0, 0, 0, 0):
252 This will re-enable THPs for the process, as if they were never disabled.
253 Whether THPs will actually be used depends on global THP controls and
254 madvise() calls.
255
256 prctl(PR_GET_THP_DISABLE, 0, 0, 0, 0):
257 This returns a value whose bits indicate how THP-disable is configured:
258 Bits
259 1 0 Value Description
260 |0|0| 0 No THP-disable behaviour specified.
261 |0|1| 1 THP is entirely disabled for this process.
262 |1|1| 3 THP-except-advised mode is set for this process.
263
264 Khugepaged controls
265 -------------------
266
267 .. note::
268 khugepaged currently only searches for opportunities to collapse to
269 PMD-sized THP and no attempt is made to collapse to other THP
270 sizes.
271
272 khugepaged runs usually at low frequency so while one may not want to
273 invoke defrag algorithms synchronously during the page faults, it
274 should be worth invoking defrag at least in khugepaged. However it's
275 also possible to disable defrag in khugepaged by writing 0 or enable
276 defrag in khugepaged by writing 1::
277
278 echo 0 >/sys/kernel/mm/transparent_hugepage/khugepaged/defrag
279 echo 1 >/sys/kernel/mm/transparent_hugepage/khugepaged/defrag
280
281 You can also control how many pages khugepaged should scan at each
282 pass::
283
284 /sys/kernel/mm/transparent_hugepage/khugepaged/pages_to_scan
285
286 and how many milliseconds to wait in khugepaged between each pass (you
287 can set this to 0 to run khugepaged at 100% utilization of one core)::
288
289 /sys/kernel/mm/transparent_hugepage/khugepaged/scan_sleep_millisecs
290
291 and how many milliseconds to wait in khugepaged if there's an hugepage
292 allocation failure to throttle the next allocation attempt::
293
294 /sys/kernel/mm/transparent_hugepage/khugepaged/alloc_sleep_millisecs
295
296 The khugepaged progress can be seen in the number of pages collapsed (note
297 that this counter may not be an exact count of the number of pages
298 collapsed, since "collapsed" could mean multiple things: (1) A PTE mapping
299 being replaced by a PMD mapping, or (2) All 4K physical pages replaced by
300 one 2M hugepage. Each may happen independently, or together, depending on
301 the type of memory and the failures that occur. As such, this value should
302 be interpreted roughly as a sign of progress, and counters in /proc/vmstat
303 consulted for more accurate accounting)::
304
305 /sys/kernel/mm/transparent_hugepage/khugepaged/pages_collapsed
306
307 for each pass::
308
309 /sys/kernel/mm/transparent_hugepage/khugepaged/full_scans
310
311 ``max_ptes_none`` specifies how many extra small pages (that are
312 not already mapped) can be allocated when collapsing a group
313 of small pages into one large page::
314
315 /sys/kernel/mm/transparent_hugepage/khugepaged/max_ptes_none
316
317 A higher value leads to use additional memory for programs.
318 A lower value leads to gain less thp performance. Value of
319 max_ptes_none can waste cpu time very little, you can
320 ignore it.
321
322 ``max_ptes_swap`` specifies how many pages can be brought in from
323 swap when collapsing a group of pages into a transparent huge page::
324
325 /sys/kernel/mm/transparent_hugepage/khugepaged/max_ptes_swap
326
327 A higher value can cause excessive swap IO and waste
328 memory. A lower value can prevent THPs from being
329 collapsed, resulting fewer pages being collapsed into
330 THPs, and lower memory access performance.
331
332 ``max_ptes_shared`` specifies how many pages can be shared across multiple
333 processes. khugepaged might treat pages of THPs as shared if any page of
334 that THP is shared. Exceeding the number would block the collapse::
335
336 /sys/kernel/mm/transparent_hugepage/khugepaged/max_ptes_shared
337
338 A higher value may increase memory footprint for some workloads.
339
340 Boot parameters
341 ===============
342
343 You can change the sysfs boot time default for the top-level "enabled"
344 control by passing the parameter ``transparent_hugepage=always`` or
345 ``transparent_hugepage=madvise`` or ``transparent_hugepage=never`` to the
346 kernel command line.
347
348 Alternatively, each supported anonymous THP size can be controlled by
349 passing ``thp_anon=<size>[KMG],<size>[KMG]:<state>;<size>[KMG]-<size>[KMG]:<state>``,
350 where ``<size>`` is the THP size (must be a power of 2 of PAGE_SIZE and
351 supported anonymous THP) and ``<state>`` is one of ``always``, ``madvise``,
352 ``never`` or ``inherit``.
353
354 For example, the following will set 16K, 32K, 64K THP to ``always``,
355 set 128K, 512K to ``inherit``, set 256K to ``madvise`` and 1M, 2M
356 to ``never``::
357
358 thp_anon=16K-64K:always;128K,512K:inherit;256K:madvise;1M-2M:never
359
360 ``thp_anon=`` may be specified multiple times to configure all THP sizes as
361 required. If ``thp_anon=`` is specified at least once, any anon THP sizes
362 not explicitly configured on the command line are implicitly set to
363 ``never``.
364
365 ``transparent_hugepage`` setting only affects the global toggle. If
366 ``thp_anon`` is not specified, PMD_ORDER THP will default to ``inherit``.
367 However, if a valid ``thp_anon`` setting is provided by the user, the
368 PMD_ORDER THP policy will be overridden. If the policy for PMD_ORDER
369 is not defined within a valid ``thp_anon``, its policy will default to
370 ``never``.
371
372 Similarly to ``transparent_hugepage``, you can control the hugepage
373 allocation policy for the internal shmem mount by using the kernel parameter
374 ``transparent_hugepage_shmem=<policy>``, where ``<policy>`` is one of the
375 seven valid policies for shmem (``always``, ``within_size``, ``advise``,
376 ``never``, ``deny``, and ``force``).
377
378 Similarly to ``transparent_hugepage_shmem``, you can control the default
379 hugepage allocation policy for the tmpfs mount by using the kernel parameter
380 ``transparent_hugepage_tmpfs=<policy>``, where ``<policy>`` is one of the
381 four valid policies for tmpfs (``always``, ``within_size``, ``advise``,
382 ``never``). The tmpfs mount default policy is ``never``.
383
384 In the same manner as ``thp_anon`` controls each supported anonymous THP
385 size, ``thp_shmem`` controls each supported shmem THP size. ``thp_shmem``
386 has the same format as ``thp_anon``, but also supports the policy
387 ``within_size``.
388
389 ``thp_shmem=`` may be specified multiple times to configure all THP sizes
390 as required. If ``thp_shmem=`` is specified at least once, any shmem THP
391 sizes not explicitly configured on the command line are implicitly set to
392 ``never``.
393
394 ``transparent_hugepage_shmem`` setting only affects the global toggle. If
395 ``thp_shmem`` is not specified, PMD_ORDER hugepage will default to
396 ``inherit``. However, if a valid ``thp_shmem`` setting is provided by the
397 user, the PMD_ORDER hugepage policy will be overridden. If the policy for
398 PMD_ORDER is not defined within a valid ``thp_shmem``, its policy will
399 default to ``never``.
400
401 Hugepages in tmpfs/shmem
402 ========================
403
404 Traditionally, tmpfs only supported a single huge page size ("PMD"). Today,
405 it also supports smaller sizes just like anonymous memory, often referred
406 to as "multi-size THP" (mTHP). Huge pages of any size are commonly
407 represented in the kernel as "large folios".
408
409 While there is fine control over the huge page sizes to use for the internal
410 shmem mount (see below), ordinary tmpfs mounts will make use of all available
411 huge page sizes without any control over the exact sizes, behaving more like
412 other file systems.
413
414 tmpfs mounts
415 ------------
416
417 The THP allocation policy for tmpfs mounts can be adjusted using the mount
418 option: ``huge=``. It can have following values:
419
420 always
421 Attempt to allocate huge pages every time we need a new page;
422 Always try PMD-sized huge pages first, and fall back to smaller-sized
423 huge pages if the PMD-sized huge page allocation fails;
424
425 never
426 Do not allocate huge pages. Note that ``madvise(..., MADV_COLLAPSE)``
427 can still cause transparent huge pages to be obtained even if this mode
428 is specified everywhere;
429
430 within_size
431 Only allocate huge page if it will be fully within i_size;
432 Always try PMD-sized huge pages first, and fall back to smaller-sized
433 huge pages if the PMD-sized huge page allocation fails;
434 Also respect madvise() hints;
435
436 advise
437 Only allocate huge pages if requested with madvise();
438
439 Remember, that the kernel may use huge pages of all available sizes, and
440 that no fine control as for the internal tmpfs mount is available.
441
442 The default policy in the past was ``never``, but it can now be adjusted
443 using the kernel parameter ``transparent_hugepage_tmpfs=<policy>``.
444
445 ``mount -o remount,huge= /mountpoint`` works fine after mount: remounting
446 ``huge=never`` will not attempt to break up huge pages at all, just stop more
447 from being allocated.
448
449 In addition to policies listed above, the sysfs knob
450 /sys/kernel/mm/transparent_hugepage/shmem_enabled will affect the
451 allocation policy of tmpfs mounts, when set to the following values:
452
453 deny
454 For use in emergencies, to force the huge option off from
455 all mounts;
456 force
457 Force the huge option on for all - very useful for testing;
458
459 shmem / internal tmpfs
460 ----------------------
461 The mount internal tmpfs mount is used for SysV SHM, memfds, shared anonymous
462 mmaps (of /dev/zero or MAP_ANONYMOUS), GPU drivers' DRM objects, Ashmem.
463
464 To control the THP allocation policy for this internal tmpfs mount, the
465 sysfs knob /sys/kernel/mm/transparent_hugepage/shmem_enabled and the knobs
466 per THP size in
467 '/sys/kernel/mm/transparent_hugepage/hugepages-<size>kB/shmem_enabled'
468 can be used.
469
470 The global knob has the same semantics as the ``huge=`` mount options
471 for tmpfs mounts, except that the different huge page sizes can be controlled
472 individually, and will only use the setting of the global knob when the
473 per-size knob is set to 'inherit'.
474
475 The options 'force' and 'deny' are dropped for the individual sizes, which
476 are rather testing artifacts from the old ages.
477
478 always
479 Attempt to allocate <size> huge pages every time we need a new page;
480
481 inherit
482 Inherit the top-level "shmem_enabled" value. By default, PMD-sized hugepages
483 have enabled="inherit" and all other hugepage sizes have enabled="never";
484
485 never
486 Do not allocate <size> huge pages. Note that ``madvise(...,
487 MADV_COLLAPSE)`` can still cause transparent huge pages to be obtained
488 even if this mode is specified everywhere;
489
490 within_size
491 Only allocate <size> huge page if it will be fully within i_size.
492 Also respect madvise() hints;
493
494 advise
495 Only allocate <size> huge pages if requested with madvise();
496
497 Need of application restart
498 ===========================
499
500 The transparent_hugepage/enabled and
501 transparent_hugepage/hugepages-<size>kB/enabled values and tmpfs mount
502 option only affect future behavior. So to make them effective you need
503 to restart any application that could have been using hugepages. This
504 also applies to the regions registered in khugepaged.
505
506 Monitoring usage
507 ================
508
509 The number of PMD-sized anonymous transparent huge pages currently used by the
510 system is available by reading the AnonHugePages field in ``/proc/meminfo``.
511 To identify what applications are using PMD-sized anonymous transparent huge
512 pages, it is necessary to read ``/proc/PID/smaps`` and count the AnonHugePages
513 fields for each mapping. (Note that AnonHugePages only applies to traditional
514 PMD-sized THP for historical reasons and should have been called
515 AnonHugePmdMapped).
516
517 The number of file transparent huge pages mapped to userspace is available
518 by reading ShmemPmdMapped and ShmemHugePages fields in ``/proc/meminfo``.
519 To identify what applications are mapping file transparent huge pages, it
520 is necessary to read ``/proc/PID/smaps`` and count the FilePmdMapped fields
521 for each mapping.
522
523 Note that reading the smaps file is expensive and reading it
524 frequently will incur overhead.
525
526 There are a number of counters in ``/proc/vmstat`` that may be used to
527 monitor how successfully the system is providing huge pages for use.
528
529 thp_fault_alloc
530 is incremented every time a huge page is successfully
531 allocated and charged to handle a page fault.
532
533 thp_collapse_alloc
534 is incremented by khugepaged when it has found
535 a range of pages to collapse into one huge page and has
536 successfully allocated a new huge page to store the data.
537
538 thp_fault_fallback
539 is incremented if a page fault fails to allocate or charge
540 a huge page and instead falls back to using small pages.
541
542 thp_fault_fallback_charge
543 is incremented if a page fault fails to charge a huge page and
544 instead falls back to using small pages even though the
545 allocation was successful.
546
547 thp_collapse_alloc_failed
548 is incremented if khugepaged found a range
549 of pages that should be collapsed into one huge page but failed
550 the allocation.
551
552 thp_file_alloc
553 is incremented every time a shmem huge page is successfully
554 allocated (Note that despite being named after "file", the counter
555 measures only shmem).
556
557 thp_file_fallback
558 is incremented if a shmem huge page is attempted to be allocated
559 but fails and instead falls back to using small pages. (Note that
560 despite being named after "file", the counter measures only shmem).
561
562 thp_file_fallback_charge
563 is incremented if a shmem huge page cannot be charged and instead
564 falls back to using small pages even though the allocation was
565 successful. (Note that despite being named after "file", the
566 counter measures only shmem).
567
568 thp_file_mapped
569 is incremented every time a file or shmem huge page is mapped into
570 user address space.
571
572 thp_split_page
573 is incremented every time a huge page is split into base
574 pages. This can happen for a variety of reasons but a common
575 reason is that a huge page is old and is being reclaimed.
576 This action implies splitting all PMD the page mapped with.
577
578 thp_split_page_failed
579 is incremented if kernel fails to split huge
580 page. This can happen if the page was pinned by somebody.
581
582 thp_deferred_split_page
583 is incremented when a huge page is put onto split
584 queue. This happens when a huge page is partially unmapped and
585 splitting it would free up some memory. Pages on split queue are
586 going to be split under memory pressure.
587
588 thp_underused_split_page
589 is incremented when a huge page on the split queue was split
590 because it was underused. A THP is underused if the number of
591 zero pages in the THP is above a certain threshold
592 (/sys/kernel/mm/transparent_hugepage/khugepaged/max_ptes_none).
593
594 thp_split_pmd
595 is incremented every time a PMD split into table of PTEs.
596 This can happen, for instance, when application calls mprotect() or
597 munmap() on part of huge page. It doesn't split huge page, only
598 page table entry.
599
600 thp_zero_page_alloc
601 is incremented every time a huge zero page used for thp is
602 successfully allocated. Note, it doesn't count every map of
603 the huge zero page, only its allocation.
604
605 thp_zero_page_alloc_failed
606 is incremented if kernel fails to allocate
607 huge zero page and falls back to using small pages.
608
609 thp_swpout
610 is incremented every time a huge page is swapout in one
611 piece without splitting.
612
613 thp_swpout_fallback
614 is incremented if a huge page has to be split before swapout.
615 Usually because failed to allocate some continuous swap space
616 for the huge page.
617
618 In /sys/kernel/mm/transparent_hugepage/hugepages-<size>kB/stats, There are
619 also individual counters for each huge page size, which can be utilized to
620 monitor the system's effectiveness in providing huge pages for usage. Each
621 counter has its own corresponding file.
622
623 anon_fault_alloc
624 is incremented every time a huge page is successfully
625 allocated and charged to handle a page fault.
626
627 anon_fault_fallback
628 is incremented if a page fault fails to allocate or charge
629 a huge page and instead falls back to using huge pages with
630 lower orders or small pages.
631
632 anon_fault_fallback_charge
633 is incremented if a page fault fails to charge a huge page and
634 instead falls back to using huge pages with lower orders or
635 small pages even though the allocation was successful.
636
637 zswpout
638 is incremented every time a huge page is swapped out to zswap in one
639 piece without splitting.
640
641 swpin
642 is incremented every time a huge page is swapped in from a non-zswap
643 swap device in one piece.
644
645 swpin_fallback
646 is incremented if swapin fails to allocate or charge a huge page
647 and instead falls back to using huge pages with lower orders or
648 small pages.
649
650 swpin_fallback_charge
651 is incremented if swapin fails to charge a huge page and instead
652 falls back to using huge pages with lower orders or small pages
653 even though the allocation was successful.
654
655 swpout
656 is incremented every time a huge page is swapped out to a non-zswap
657 swap device in one piece without splitting.
658
659 swpout_fallback
660 is incremented if a huge page has to be split before swapout.
661 Usually because failed to allocate some continuous swap space
662 for the huge page.
663
664 shmem_alloc
665 is incremented every time a shmem huge page is successfully
666 allocated.
667
668 shmem_fallback
669 is incremented if a shmem huge page is attempted to be allocated
670 but fails and instead falls back to using small pages.
671
672 shmem_fallback_charge
673 is incremented if a shmem huge page cannot be charged and instead
674 falls back to using small pages even though the allocation was
675 successful.
676
677 split
678 is incremented every time a huge page is successfully split into
679 smaller orders. This can happen for a variety of reasons but a
680 common reason is that a huge page is old and is being reclaimed.
681
682 split_failed
683 is incremented if kernel fails to split huge
684 page. This can happen if the page was pinned by somebody.
685
686 split_deferred
687 is incremented when a huge page is put onto split queue.
688 This happens when a huge page is partially unmapped and splitting
689 it would free up some memory. Pages on split queue are going to
690 be split under memory pressure, if splitting is possible.
691
692 nr_anon
693 the number of anonymous THP we have in the whole system. These THPs
694 might be currently entirely mapped or have partially unmapped/unused
695 subpages.
696
697 nr_anon_partially_mapped
698 the number of anonymous THP which are likely partially mapped, possibly
699 wasting memory, and have been queued for deferred memory reclamation.
700 Note that in corner some cases (e.g., failed migration), we might detect
701 an anonymous THP as "partially mapped" and count it here, even though it
702 is not actually partially mapped anymore.
703
704 As the system ages, allocating huge pages may be expensive as the
705 system uses memory compaction to copy data around memory to free a
706 huge page for use. There are some counters in ``/proc/vmstat`` to help
707 monitor this overhead.
708
709 compact_stall
710 is incremented every time a process stalls to run
711 memory compaction so that a huge page is free for use.
712
713 compact_success
714 is incremented if the system compacted memory and
715 freed a huge page for use.
716
717 compact_fail
718 is incremented if the system tries to compact memory
719 but failed.
720
721 It is possible to establish how long the stalls were using the function
722 tracer to record how long was spent in __alloc_pages() and
723 using the mm_page_alloc tracepoint to identify which allocations were
724 for huge pages.
725
726 Optimizing the applications
727 ===========================
728
729 To be guaranteed that the kernel will map a THP immediately in any
730 memory region, the mmap region has to be hugepage naturally
731 aligned. posix_memalign() can provide that guarantee.
732
733 Hugetlbfs
734 =========
735
736 You can use hugetlbfs on a kernel that has transparent hugepage
737 support enabled just fine as always. No difference can be noted in
738 hugetlbfs other than there will be less overall fragmentation. All
739 usual features belonging to hugetlbfs are preserved and
740 unaffected. libhugetlbfs will also work fine as usual.
741

3. 한국어 전문 번역

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

목표와 전제

1-21

큰 memory working set을 다루는 성능 중심 application은 이미 libhugetlbfs와 hugetlbfs를 사용합니다. Transparent HugePage Support(THP)는 virtual memory backing에 hugepage를 사용하는 대안으로, page size를 자동 승격·강등하며 hugetlbfs의 단점을 피합니다.

현재 THP는 anonymous memory mapping과 tmpfs/shmem에서 동작하며, 앞으로 다른 filesystem으로 확장될 수 있습니다.

이 문서의 예시는 기본 page size가 4K이고 hugepage size가 2M이라고 가정합니다. 실제 값은 CPU architecture에 따라 달라질 수 있습니다.

성능 이점

22-49

첫 번째 이점은 user space가 건드린 각 2M virtual region에서 page fault를 한 번만 처리해 kernel 진입·복귀 빈도를 512배 줄이는 것입니다. 다만 mapping lifetime의 최초 접근에만 영향을 주고, fault에서 더 큰 clear-page·copy-page가 필요하다는 단점도 있어 중요도는 낮습니다.

두 번째이자 지속적인 핵심 이점은 모든 후속 memory access에 영향을 줍니다. TLB miss 처리 자체가 빨라지고, 하나의 TLB entry가 더 큰 virtual memory를 mapping해 miss 횟수가 줄어듭니다. Nested page table을 쓰는 virtualization에서는 KVM과 Linux guest 모두 hugepage를 쓰면 가장 큰 이득을 얻지만 한쪽만 사용해도 miss 처리 단축 효과가 있습니다.

요소동작효과
Page fault2M virtual region당 최초 1회4K page 대비 kernel 진입·복귀 빈도를 최대 512배 감소
TLBmiss 처리 단축과 entry coverage 확대전체 runtime 동안 miss 횟수와 비용을 줄임

Multi-size THP와 자동 collapse

50-76

Modern kernel의 multi-size THP(mTHP)는 base page보다 크고 전통적인 PMD size보다 작은 power-of-2 page block을 지원합니다. Anonymous memory를 16K, 32K, 64K 등으로 backing할 수 있으며 PTE mapping을 유지합니다.

mTHP는 fault 횟수를 4배·8배·16배 등으로 줄이면서 PMD THP보다 page가 작아 clear해야 할 memory와 latency spike가 적습니다. 일부 architecture는 virtual·physical contiguous PTE 묶음에 TLB compression을 적용해 miss 빈도도 줄입니다.

THP는 system-wide, 특정 task, 또는 task address space의 특정 range로 제한할 수 있습니다. 완전히 비활성화하지 않으면 `khugepaged`가 memory를 scan해 basic page sequence를 PMD-size hugepage로 collapse합니다. 동작은 sysfs, madvise(2), prctl(2)로 제어합니다.

THP size 계층
형태예시 sizemapping과 특성
Base page4KPTE mapping, fault와 TLB entry 수가 많음
mTHP16K / 32K / 64K ...PTE mapping, power-of-2 block
PMD THP2M512 × 4K, PMD mapping
Architecture실제 base·huge page size와 지원 mTHP size는 CPU architecture마다 다릅니다.

mTHP는 4K base page와 2M PMD THP 사이에서 fault 감소와 latency·memory 비용을 절충합니다.

hugetlbfs 대비 장점과 적용 범위

77-103

THP는 hugetlbfs의 reservation 방식보다 free memory 활용도를 높입니다. 사용하지 않는 memory를 cache나 movable·unmovable entity에 쓸 수 있고, allocation 실패를 숨기기 위한 사전 예약이 필요하지 않으며 paging과 고급 VM 기능을 hugepage에서도 사용할 수 있습니다. Application 수정 없이도 이점을 얻습니다.

User space가 모든 malloc(4k)마다 mmap을 남발하지 않도록 최적화할 수 있지만 필수는 아닙니다. `khugepaged`는 hugepage를 모르는 application의 장기 page allocation도 처리합니다.

System-wide hugepage는 큰 region에서 1 byte만 건드려도 4K 대신 2M을 할당하는 낭비를 만들 수 있습니다. 그래서 system-wide로 끄고 `MADV_HUGEPAGE` region에서만 허용할 수 있습니다. Embedded system은 precious memory 낭비를 피하도록 madvise region으로 제한하는 편이 안전합니다.

Hugepage 이득이 크고 memory 손실 위험이 없는 application은 중요한 mmap region에 `madvise(MADV_HUGEPAGE)`를 사용해야 합니다.

THP size별·top-level enabled

104-150

Anonymous memory THP는 지원되는 size별로 system-wide always, `MADV_HUGEPAGE` region 전용 madvise, 또는 never로 설정할 수 있습니다.

echo always >/sys/kernel/mm/transparent_hugepage/hugepages-<size>kB/enabled
echo madvise >/sys/kernel/mm/transparent_hugepage/hugepages-<size>kB/enabled
echo never >/sys/kernel/mm/transparent_hugepage/hugepages-<size>kB/enabled

예를 들어 2M THP를 always로 설정합니다.

echo always >/sys/kernel/mm/transparent_hugepage/hugepages-2048kB/enabled

해당 size가 top-level enabled 값을 상속하도록 지정할 수도 있습니다.

echo inherit >/sys/kernel/mm/transparent_hugepage/hugepages-<size>kB/enabled

2M THP 상속 예시는 다음과 같습니다.

echo inherit >/sys/kernel/mm/transparent_hugepage/hugepages-2048kB/enabled

Top-level enabled 값은 다음 command 중 하나로 설정합니다.

echo always >/sys/kernel/mm/transparent_hugepage/enabled
echo madvise >/sys/kernel/mm/transparent_hugepage/enabled
echo never >/sys/kernel/mm/transparent_hugepage/enabled
상태의미
always지원되는 해당 THP size를 system-wide로 사용
madvise`MADV_HUGEPAGE`로 지정한 region에서 사용
never일반 fault/collapse 경로에서 해당 size를 사용하지 않음
inherittop-level `transparent_hugepage/enabled` 값을 상속

모든 sysfs THP control을 never로 설정해도 global THP가 완전히 꺼지는 것은 아닙니다. `madvise(..., MADV_COLLAPSE)`는 이 설정을 무시하고 PMD-size hugepage로 무조건 collapse합니다.

기본값은 PMD-size hugepage의 enabled가 inherit이고 다른 size는 never입니다. 여러 size를 활성화하면 kernel이 allocation마다 가장 적절한 enabled size를 선택합니다.

THP control 우선순위
계층control역할
1Per-size enabledalways / madvise / never / inherit
2Top-level enabledinherit size의 기본 정책
3Process prctlprocess 전체 허용 범위 제한
4madviseregion hint 또는 explicit MADV_COLLAPSE

Per-size inherit는 top-level 값을 사용하지만 process와 madvise hint가 실제 적용 범위를 더 좁히거나 `MADV_COLLAPSE`로 명시적 collapse를 요청할 수 있습니다.

Defrag 정책

151-199

Anonymous hugepage가 즉시 free하지 않을 때 VM의 defrag 노력을 제한하거나, defrag 없이 regular page로 fallback하도록 선택할 수 있습니다. Defrag CPU 비용은 이후 hugepage 이득으로 상쇄되기를 기대하지만 보장되지는 않으며 `MADV_HUGEPAGE` allocation에서 가능성이 더 높습니다.

echo always >/sys/kernel/mm/transparent_hugepage/defrag
echo defer >/sys/kernel/mm/transparent_hugepage/defrag
echo defer+madvise >/sys/kernel/mm/transparent_hugepage/defrag
echo madvise >/sys/kernel/mm/transparent_hugepage/defrag
echo never >/sys/kernel/mm/transparent_hugepage/defrag
mode동작
alwaysallocation 실패 시 application을 멈추고 direct reclaim·compaction 수행
deferkswapd·kcompactd를 깨우고 khugepaged가 나중에 THP를 설치
defer+madvise`MADV_HUGEPAGE` region은 direct reclaim·compaction, 나머지는 background 처리
madvise`MADV_HUGEPAGE` region에서만 direct reclaim 수행하는 기본 mode
neverdefrag를 시도하지 않고 regular page로 fallback; `MADV_COLLAPSE`는 예외

always는 즉시 THP를 얻기 위해 application stall을 허용하므로 THP 이득이 크고 시작 지연을 감수하는 VM에 적합합니다. defer는 background daemon을 깨우고 khugepaged가 나중에 설치하게 합니다. madvise 계열은 명시된 region에 direct reclaim·compaction 비용을 집중합니다.

Zero page와 underused THP

200-227

Kernel은 anonymous read fault에서 기본적으로 PMD-mappable huge zero page를 사용합니다. 0을 기록하면 끄고 1을 기록하면 다시 켭니다.

echo 0 >/sys/kernel/mm/transparent_hugepage/use_zero_page
echo 1 >/sys/kernel/mm/transparent_hugepage/use_zero_page

User space는 다음 file에서 PMD-mappable THP size를 byte 단위로 읽을 수 있습니다.

cat /sys/kernel/mm/transparent_hugepage/hpage_pmd_size

Fault와 collapse 시 모든 THP는 `_deferred_list`에 들어가며 underused로 판단되면 memory pressure에서 split됩니다. THP의 zero-filled page 수가 `max_ptes_none`보다 많으면 underused입니다. `shrink_underused`에 0 또는 1을 기록해 이 동작을 끄거나 켭니다.

echo 0 > /sys/kernel/mm/transparent_hugepage/shrink_underused
echo 1 > /sys/kernel/mm/transparent_hugepage/shrink_underused

PMD-size THP의 per-size anon control 또는 top-level control이 always나 madvise이면 khugepaged가 자동 시작되고, 둘 다 never이면 자동 종료됩니다.

Process THP control

228-263

Process는 prctl(2)의 `PR_SET_THP_DISABLE`과 `PR_GET_THP_DISABLE`로 자체 THP 동작을 제어합니다. `PR_SET_THP_DISABLE` 설정은 fork(2)와 execve(2)에 걸쳐 상속됩니다.

prctl(PR_SET_THP_DISABLE, 1, 0, 0, 0):
This will disable THPs completely for the process, irrespective
of global THP controls or madvise(..., MADV_COLLAPSE) being used.

prctl(PR_SET_THP_DISABLE, 1, PR_THP_DISABLE_EXCEPT_ADVISED, 0, 0):
This will disable THPs for the process except when the usage of THPs is
advised. Consequently, THPs will only be used when:
- Global THP controls are set to "always" or "madvise" and
madvise(..., MADV_HUGEPAGE) or madvise(..., MADV_COLLAPSE) is used.
- Global THP controls are set to "never" and madvise(..., MADV_COLLAPSE)
is used. This is the same behavior as if THPs would not be disabled on
a process level.
Note that MADV_COLLAPSE is currently always rejected if
madvise(..., MADV_NOHUGEPAGE) is set on an area.

prctl(PR_SET_THP_DISABLE, 0, 0, 0, 0):
This will re-enable THPs for the process, as if they were never disabled.
Whether THPs will actually be used depends on global THP controls and
madvise() calls.

prctl(PR_GET_THP_DISABLE, 0, 0, 0, 0):
This returns a value whose bits indicate how THP-disable is configured:
Bits
1 0  Value  Description
|0|0|   0    No THP-disable behaviour specified.
|0|1|   1    THP is entirely disabled for this process.
|1|1|   3    THP-except-advised mode is set for this process.
호출효과
`PR_SET_THP_DISABLE, 1, 0, 0, 0`global control과 `MADV_COLLAPSE`에 관계없이 process THP 완전 비활성화
`PR_SET_THP_DISABLE, 1, PR_THP_DISABLE_EXCEPT_ADVISED, 0, 0`명시적으로 권고된 region에서만 THP 허용
`PR_SET_THP_DISABLE, 0, 0, 0, 0`process-level disable을 해제하고 global·madvise 정책으로 복귀
`PR_GET_THP_DISABLE, 0, 0, 0, 0`THP-disable 설정 bit를 반환
bits설명
`|0|0|`0THP-disable 동작을 지정하지 않음
`|0|1|`1이 process에서 THP 완전 비활성화
`|1|1|`3THP-except-advised mode

`PR_THP_DISABLE_EXCEPT_ADVISED` mode에서도 `MADV_NOHUGEPAGE`가 설정된 area에는 `MADV_COLLAPSE`가 항상 거부됩니다.

Khugepaged scan과 진행량

264-310

현재 khugepaged는 PMD-size THP로 collapse할 기회만 찾으며 다른 THP size로 collapse하지 않습니다.

khugepaged는 보통 낮은 빈도로 실행되므로 page fault에서 synchronous defrag를 피하더라도 background에서는 defrag를 수행할 가치가 있습니다. 다음 setting으로 khugepaged defrag를 끄거나 켭니다.

echo 0 >/sys/kernel/mm/transparent_hugepage/khugepaged/defrag
echo 1 >/sys/kernel/mm/transparent_hugepage/khugepaged/defrag

한 pass에서 scan할 page 수를 제어합니다.

/sys/kernel/mm/transparent_hugepage/khugepaged/pages_to_scan

Pass 사이 대기 millisecond를 지정하며 0이면 한 core를 100% 사용합니다.

/sys/kernel/mm/transparent_hugepage/khugepaged/scan_sleep_millisecs

Hugepage allocation 실패 뒤 다음 allocation 시도까지의 대기 시간을 지정합니다.

/sys/kernel/mm/transparent_hugepage/khugepaged/alloc_sleep_millisecs

`pages_collapsed`는 PTE mapping을 PMD로 바꾸거나 여러 4K physical page를 하나의 2M hugepage로 교체하는 서로 다른 의미를 포함할 수 있어 대략적인 진행 신호로 해석해야 합니다. 정확한 accounting에는 `/proc/vmstat`을 사용합니다.

/sys/kernel/mm/transparent_hugepage/khugepaged/pages_collapsed

완료한 full scan 수는 다음 file에서 봅니다.

/sys/kernel/mm/transparent_hugepage/khugepaged/full_scans
항목sysfs의미
defrag`khugepaged/defrag`background collapse를 위한 memory compaction 허용
scan 양`pages_to_scan`한 pass에서 검사할 page 수
pass 간격`scan_sleep_millisecs`pass 사이 대기 시간; 0이면 한 core를 100% 사용
실패 간격`alloc_sleep_millisecs`hugepage allocation 실패 뒤 다음 시도까지 대기
진행량`pages_collapsed`collapse 진행 신호이며 정확한 accounting은 `/proc/vmstat` 사용
pass 수`full_scans`완료한 full scan 횟수

Khugepaged collapse threshold

311-339

`max_ptes_none`은 small page group을 하나의 large page로 collapse할 때 추가 할당할 수 있는 아직 mapping되지 않은 small page 수입니다.

/sys/kernel/mm/transparent_hugepage/khugepaged/max_ptes_none

값이 높으면 program memory 사용이 늘고, 낮으면 THP 성능 이득이 줄 수 있습니다. CPU 낭비는 매우 작습니다.

`max_ptes_swap`은 collapse 중 swap에서 가져올 수 있는 page 수입니다. 높으면 과도한 swap I/O와 memory 낭비를 만들고, 낮으면 collapse가 막혀 memory access 성능이 낮아질 수 있습니다.

/sys/kernel/mm/transparent_hugepage/khugepaged/max_ptes_swap

`max_ptes_shared`는 여러 process가 공유해도 collapse를 허용할 page 수입니다. THP의 page 하나라도 공유되면 khugepaged가 THP page를 shared로 취급할 수 있으며 threshold 초과 시 collapse를 막습니다. 높은 값은 일부 workload의 footprint를 늘립니다.

/sys/kernel/mm/transparent_hugepage/khugepaged/max_ptes_shared
항목sysfstradeoff
빈 PTE`max_ptes_none`collapse 중 새로 할당할 수 있는 아직 mapping되지 않은 small page 수
swap PTE`max_ptes_swap`collapse 중 swap에서 가져올 수 있는 page 수
공유 PTE`max_ptes_shared`여러 process가 공유해도 collapse를 허용할 page 수

Boot parameter

340-400

Kernel command line의 `transparent_hugepage=always`, `transparent_hugepage=madvise`, `transparent_hugepage=never`로 top-level enabled의 boot 기본값을 바꿀 수 있습니다.

지원되는 anonymous THP size별 정책은 `thp_anon=<size>[KMG],<size>[KMG]:<state>;<size>[KMG]-<size>[KMG]:<state>` 형식으로 설정합니다. Size는 PAGE_SIZE의 power of 2이면서 지원되는 anonymous THP여야 하며 state는 always, madvise, never, inherit 중 하나입니다.

다음 예시는 16K–64K를 always, 128K와 512K를 inherit, 256K를 madvise, 1M–2M을 never로 설정합니다.

thp_anon=16K-64K:always;128K,512K:inherit;256K:madvise;1M-2M:never

`thp_anon=`은 여러 번 지정할 수 있습니다. 한 번이라도 지정하면 command line에서 명시하지 않은 anonymous THP size는 implicitly never가 됩니다. 유효한 설정이 있으면 PMD_ORDER policy도 override되며 명시하지 않은 PMD_ORDER는 never가 됩니다.

`transparent_hugepage_shmem=<policy>`는 internal shmem mount의 global allocation 정책을, `transparent_hugepage_tmpfs=<policy>`는 일반 tmpfs mount의 기본 정책을 정합니다. tmpfs 기본값은 never입니다.

`thp_shmem`은 `thp_anon`과 같은 형식으로 shmem size별 정책을 제어하고 within_size도 지원합니다. 한 번이라도 지정하면 명시하지 않은 size는 never이며, 유효한 설정은 PMD_ORDER의 inherit 기본값을 override합니다.

parameter범위
`transparent_hugepage=`always / madvise / nevertop-level anonymous THP toggle의 boot 기본값
`thp_anon=`size 또는 range별 always / madvise / never / inheritanonymous mTHP size별 정책
`transparent_hugepage_shmem=`shmem global policyinternal shmem mount의 allocation 정책
`transparent_hugepage_tmpfs=`always / within_size / advise / never일반 tmpfs mount의 기본 정책
`thp_shmem=``thp_anon` 형식 + within_sizeshmem THP size별 정책

tmpfs/shmem의 hugepage

401-413

과거 tmpfs는 PMD라는 단일 hugepage size만 지원했지만 이제 anonymous memory처럼 smaller mTHP를 지원합니다. Kernel에서는 모든 size의 hugepage를 흔히 large folio로 표현합니다.

Internal shmem mount는 size를 세밀하게 제어할 수 있지만 일반 tmpfs mount는 정확한 size를 지정하지 않고 사용 가능한 모든 hugepage size를 활용해 다른 filesystem과 비슷하게 동작합니다.

일반 tmpfs mount 정책

414-458

tmpfs mount의 THP allocation policy는 `huge=` mount option으로 조정합니다.

policy동작
always새 page마다 hugepage를 시도하고 PMD size 실패 시 smaller size로 fallback
neverhugepage를 할당하지 않음; `MADV_COLLAPSE`는 예외
within_size`i_size` 안에 완전히 들어갈 때만 할당하며 madvise hint도 존중
advisemadvise로 요청한 경우에만 할당
deny긴급 시 모든 tmpfs mount의 huge option을 강제로 끔
force시험을 위해 모든 mount의 huge option을 강제로 켬

Kernel은 사용 가능한 모든 size를 쓸 수 있으며 internal tmpfs처럼 세밀한 size control은 제공하지 않습니다. 과거 기본값은 never였지만 이제 `transparent_hugepage_tmpfs=<policy>` boot parameter로 조정할 수 있습니다.

Mount 뒤에도 `mount -o remount,huge= /mountpoint`가 동작합니다. huge=never로 remount하면 기존 hugepage를 분할하지 않고 새 allocation만 중단합니다.

Global `/sys/kernel/mm/transparent_hugepage/shmem_enabled`의 deny는 긴급 시 모든 mount의 huge option을 끄고, force는 시험을 위해 모두 켭니다.

Internal shmem mount

459-496

Internal tmpfs mount는 SysV SHM, memfd, `/dev/zero` 또는 `MAP_ANONYMOUS`의 shared anonymous mmap, GPU driver의 DRM object, Ashmem에 사용됩니다.

Global `/sys/kernel/mm/transparent_hugepage/shmem_enabled`와 size별 `/sys/kernel/mm/transparent_hugepage/hugepages-<size>kB/shmem_enabled`로 THP allocation policy를 제어합니다.

Global knob은 tmpfs의 huge= option과 같은 의미지만 size를 개별 제어할 수 있고 per-size knob이 inherit일 때만 global 값을 사용합니다. 과거 시험용 artifact인 force와 deny는 개별 size에서 제거되었습니다.

policy해당 size 동작
always새 page가 필요할 때 해당 `<size>` hugepage 할당 시도
inherittop-level `shmem_enabled` 값을 상속
never해당 `<size>` hugepage를 할당하지 않음; `MADV_COLLAPSE`는 예외
within_size`i_size` 안에 완전히 들어갈 때만 할당하고 madvise hint 존중
advisemadvise 요청이 있을 때만 해당 size 할당

Application restart 필요성

497-505

`transparent_hugepage/enabled`, `transparent_hugepage/hugepages-<size>kB/enabled`, tmpfs mount option은 향후 동작에만 영향을 줍니다. Hugepage를 사용했을 수 있는 application을 restart해야 새 설정이 적용되며, khugepaged에 등록된 region도 마찬가지입니다.

사용량 관찰

506-532

현재 사용 중인 PMD-size anonymous THP 수는 `/proc/meminfo`의 AnonHugePages에서 읽습니다. Application별 사용량은 `/proc/PID/smaps`의 mapping별 AnonHugePages를 합산합니다. 역사적 이유로 이 field는 PMD THP에만 적용되며 정확히는 AnonHugePmdMapped라는 이름이 더 적절합니다.

User space에 mapping된 file THP는 `/proc/meminfo`의 ShmemPmdMapped와 ShmemHugePages로 보고, application별 mapping은 `/proc/PID/smaps`의 FilePmdMapped를 합산합니다.

interface의미
`/proc/meminfo: AnonHugePages`현재 사용 중인 PMD-size anonymous THP
`/proc/PID/smaps: AnonHugePages`mapping별 PMD-size anonymous THP
`/proc/meminfo: ShmemPmdMapped`, `ShmemHugePages`user space에 mapping된 file/shmem THP
`/proc/PID/smaps: FilePmdMapped`application mapping별 file THP

smaps 판독은 비싸므로 자주 읽으면 overhead가 발생합니다. Hugepage 제공 성공률은 `/proc/vmstat` counter로 관찰할 수 있습니다.

전역 THP vmstat counter

533-612

다음 `/proc/vmstat` counter는 fault allocation, khugepaged collapse, fallback, mapping, split, zero page와 swapout 결과를 구분합니다. 이름에 file이 들어간 일부 counter는 실제로 shmem만 측정한다는 점에 주의합니다.

counter증가 조건
thp_fault_allocpage fault 처리용 hugepage allocation·charge 성공
thp_collapse_allockhugepaged collapse용 새 hugepage allocation 성공
thp_fault_fallbackfault에서 hugepage 확보 실패 후 small page 사용
thp_fault_fallback_chargeallocation은 성공했지만 charge 실패 후 small page 사용
thp_collapse_alloc_failedcollapse 대상은 찾았지만 hugepage allocation 실패
thp_file_allocshmem hugepage allocation 성공
thp_file_fallbackshmem hugepage allocation 실패 후 small page 사용
thp_file_fallback_chargeshmem hugepage charge 실패 후 small page 사용
thp_file_mappedfile 또는 shmem hugepage를 user address space에 mapping
thp_split_pagehugepage를 base page로 분할
thp_split_page_failedpin 등의 이유로 hugepage 분할 실패
thp_deferred_split_pagepartially unmapped hugepage를 split queue에 추가
thp_underused_split_pagezero page 수가 threshold를 넘은 underused THP를 split
thp_split_pmdPMD를 PTE table로 분할하며 physical hugepage는 유지
thp_zero_page_allochuge zero page 자체 allocation 성공
thp_zero_page_alloc_failedhuge zero page allocation 실패 후 small page 사용
thp_swpouthugepage를 분할하지 않고 한 덩어리로 swapout
thp_swpout_fallback연속 swap 공간 부족 등으로 swapout 전에 hugepage 분할

THP size별 stats

613-696

`/sys/kernel/mm/transparent_hugepage/hugepages-<size>kB/stats`에는 각 hugepage size별 counter file이 있습니다. Anonymous fault, zswap·swap I/O, shmem, split과 현재 anonymous THP 수를 size별로 관찰할 수 있습니다.

counter증가 또는 값의 의미
anon_fault_alloc해당 size anonymous hugepage fault allocation·charge 성공
anon_fault_fallbackallocation 또는 charge 실패 후 lower-order hugepage나 small page 사용
anon_fault_fallback_chargeallocation 성공·charge 실패 후 lower-order hugepage나 small page 사용
zswpouthugepage를 분할하지 않고 zswap으로 swapout
swpinnon-zswap device에서 hugepage를 한 덩어리로 swapin
swpin_fallbackswapin allocation·charge 실패 후 lower-order hugepage나 small page 사용
swpin_fallback_chargeswapin allocation 성공·charge 실패 후 lower-order 또는 small page 사용
swpoutnon-zswap device로 hugepage를 한 덩어리로 swapout
swpout_fallback연속 swap 공간 부족 등으로 swapout 전에 분할
shmem_allocshmem hugepage allocation 성공
shmem_fallbackshmem hugepage allocation 실패 후 small page 사용
shmem_fallback_chargeshmem hugepage charge 실패 후 small page 사용
splithugepage를 smaller order로 분할 성공
split_failedpin 등의 이유로 분할 실패
split_deferredpartially unmapped hugepage를 split queue에 추가
nr_anonsystem 전체 anonymous THP 수
nr_anon_partially_mapped부분 mapping으로 판단되어 deferred reclaim queue에 들어간 anonymous THP 수

`nr_anon_partially_mapped`는 deferred reclaim 대상 수를 나타내지만 migration 실패 같은 corner case에서는 실제로 더 이상 partial mapping이 아닌 THP가 포함될 수 있습니다.

Compaction overhead 관찰

697-725

System이 오래 실행될수록 hugepage 확보를 위해 memory compaction이 data를 이동해야 하므로 allocation 비용이 커질 수 있습니다. `/proc/vmstat`의 다음 counter로 이 overhead를 관찰합니다.

counter의미
compact_stallhugepage 확보를 위해 process가 compaction에서 stall
compact_successcompaction으로 hugepage 공간 확보 성공
compact_failcompaction을 시도했지만 공간 확보 실패

Function tracer로 `__alloc_pages()`에 머문 시간을 기록하고 `mm_page_alloc` tracepoint로 hugepage allocation을 식별하면 stall 시간을 측정할 수 있습니다.

Application 최적화

726-732

Kernel이 어떤 memory region에서든 즉시 THP를 mapping하도록 보장하려면 mmap region이 hugepage natural alignment를 만족해야 합니다. `posix_memalign()`이 이를 보장할 수 있습니다.

Hugetlbfs와의 공존

733-740

Transparent hugepage support가 활성화된 kernel에서도 hugetlbfs를 평소처럼 사용할 수 있습니다. 전체 fragmentation이 줄어드는 것 외에는 차이가 없고 hugetlbfs의 기존 기능은 보존되며 영향을 받지 않습니다. libhugetlbfs도 그대로 동작합니다.