요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
.. SPDX-License-Identifier: GPL-2.0
=============
Multi-Gen LRU
=============
The multi-gen LRU is an alternative LRU implementation that optimizes
page reclaim and improves performance under memory pressure. Page
reclaim decides the kernel's caching policy and ability to overcommit
memory. It directly impacts the kswapd CPU usage and RAM efficiency.
Quick start
===========
Build the kernel with the following configurations.
* ``CONFIG_LRU_GEN=y``
* ``CONFIG_LRU_GEN_ENABLED=y``
All set!
Runtime options
===============
``/sys/kernel/mm/lru_gen/`` contains stable ABIs described in the
following subsections.
Kill switch
-----------
``enabled`` accepts different values to enable or disable the
following components. Its default value depends on
``CONFIG_LRU_GEN_ENABLED``. All the components should be enabled
unless some of them have unforeseen side effects. Writing to
``enabled`` has no effect when a component is not supported by the
hardware, and valid values will be accepted even when the main switch
is off.
====== ===============================================================
Values Components
====== ===============================================================
0x0001 The main switch for the multi-gen LRU.
0x0002 Clearing the accessed bit in leaf page table entries in large
batches, when MMU sets it (e.g., on x86). This behavior can
theoretically worsen lock contention (mmap_lock). If it is
disabled, the multi-gen LRU will suffer a minor performance
degradation for workloads that contiguously map hot pages,
whose accessed bits can be otherwise cleared by fewer larger
batches.
0x0004 Clearing the accessed bit in non-leaf page table entries as
well, when MMU sets it (e.g., on x86). This behavior was not
verified on x86 varieties other than Intel and AMD. If it is
disabled, the multi-gen LRU will suffer a negligible
performance degradation.
[yYnN] Apply to all the components above.
====== ===============================================================
E.g.,
::
echo y >/sys/kernel/mm/lru_gen/enabled
cat /sys/kernel/mm/lru_gen/enabled
0x0007
echo 5 >/sys/kernel/mm/lru_gen/enabled
cat /sys/kernel/mm/lru_gen/enabled
0x0005
Thrashing prevention
--------------------
Personal computers are more sensitive to thrashing because it can
cause janks (lags when rendering UI) and negatively impact user
experience. The multi-gen LRU offers thrashing prevention to the
majority of laptop and desktop users who do not have ``oomd``.
Users can write ``N`` to ``min_ttl_ms`` to prevent the working set of
``N`` milliseconds from getting evicted. The OOM killer is triggered
if this working set cannot be kept in memory. In other words, this
option works as an adjustable pressure relief valve, and when open, it
terminates applications that are hopefully not being used.
Based on the average human detectable lag (~100ms), ``N=1000`` usually
eliminates intolerable janks due to thrashing. Larger values like
``N=3000`` make janks less noticeable at the risk of premature OOM
kills.
The default value ``0`` means disabled.
Experimental features
=====================
``/sys/kernel/debug/lru_gen`` accepts commands described in the
following subsections. Multiple command lines are supported, so does
concatenation with delimiters ``,`` and ``;``.
``/sys/kernel/debug/lru_gen_full`` provides additional stats for
debugging. ``CONFIG_LRU_GEN_STATS=y`` keeps historical stats from
evicted generations in this file.
Working set estimation
----------------------
Working set estimation measures how much memory an application needs
in a given time interval, and it is usually done with little impact on
the performance of the application. E.g., data centers want to
optimize job scheduling (bin packing) to improve memory utilizations.
When a new job comes in, the job scheduler needs to find out whether
each server it manages can allocate a certain amount of memory for
this new job before it can pick a candidate. To do so, the job
scheduler needs to estimate the working sets of the existing jobs.
When it is read, ``lru_gen`` returns a histogram of numbers of pages
accessed over different time intervals for each memcg and node.
``MAX_NR_GENS`` decides the number of bins for each histogram. The
histograms are noncumulative.
::
memcg memcg_id memcg_path
node node_id
min_gen_nr age_in_ms nr_anon_pages nr_file_pages
...
max_gen_nr age_in_ms nr_anon_pages nr_file_pages
Each bin contains an estimated number of pages that have been accessed
within ``age_in_ms``. E.g., ``min_gen_nr`` contains the coldest pages
and ``max_gen_nr`` contains the hottest pages, since ``age_in_ms`` of
the former is the largest and that of the latter is the smallest.
Users can write the following command to ``lru_gen`` to create a new
generation ``max_gen_nr+1``:
``+ memcg_id node_id max_gen_nr [can_swap [force_scan]]``
``can_swap`` defaults to the swap setting and, if it is set to ``1``,
it forces the scan of anon pages when swap is off, and vice versa.
``force_scan`` defaults to ``1`` and, if it is set to ``0``, it
employs heuristics to reduce the overhead, which is likely to reduce
the coverage as well.
A typical use case is that a job scheduler runs this command at a
certain time interval to create new generations, and it ranks the
servers it manages based on the sizes of their cold pages defined by
this time interval.
Proactive reclaim
-----------------
Proactive reclaim induces page reclaim when there is no memory
pressure. It usually targets cold pages only. E.g., when a new job
comes in, the job scheduler wants to proactively reclaim cold pages on
the server it selected, to improve the chance of successfully landing
this new job.
Users can write the following command to ``lru_gen`` to evict
generations less than or equal to ``min_gen_nr``.
``- memcg_id node_id min_gen_nr [swappiness [nr_to_reclaim]]``
``min_gen_nr`` should be less than ``max_gen_nr-1``, since
``max_gen_nr`` and ``max_gen_nr-1`` are not fully aged (equivalent to
the active list) and therefore cannot be evicted. ``swappiness``
overrides the default value in ``/proc/sys/vm/swappiness`` and the valid
range is [0-200, max], with max being exclusively used for the reclamation
of anonymous memory. ``nr_to_reclaim`` limits the number of pages to evict.
A typical use case is that a job scheduler runs this command before it
tries to land a new job on a server. If it fails to materialize enough
cold pages because of the overestimation, it retries on the next
server according to the ranking result obtained from the working set
estimation step. This less forceful approach limits the impacts on the
existing jobs.
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
Multi-Gen LRU 개요
1-10Multi-Gen LRU는 page reclaim을 최적화하고 memory pressure에서 성능을 개선하는 대체 LRU 구현입니다. Page reclaim은 kernel caching policy와 memory overcommit 능력을 결정하므로 kswapd CPU 사용량과 RAM 효율에 직접 영향을 줍니다.
빠른 시작
11-19Kernel을 CONFIG_LRU_GEN=y와 CONFIG_LRU_GEN_ENABLED=y로 build하면 Multi-Gen LRU를 사용할 준비가 끝납니다.
| 구성 | 역할 |
|---|---|
| CONFIG_LRU_GEN=y | Multi-Gen LRU 기능을 build |
| CONFIG_LRU_GEN_ENABLED=y | 기능을 기본 활성화 |
Runtime kill switch
20-63/sys/kernel/mm/lru_gen/에는 이 문서가 설명하는 stable ABI가 있습니다. enabled는 여러 component를 bitmask 또는 y/n으로 켜고 끕니다. 기본값은 CONFIG_LRU_GEN_ENABLED에 따르며, 예상하지 못한 side effect가 없다면 모든 component를 켜야 합니다.
Hardware가 component를 지원하지 않으면 enabled에 써도 효과가 없습니다. Main switch가 꺼져 있어도 유효한 값 자체는 받아들입니다.
| 값 | Component |
|---|---|
| 0x0001 | Multi-Gen LRU의 main switch |
| 0x0002 | MMU가 설정한 leaf page-table entry의 accessed bit를 큰 batch로 clear. mmap_lock contention을 이론상 악화시킬 수 있으나 끄면 contiguous hot-page mapping workload가 약간 느려질 수 있음 |
| 0x0004 | MMU가 설정한 non-leaf page-table entry의 accessed bit도 clear. Intel·AMD 이외 x86에서는 검증되지 않았고, 끄면 성능 저하는 무시할 정도 |
| y / Y / n / N | 위 모든 component에 한꺼번에 적용 |
다음 예에서 y는 세 bit를 모두 켜 0x0007이 되고, decimal 5는 0x0001과 0x0004만 켜 0x0005가 됩니다.
echo y >/sys/kernel/mm/lru_gen/enabled
cat /sys/kernel/mm/lru_gen/enabled
0x0007
echo 5 >/sys/kernel/mm/lru_gen/enabled
cat /sys/kernel/mm/lru_gen/enabled
0x0005
Thrashing 방지
64-83Personal computer는 thrashing이 UI rendering lag인 jank를 만들기 때문에 특히 민감합니다. Multi-Gen LRU는 oomd를 사용하지 않는 다수 laptop·desktop 사용자를 위해 thrashing prevention을 제공합니다.
min_ttl_ms에 N을 쓰면 최근 N milliseconds의 working set이 eviction되지 않습니다. 이 working set을 memory에 유지할 수 없으면 OOM killer가 실행됩니다. 즉, 조정 가능한 pressure relief valve처럼 동작하며 valve가 열리면 사용 중이 아닐 것으로 기대되는 application을 종료합니다.
| min_ttl_ms | 효과 |
|---|---|
| 0 | 기본값. thrashing prevention 비활성화 |
| 1000 | 약 100 ms인 인간 감지 lag 기준으로 intolerable UI jank를 대체로 제거 |
| 3000 | jank를 더 줄이지만 premature OOM kill 위험 증가 |
| N | 최근 N milliseconds의 working set을 eviction에서 보호 |
평균적으로 사람이 감지할 수 있는 lag가 약 100 ms라는 점을 기준으로 N=1000은 thrashing으로 인한 견디기 어려운 jank를 보통 제거합니다. N=3000 같은 더 큰 값은 jank를 덜 눈에 띄게 만들지만 OOM kill이 너무 일찍 일어날 위험이 있습니다.
실험 기능 ABI
84-93/sys/kernel/debug/lru_gen은 뒤 절의 command를 받습니다. 여러 command line을 한 번에 쓸 수 있고 comma(,)와 semicolon(;) delimiter로 이어 붙일 수도 있습니다.
/sys/kernel/debug/lru_gen_full은 debugging용 추가 statistic을 제공합니다. CONFIG_LRU_GEN_STATS=y이면 evicted generation의 historical statistic도 이 file에 유지합니다.
Working-set estimation 출력
94-121Working-set estimation은 주어진 time interval 동안 application에 필요한 memory 양을 측정하며 보통 application 성능에 미치는 영향이 작습니다. Data center는 memory utilization을 높이기 위한 job scheduling, 즉 bin packing에 이를 사용할 수 있습니다.
새 job이 들어오면 scheduler는 후보 server를 고르기 전에 각 server가 필요한 memory를 할당할 수 있는지 판단해야 합니다. 이를 위해 기존 job의 working set을 추정합니다.
lru_gen을 읽으면 memcg와 node마다 서로 다른 time interval에서 접근한 page 수의 histogram이 반환됩니다. MAX_NR_GENS가 각 histogram의 bin 수를 정하며 histogram은 cumulative이 아닙니다.
memcg memcg_id memcg_path
node node_id
min_gen_nr age_in_ms nr_anon_pages nr_file_pages
...
max_gen_nr age_in_ms nr_anon_pages nr_file_pages
원문의 들여쓰기 출력을 memcg, NUMA node, generation bin 계층으로 다시 구성했습니다.
각 bin은 age_in_ms 이내에 접근된 것으로 추정하는 page 수를 담습니다. min_gen_nr은 age가 가장 커 가장 차갑고, max_gen_nr은 age가 가장 작아 가장 뜨겁습니다.
새 generation 생성
122-137lru_gen에 다음 command를 쓰면 max_gen_nr+1인 새 generation을 만듭니다.
``+ memcg_id node_id max_gen_nr [can_swap [force_scan]]``
can_swap의 기본값은 현재 swap 설정입니다. 1이면 swap이 꺼져 있어도 anon page scan을 강제하고, 반대 값이면 그 반대로 동작합니다. force_scan 기본값은 1이며 0이면 overhead를 줄이는 heuristic을 사용하지만 coverage도 낮아질 가능성이 큽니다.
대표적인 사용법은 job scheduler가 일정 interval마다 이 command로 새 generation을 만든 뒤, 그 interval이 정의한 cold page 크기로 관리 대상 server의 순위를 매기는 것입니다.
Proactive reclaim
138-163Proactive reclaim은 memory pressure가 없을 때 page reclaim을 유도하며 보통 cold page만 대상으로 합니다. 새 job이 들어오면 scheduler는 선택한 server에서 cold page를 미리 회수해 job을 성공적으로 배치할 가능성을 높일 수 있습니다.
lru_gen에 다음 command를 쓰면 min_gen_nr 이하의 generation을 evict합니다.
``- memcg_id node_id min_gen_nr [swappiness [nr_to_reclaim]]``
min_gen_nr은 max_gen_nr-1보다 작아야 합니다. max_gen_nr과 max_gen_nr-1은 active list와 동등하게 aging이 끝나지 않았으므로 evict할 수 없습니다.
swappiness는 /proc/sys/vm/swappiness의 기본값을 override하며 유효 범위는 [0-200, max]입니다. max는 anonymous memory reclaim에만 배타적으로 사용합니다. nr_to_reclaim은 evict할 page 수를 제한합니다.
일반적으로 job scheduler는 새 job을 server에 배치하기 전에 이 command를 실행합니다. Working-set estimation이 과대 추정되어 충분한 cold page를 실제로 확보하지 못하면, 앞서 얻은 server ranking에 따라 다음 server에서 재시도합니다. 이 덜 강제적인 접근은 기존 job에 미치는 영향을 제한합니다.
운영 핵심
multigen_lru.rst:1-163Multi-Gen LRU는 page의 접근 시기를 여러 generation으로 분류해 cold page를 더 정교하게 회수합니다. Stable sysfs ABI로 기능과 working-set TTL을 제어하고, experimental debugfs ABI로 generation 생성과 proactive reclaim을 실행할 수 있습니다.