요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
.. SPDX-License-Identifier: GPL-2.0
===============
Physical Memory
===============
Linux is available for a wide range of architectures so there is a need for an
architecture-independent abstraction to represent the physical memory. This
chapter describes the structures used to manage physical memory in a running
system.
The first principal concept prevalent in the memory management is
`Non-Uniform Memory Access (NUMA)
<https://en.wikipedia.org/wiki/Non-uniform_memory_access>`_.
With multi-core and multi-socket machines, memory may be arranged into banks
that incur a different cost to access depending on the “distance” from the
processor. For example, there might be a bank of memory assigned to each CPU or
a bank of memory very suitable for DMA near peripheral devices.
Each bank is called a node and the concept is represented under Linux by a
``struct pglist_data`` even if the architecture is UMA. This structure is
always referenced by its typedef ``pg_data_t``. A ``pg_data_t`` structure
for a particular node can be referenced by ``NODE_DATA(nid)`` macro where
``nid`` is the ID of that node.
For NUMA architectures, the node structures are allocated by the architecture
specific code early during boot. Usually, these structures are allocated
locally on the memory bank they represent. For UMA architectures, only one
static ``pg_data_t`` structure called ``contig_page_data`` is used. Nodes will
be discussed further in Section :ref:`Nodes <nodes>`
The entire physical address space is partitioned into one or more blocks
called zones which represent ranges within memory. These ranges are usually
determined by architectural constraints for accessing the physical memory.
The memory range within a node that corresponds to a particular zone is
described by a ``struct zone``. Each zone has
one of the types described below.
* ``ZONE_DMA`` and ``ZONE_DMA32`` historically represented memory suitable for
DMA by peripheral devices that cannot access all of the addressable
memory. For many years there are better more and robust interfaces to get
memory with DMA specific requirements (Documentation/core-api/dma-api.rst),
but ``ZONE_DMA`` and ``ZONE_DMA32`` still represent memory ranges that have
restrictions on how they can be accessed.
Depending on the architecture, either of these zone types or even they both
can be disabled at build time using ``CONFIG_ZONE_DMA`` and
``CONFIG_ZONE_DMA32`` configuration options. Some 64-bit platforms may need
both zones as they support peripherals with different DMA addressing
limitations.
* ``ZONE_NORMAL`` is for normal memory that can be accessed by the kernel all
the time. DMA operations can be performed on pages in this zone if the DMA
devices support transfers to all addressable memory. ``ZONE_NORMAL`` is
always enabled.
* ``ZONE_HIGHMEM`` is the part of the physical memory that is not covered by a
permanent mapping in the kernel page tables. The memory in this zone is only
accessible to the kernel using temporary mappings. This zone is available
only on some 32-bit architectures and is enabled with ``CONFIG_HIGHMEM``.
* ``ZONE_MOVABLE`` is for normal accessible memory, just like ``ZONE_NORMAL``.
The difference is that the contents of most pages in ``ZONE_MOVABLE`` is
movable. That means that while virtual addresses of these pages do not
change, their content may move between different physical pages. Often
``ZONE_MOVABLE`` is populated during memory hotplug, but it may be
also populated on boot using one of ``kernelcore``, ``movablecore`` and
``movable_node`` kernel command line parameters. See
Documentation/mm/page_migration.rst and
Documentation/admin-guide/mm/memory-hotplug.rst for additional details.
* ``ZONE_DEVICE`` represents memory residing on devices such as PMEM and GPU.
It has different characteristics than RAM zone types and it exists to provide
:ref:`struct page <Pages>` and memory map services for device driver
identified physical address ranges. ``ZONE_DEVICE`` is enabled with
configuration option ``CONFIG_ZONE_DEVICE``.
It is important to note that many kernel operations can only take place using
``ZONE_NORMAL`` so it is the most performance critical zone. Zones are
discussed further in Section :ref:`Zones <zones>`.
The relation between node and zone extents is determined by the physical memory
map reported by the firmware, architectural constraints for memory addressing
and certain parameters in the kernel command line.
For example, with 32-bit kernel on an x86 UMA machine with 2 Gbytes of RAM the
entire memory will be on node 0 and there will be three zones: ``ZONE_DMA``,
``ZONE_NORMAL`` and ``ZONE_HIGHMEM``::
0 2G
+-------------------------------------------------------------+
| node 0 |
+-------------------------------------------------------------+
0 16M 896M 2G
+----------+-----------------------+--------------------------+
| ZONE_DMA | ZONE_NORMAL | ZONE_HIGHMEM |
+----------+-----------------------+--------------------------+
With a kernel built with ``ZONE_DMA`` disabled and ``ZONE_DMA32`` enabled and
booted with ``movablecore=80%`` parameter on an arm64 machine with 16 Gbytes of
RAM equally split between two nodes, there will be ``ZONE_DMA32``,
``ZONE_NORMAL`` and ``ZONE_MOVABLE`` on node 0, and ``ZONE_NORMAL`` and
``ZONE_MOVABLE`` on node 1::
1G 9G 17G
+--------------------------------+ +--------------------------+
| node 0 | | node 1 |
+--------------------------------+ +--------------------------+
1G 4G 4200M 9G 9320M 17G
+---------+----------+-----------+ +------------+-------------+
| DMA32 | NORMAL | MOVABLE | | NORMAL | MOVABLE |
+---------+----------+-----------+ +------------+-------------+
Memory banks may belong to interleaving nodes. In the example below an x86
machine has 16 Gbytes of RAM in 4 memory banks, even banks belong to node 0
and odd banks belong to node 1::
0 4G 8G 12G 16G
+-------------+ +-------------+ +-------------+ +-------------+
| node 0 | | node 1 | | node 0 | | node 1 |
+-------------+ +-------------+ +-------------+ +-------------+
0 16M 4G
+-----+-------+ +-------------+ +-------------+ +-------------+
| DMA | DMA32 | | NORMAL | | NORMAL | | NORMAL |
+-----+-------+ +-------------+ +-------------+ +-------------+
In this case node 0 will span from 0 to 12 Gbytes and node 1 will span from
4 to 16 Gbytes.
.. _nodes:
Nodes
=====
As we have mentioned, each node in memory is described by a ``pg_data_t`` which
is a typedef for a ``struct pglist_data``. When allocating a page, by default
Linux uses a node-local allocation policy to allocate memory from the node
closest to the running CPU. As processes tend to run on the same CPU, it is
likely the memory from the current node will be used. The allocation policy can
be controlled by users as described in
Documentation/admin-guide/mm/numa_memory_policy.rst.
Most NUMA architectures maintain an array of pointers to the node
structures. The actual structures are allocated early during boot when
architecture specific code parses the physical memory map reported by the
firmware. The bulk of the node initialization happens slightly later in the
boot process by free_area_init() function, described later in Section
:ref:`Initialization <initialization>`.
Along with the node structures, kernel maintains an array of ``nodemask_t``
bitmasks called ``node_states``. Each bitmask in this array represents a set of
nodes with particular properties as defined by ``enum node_states``:
``N_POSSIBLE``
The node could become online at some point.
``N_ONLINE``
The node is online.
``N_NORMAL_MEMORY``
The node has regular memory.
``N_HIGH_MEMORY``
The node has regular or high memory. When ``CONFIG_HIGHMEM`` is disabled
aliased to ``N_NORMAL_MEMORY``.
``N_MEMORY``
The node has memory(regular, high, movable)
``N_CPU``
The node has one or more CPUs
``N_GENERIC_INITIATOR``
The node has one or more Generic Initiators
For each node that has a property described above, the bit corresponding to the
node ID in the ``node_states[<property>]`` bitmask is set.
For example, for node 2 with normal memory and CPUs, bit 2 will be set in ::
node_states[N_POSSIBLE]
node_states[N_ONLINE]
node_states[N_NORMAL_MEMORY]
node_states[N_HIGH_MEMORY]
node_states[N_MEMORY]
node_states[N_CPU]
For various operations possible with nodemasks please refer to
``include/linux/nodemask.h``.
Among other things, nodemasks are used to provide macros for node traversal,
namely ``for_each_node()`` and ``for_each_online_node()``.
For instance, to call a function foo() for each online node::
for_each_online_node(nid) {
pg_data_t *pgdat = NODE_DATA(nid);
foo(pgdat);
}
Node structure
--------------
The nodes structure ``struct pglist_data`` is declared in
``include/linux/mmzone.h``. Here we briefly describe fields of this
structure:
General
~~~~~~~
``node_zones``
The zones for this node. Not all of the zones may be populated, but it is
the full list. It is referenced by this node's node_zonelists as well as
other node's node_zonelists.
``node_zonelists``
The list of all zones in all nodes. This list defines the order of zones
that allocations are preferred from. The ``node_zonelists`` is set up by
``build_zonelists()`` in ``mm/page_alloc.c`` during the initialization of
core memory management structures.
``nr_zones``
Number of populated zones in this node.
``node_mem_map``
For UMA systems that use FLATMEM memory model the 0's node
``node_mem_map`` is array of struct pages representing each physical frame.
``node_page_ext``
For UMA systems that use FLATMEM memory model the 0's node
``node_page_ext`` is array of extensions of struct pages. Available only
in the kernels built with ``CONFIG_PAGE_EXTENSION`` enabled.
``node_start_pfn``
The page frame number of the starting page frame in this node.
``node_present_pages``
Total number of physical pages present in this node.
``node_spanned_pages``
Total size of physical page range, including holes.
``node_size_lock``
A lock that protects the fields defining the node extents. Only defined when
at least one of ``CONFIG_MEMORY_HOTPLUG`` or
``CONFIG_DEFERRED_STRUCT_PAGE_INIT`` configuration options are enabled.
``pgdat_resize_lock()`` and ``pgdat_resize_unlock()`` are provided to
manipulate ``node_size_lock`` without checking for ``CONFIG_MEMORY_HOTPLUG``
or ``CONFIG_DEFERRED_STRUCT_PAGE_INIT``.
``node_id``
The Node ID (NID) of the node, starts at 0.
``totalreserve_pages``
This is a per-node reserve of pages that are not available to userspace
allocations.
``first_deferred_pfn``
If memory initialization on large machines is deferred then this is the first
PFN that needs to be initialized. Defined only when
``CONFIG_DEFERRED_STRUCT_PAGE_INIT`` is enabled
``deferred_split_queue``
Per-node queue of huge pages that their split was deferred. Defined only when ``CONFIG_TRANSPARENT_HUGEPAGE`` is enabled.
``__lruvec``
Per-node lruvec holding LRU lists and related parameters. Used only when
memory cgroups are disabled. It should not be accessed directly, use
``mem_cgroup_lruvec()`` to look up lruvecs instead.
Reclaim control
~~~~~~~~~~~~~~~
See also Documentation/mm/page_reclaim.rst.
``kswapd``
Per-node instance of kswapd kernel thread.
``kswapd_wait``, ``pfmemalloc_wait``, ``reclaim_wait``
Workqueues used to synchronize memory reclaim tasks
``nr_writeback_throttled``
Number of tasks that are throttled waiting on dirty pages to clean.
``nr_reclaim_start``
Number of pages written while reclaim is throttled waiting for writeback.
``kswapd_order``
Controls the order kswapd tries to reclaim
``kswapd_highest_zoneidx``
The highest zone index to be reclaimed by kswapd
``kswapd_failures``
Number of runs kswapd was unable to reclaim any pages
``min_unmapped_pages``
Minimal number of unmapped file backed pages that cannot be reclaimed.
Determined by ``vm.min_unmapped_ratio`` sysctl. Only defined when
``CONFIG_NUMA`` is enabled.
``min_slab_pages``
Minimal number of SLAB pages that cannot be reclaimed. Determined by
``vm.min_slab_ratio sysctl``. Only defined when ``CONFIG_NUMA`` is enabled
``flags``
Flags controlling reclaim behavior.
Compaction control
~~~~~~~~~~~~~~~~~~
``kcompactd_max_order``
Page order that kcompactd should try to achieve.
``kcompactd_highest_zoneidx``
The highest zone index to be compacted by kcompactd.
``kcompactd_wait``
Workqueue used to synchronize memory compaction tasks.
``kcompactd``
Per-node instance of kcompactd kernel thread.
``proactive_compact_trigger``
Determines if proactive compaction is enabled. Controlled by
``vm.compaction_proactiveness`` sysctl.
Statistics
~~~~~~~~~~
``per_cpu_nodestats``
Per-CPU VM statistics for the node
``vm_stat``
VM statistics for the node.
.. _zones:
Zones
=====
As we have mentioned, each zone in memory is described by a ``struct zone``
which is an element of the ``node_zones`` array of the node it belongs to.
``struct zone`` is the core data structure of the page allocator. A zone
represents a range of physical memory and may have holes.
The page allocator uses the GFP flags, see :ref:`mm-api-gfp-flags`, specified by
a memory allocation to determine the highest zone in a node from which the
memory allocation can allocate memory. The page allocator first allocates memory
from that zone, if the page allocator can't allocate the requested amount of
memory from the zone, it will allocate memory from the next lower zone in the
node, the process continues up to and including the lowest zone. For example, if
a node contains ``ZONE_DMA32``, ``ZONE_NORMAL`` and ``ZONE_MOVABLE`` and the
highest zone of a memory allocation is ``ZONE_MOVABLE``, the order of the zones
from which the page allocator allocates memory is ``ZONE_MOVABLE`` >
``ZONE_NORMAL`` > ``ZONE_DMA32``.
At runtime, free pages in a zone are in the Per-CPU Pagesets (PCP) or free areas
of the zone. The Per-CPU Pagesets are a vital mechanism in the kernel's memory
management system. By handling most frequent allocations and frees locally on
each CPU, the Per-CPU Pagesets improve performance and scalability, especially
on systems with many cores. The page allocator in the kernel employs a two-step
strategy for memory allocation, starting with the Per-CPU Pagesets before
falling back to the buddy allocator. Pages are transferred between the Per-CPU
Pagesets and the global free areas (managed by the buddy allocator) in batches.
This minimizes the overhead of frequent interactions with the global buddy
allocator.
Architecture specific code calls free_area_init() to initializes zones.
Zone structure
--------------
The zones structure ``struct zone`` is defined in ``include/linux/mmzone.h``.
Here we briefly describe fields of this structure:
General
~~~~~~~
``_watermark``
The watermarks for this zone. When the amount of free pages in a zone is below
the min watermark, boosting is ignored, an allocation may trigger direct
reclaim and direct compaction, it is also used to throttle direct reclaim.
When the amount of free pages in a zone is below the low watermark, kswapd is
woken up. When the amount of free pages in a zone is above the high watermark,
kswapd stops reclaiming (a zone is balanced) when the
``NUMA_BALANCING_MEMORY_TIERING`` bit of ``sysctl_numa_balancing_mode`` is not
set. The promo watermark is used for memory tiering and NUMA balancing. When
the amount of free pages in a zone is above the promo watermark, kswapd stops
reclaiming when the ``NUMA_BALANCING_MEMORY_TIERING`` bit of
``sysctl_numa_balancing_mode`` is set. The watermarks are set by
``__setup_per_zone_wmarks()``. The min watermark is calculated according to
``vm.min_free_kbytes`` sysctl. The other three watermarks are set according
to the distance between two watermarks. The distance itself is calculated
taking ``vm.watermark_scale_factor`` sysctl into account.
``watermark_boost``
The number of pages which are used to boost watermarks to increase reclaim
pressure to reduce the likelihood of future fallbacks and wake kswapd now
as the node may be balanced overall and kswapd will not wake naturally.
``nr_reserved_highatomic``
The number of pages which are reserved for high-order atomic allocations.
``nr_free_highatomic``
The number of free pages in reserved highatomic pageblocks
``lowmem_reserve``
The array of the amounts of the memory reserved in this zone for memory
allocations. For example, if the highest zone a memory allocation can
allocate memory from is ``ZONE_MOVABLE``, the amount of memory reserved in
this zone for this allocation is ``lowmem_reserve[ZONE_MOVABLE]`` when
attempting to allocate memory from this zone. This is a mechanism the page
allocator uses to prevent allocations which could use ``highmem`` from using
too much ``lowmem``. For some specialised workloads on ``highmem`` machines,
it is dangerous for the kernel to allow process memory to be allocated from
the ``lowmem`` zone. This is because that memory could then be pinned via the
``mlock()`` system call, or by unavailability of swapspace.
``vm.lowmem_reserve_ratio`` sysctl determines how aggressive the kernel is in
defending these lower zones. This array is recalculated by
``setup_per_zone_lowmem_reserve()`` at runtime if ``vm.lowmem_reserve_ratio``
sysctl changes.
``node``
The index of the node this zone belongs to. Available only when
``CONFIG_NUMA`` is enabled because there is only one zone in a UMA system.
``zone_pgdat``
Pointer to the ``struct pglist_data`` of the node this zone belongs to.
``per_cpu_pageset``
Pointer to the Per-CPU Pagesets (PCP) allocated and initialized by
``setup_zone_pageset()``. By handling most frequent allocations and frees
locally on each CPU, PCP improves performance and scalability on systems with
many cores.
``pageset_high_min``
Copied to the ``high_min`` of the Per-CPU Pagesets for faster access.
``pageset_high_max``
Copied to the ``high_max`` of the Per-CPU Pagesets for faster access.
``pageset_batch``
Copied to the ``batch`` of the Per-CPU Pagesets for faster access. The
``batch``, ``high_min`` and ``high_max`` of the Per-CPU Pagesets are used to
calculate the number of elements the Per-CPU Pagesets obtain from the buddy
allocator under a single hold of the lock for efficiency. They are also used
to decide if the Per-CPU Pagesets return pages to the buddy allocator in page
free process.
``pageblock_flags``
The pointer to the flags for the pageblocks in the zone (see
``include/linux/pageblock-flags.h`` for flags list). The memory is allocated
in ``setup_usemap()``. Each pageblock occupies ``NR_PAGEBLOCK_BITS`` bits.
Defined only when ``CONFIG_FLATMEM`` is enabled. The flags is stored in
``mem_section`` when ``CONFIG_SPARSEMEM`` is enabled.
``zone_start_pfn``
The start pfn of the zone. It is initialized by
``calculate_node_totalpages()``.
``managed_pages``
The present pages managed by the buddy system, which is calculated as:
``managed_pages`` = ``present_pages`` - ``reserved_pages``, ``reserved_pages``
includes pages allocated by the memblock allocator. It should be used by page
allocator and vm scanner to calculate all kinds of watermarks and thresholds.
It is accessed using ``atomic_long_xxx()`` functions. It is initialized in
``free_area_init_core()`` and then is reinitialized when memblock allocator
frees pages into buddy system.
``spanned_pages``
The total pages spanned by the zone, including holes, which is calculated as:
``spanned_pages`` = ``zone_end_pfn`` - ``zone_start_pfn``. It is initialized
by ``calculate_node_totalpages()``.
``present_pages``
The physical pages existing within the zone, which is calculated as:
``present_pages`` = ``spanned_pages`` - ``absent_pages`` (pages in holes). It
may be used by memory hotplug or memory power management logic to figure out
unmanaged pages by checking (``present_pages`` - ``managed_pages``). Write
access to ``present_pages`` at runtime should be protected by
``mem_hotplug_begin/done()``. Any reader who can't tolerant drift of
``present_pages`` should use ``get_online_mems()`` to get a stable value. It
is initialized by ``calculate_node_totalpages()``.
``present_early_pages``
The present pages existing within the zone located on memory available since
early boot, excluding hotplugged memory. Defined only when
``CONFIG_MEMORY_HOTPLUG`` is enabled and initialized by
``calculate_node_totalpages()``.
``cma_pages``
The pages reserved for CMA use. These pages behave like ``ZONE_MOVABLE`` when
they are not used for CMA. Defined only when ``CONFIG_CMA`` is enabled.
``name``
The name of the zone. It is a pointer to the corresponding element of
the ``zone_names`` array.
``nr_isolate_pageblock``
Number of isolated pageblocks. It is used to solve incorrect freepage counting
problem due to racy retrieving migratetype of pageblock. Protected by
``zone->lock``. Defined only when ``CONFIG_MEMORY_ISOLATION`` is enabled.
``span_seqlock``
The seqlock to protect ``zone_start_pfn`` and ``spanned_pages``. It is a
seqlock because it has to be read outside of ``zone->lock``, and it is done in
the main allocator path. However, the seqlock is written quite infrequently.
Defined only when ``CONFIG_MEMORY_HOTPLUG`` is enabled.
``initialized``
The flag indicating if the zone is initialized. Set by
``init_currently_empty_zone()`` during boot.
``free_area``
The array of free areas, where each element corresponds to a specific order
which is a power of two. The buddy allocator uses this structure to manage
free memory efficiently. When allocating, it tries to find the smallest
sufficient block, if the smallest sufficient block is larger than the
requested size, it will be recursively split into the next smaller blocks
until the required size is reached. When a page is freed, it may be merged
with its buddy to form a larger block. It is initialized by
``zone_init_free_lists()``.
``unaccepted_pages``
The list of pages to be accepted. All pages on the list are ``MAX_PAGE_ORDER``.
Defined only when ``CONFIG_UNACCEPTED_MEMORY`` is enabled.
``flags``
The zone flags. The least three bits are used and defined by
``enum zone_flags``. ``ZONE_BOOSTED_WATERMARK`` (bit 0): zone recently boosted
watermarks. Cleared when kswapd is woken. ``ZONE_RECLAIM_ACTIVE`` (bit 1):
kswapd may be scanning the zone. ``ZONE_BELOW_HIGH`` (bit 2): zone is below
high watermark.
``lock``
The main lock that protects the internal data structures of the page allocator
specific to the zone, especially protects ``free_area``.
``percpu_drift_mark``
When free pages are below this point, additional steps are taken when reading
the number of free pages to avoid per-cpu counter drift allowing watermarks
to be breached. It is updated in ``refresh_zone_stat_thresholds()``.
Compaction control
~~~~~~~~~~~~~~~~~~
``compact_cached_free_pfn``
The PFN where compaction free scanner should start in the next scan.
``compact_cached_migrate_pfn``
The PFNs where compaction migration scanner should start in the next scan.
This array has two elements: the first one is used in ``MIGRATE_ASYNC`` mode,
and the other one is used in ``MIGRATE_SYNC`` mode.
``compact_init_migrate_pfn``
The initial migration PFN which is initialized to 0 at boot time, and to the
first pageblock with migratable pages in the zone after a full compaction
finishes. It is used to check if a scan is a whole zone scan or not.
``compact_init_free_pfn``
The initial free PFN which is initialized to 0 at boot time and to the last
pageblock with free ``MIGRATE_MOVABLE`` pages in the zone. It is used to check
if it is the start of a scan.
``compact_considered``
The number of compactions attempted since last failure. It is reset in
``defer_compaction()`` when a compaction fails to result in a page allocation
success. It is increased by 1 in ``compaction_deferred()`` when a compaction
should be skipped. ``compaction_deferred()`` is called before
``compact_zone()`` is called, ``compaction_defer_reset()`` is called when
``compact_zone()`` returns ``COMPACT_SUCCESS``, ``defer_compaction()`` is
called when ``compact_zone()`` returns ``COMPACT_PARTIAL_SKIPPED`` or
``COMPACT_COMPLETE``.
``compact_defer_shift``
The number of compactions skipped before trying again is
``1<<compact_defer_shift``. It is increased by 1 in ``defer_compaction()``.
It is reset in ``compaction_defer_reset()`` when a direct compaction results
in a page allocation success. Its maximum value is ``COMPACT_MAX_DEFER_SHIFT``.
``compact_order_failed``
The minimum compaction failed order. It is set in ``compaction_defer_reset()``
when a compaction succeeds and in ``defer_compaction()`` when a compaction
fails to result in a page allocation success.
``compact_blockskip_flush``
Set to true when compaction migration scanner and free scanner meet, which
means the ``PB_compact_skip`` bits should be cleared.
``contiguous``
Set to true when the zone is contiguous (in other words, no hole).
Statistics
~~~~~~~~~~
``vm_stat``
VM statistics for the zone. The items tracked are defined by
``enum zone_stat_item``.
``vm_numa_event``
VM NUMA event statistics for the zone. The items tracked are defined by
``enum numa_stat_item``.
``per_cpu_zonestats``
Per-CPU VM statistics for the zone. It records VM statistics and VM NUMA event
statistics on a per-CPU basis. It reduces updates to the global ``vm_stat``
and ``vm_numa_event`` fields of the zone to improve performance.
.. _pages:
Pages
=====
.. admonition:: Stub
This section is incomplete. Please list and describe the appropriate fields.
.. _folios:
Folios
======
.. admonition:: Stub
This section is incomplete. Please list and describe the appropriate fields.
.. _initialization:
Initialization
==============
.. admonition:: Stub
This section is incomplete. Please list and describe the appropriate fields.
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
Physical-memory abstraction과 NUMA node
1-30Linux는 매우 다양한 architecture에서 동작하므로 physical memory를 표현하는 architecture-independent abstraction이 필요합니다. 이 장은 실행 중인 system에서 physical memory를 관리하는 자료 구조를 설명합니다.
Memory management의 첫 핵심 개념은 `Non-Uniform Memory Access (NUMA)`입니다. Multi-core·multi-socket machine에서는 processor와의 `distance`에 따라 접근 비용이 다른 여러 bank로 memory를 구성할 수 있습니다. CPU마다 memory bank가 있거나 peripheral device 가까이에 DMA에 매우 적합한 bank가 있을 수 있습니다.
각 bank를 node라고 하며, architecture가 UMA이더라도 Linux에서는 `struct pglist_data`로 표현합니다. 이 구조는 항상 typedef인 `pg_data_t`로 참조합니다. 특정 node의 `pg_data_t`는 node ID `nid`를 받는 `NODE_DATA(nid)` macro로 참조할 수 있습니다.
NUMA architecture에서는 boot 초기 architecture-specific code가 node structure를 할당합니다. 보통 각 structure는 자신이 나타내는 memory bank에 local하게 할당됩니다. UMA architecture는 `contig_page_data`라는 static `pg_data_t` 하나만 사용합니다. Node에 관한 자세한 내용은 뒤의 `Nodes` section에서 설명합니다.
.. SPDX-License-Identifier: GPL-2.0
===============
Physical Memory
===============
Linux is available for a wide range of architectures so there is a need for an
architecture-independent abstraction to represent the physical memory. This
chapter describes the structures used to manage physical memory in a running
system.
The first principal concept prevalent in the memory management is
`Non-Uniform Memory Access (NUMA)
<https://en.wikipedia.org/wiki/Non-uniform_memory_access>`_.
With multi-core and multi-socket machines, memory may be arranged into banks
that incur a different cost to access depending on the “distance” from the
processor. For example, there might be a bank of memory assigned to each CPU or
a bank of memory very suitable for DMA near peripheral devices.
Each bank is called a node and the concept is represented under Linux by a
``struct pglist_data`` even if the architecture is UMA. This structure is
always referenced by its typedef ``pg_data_t``. A ``pg_data_t`` structure
for a particular node can be referenced by ``NODE_DATA(nid)`` macro where
``nid`` is the ID of that node.
For NUMA architectures, the node structures are allocated by the architecture
specific code early during boot. Usually, these structures are allocated
locally on the memory bank they represent. For UMA architectures, only one
static ``pg_data_t`` structure called ``contig_page_data`` is used. Nodes will
be discussed further in Section :ref:`Nodes <nodes>`
Physical address space와 zone 유형
31-80전체 physical-address space는 memory 안의 range를 나타내는 zone 하나 이상으로 나뉩니다. Range는 보통 physical memory 접근에 관한 architecture 제약으로 결정됩니다. Node 안에서 특정 zone에 해당하는 memory range는 `struct zone`이 설명합니다.
- `ZONE_DMA`와 `ZONE_DMA32`: 주소 지정 가능한 memory 전체에 접근하지 못하는 peripheral device의 DMA에 알맞은 memory를 역사적으로 나타냈습니다. 현재는 DMA 요구에 맞는 memory를 얻는 더 견고한 interface가 있으며 `Documentation/core-api/dma-api.rst`에 설명되어 있습니다. 그래도 두 zone은 접근 방식에 제약이 있는 memory range를 계속 나타냅니다. Architecture에 따라 `CONFIG_ZONE_DMA`, `CONFIG_ZONE_DMA32`로 둘 중 하나 또는 둘 다 build 때 disable할 수 있습니다. DMA address 한계가 다른 peripheral을 지원하는 일부 64bit platform은 두 zone이 모두 필요할 수 있습니다.
- `ZONE_NORMAL`: Kernel이 항상 접근할 수 있는 일반 memory입니다. DMA device가 주소 지정 가능한 memory 전체로 transfer할 수 있다면 이 zone page에도 DMA operation을 수행할 수 있습니다. 항상 enable됩니다.
- `ZONE_HIGHMEM`: Kernel page table에 permanent mapping이 없는 physical memory 부분입니다. Kernel은 temporary mapping을 통해서만 이 zone에 접근합니다. 일부 32bit architecture에서만 사용할 수 있고 `CONFIG_HIGHMEM`으로 enable합니다.
- `ZONE_MOVABLE`: `ZONE_NORMAL`처럼 정상적으로 접근할 수 있는 memory입니다. 차이는 page 대부분의 content를 이동할 수 있다는 점입니다. Virtual address는 바뀌지 않지만 content가 다른 physical page로 이동할 수 있습니다. Memory hotplug 때 채우는 경우가 많고, boot 때 `kernelcore`, `movablecore`, `movable_node` kernel command-line parameter로 채울 수도 있습니다. `Documentation/mm/page_migration.rst`와 `Documentation/admin-guide/mm/memory-hotplug.rst`를 참조하십시오.
- `ZONE_DEVICE`: PMEM이나 GPU 같은 device에 있는 memory를 나타냅니다. RAM zone과 특성이 다르며, device driver가 지정한 physical-address range에 `struct page`와 memory-map service를 제공하려고 존재합니다. `CONFIG_ZONE_DEVICE`로 enable합니다.
많은 kernel operation은 `ZONE_NORMAL`에서만 수행할 수 있으므로 가장 성능에 민감한 zone입니다. Node와 zone extent의 관계는 firmware가 보고한 physical-memory map, memory addressing architecture 제약, 특정 kernel command-line parameter로 결정됩니다.
The entire physical address space is partitioned into one or more blocks
called zones which represent ranges within memory. These ranges are usually
determined by architectural constraints for accessing the physical memory.
The memory range within a node that corresponds to a particular zone is
described by a ``struct zone``. Each zone has
one of the types described below.
* ``ZONE_DMA`` and ``ZONE_DMA32`` historically represented memory suitable for
DMA by peripheral devices that cannot access all of the addressable
memory. For many years there are better more and robust interfaces to get
memory with DMA specific requirements (Documentation/core-api/dma-api.rst),
but ``ZONE_DMA`` and ``ZONE_DMA32`` still represent memory ranges that have
restrictions on how they can be accessed.
Depending on the architecture, either of these zone types or even they both
can be disabled at build time using ``CONFIG_ZONE_DMA`` and
``CONFIG_ZONE_DMA32`` configuration options. Some 64-bit platforms may need
both zones as they support peripherals with different DMA addressing
limitations.
* ``ZONE_NORMAL`` is for normal memory that can be accessed by the kernel all
the time. DMA operations can be performed on pages in this zone if the DMA
devices support transfers to all addressable memory. ``ZONE_NORMAL`` is
always enabled.
* ``ZONE_HIGHMEM`` is the part of the physical memory that is not covered by a
permanent mapping in the kernel page tables. The memory in this zone is only
accessible to the kernel using temporary mappings. This zone is available
only on some 32-bit architectures and is enabled with ``CONFIG_HIGHMEM``.
* ``ZONE_MOVABLE`` is for normal accessible memory, just like ``ZONE_NORMAL``.
The difference is that the contents of most pages in ``ZONE_MOVABLE`` is
movable. That means that while virtual addresses of these pages do not
change, their content may move between different physical pages. Often
``ZONE_MOVABLE`` is populated during memory hotplug, but it may be
also populated on boot using one of ``kernelcore``, ``movablecore`` and
``movable_node`` kernel command line parameters. See
Documentation/mm/page_migration.rst and
Documentation/admin-guide/mm/memory-hotplug.rst for additional details.
* ``ZONE_DEVICE`` represents memory residing on devices such as PMEM and GPU.
It has different characteristics than RAM zone types and it exists to provide
:ref:`struct page <Pages>` and memory map services for device driver
identified physical address ranges. ``ZONE_DEVICE`` is enabled with
configuration option ``CONFIG_ZONE_DEVICE``.
It is important to note that many kernel operations can only take place using
``ZONE_NORMAL`` so it is the most performance critical zone. Zones are
discussed further in Section :ref:`Zones <zones>`.
Node와 zone extent 예제
81-135첫 예제는 RAM 2GB인 x86 UMA machine의 32bit kernel입니다. Memory 전체가 node 0에 있으며 `ZONE_DMA`, `ZONE_NORMAL`, `ZONE_HIGHMEM` 세 zone으로 나뉩니다. 주소 0~16MB는 DMA, 16~896MB는 NORMAL, 896MB~2GB는 HIGHMEM입니다.
두 번째 예제는 RAM 16GB가 node 두 개에 똑같이 나뉜 arm64 machine입니다. Kernel은 `ZONE_DMA` 없이 `ZONE_DMA32`를 enable했고 `movablecore=80%`로 boot했습니다. Node 0에는 `ZONE_DMA32`, `ZONE_NORMAL`, `ZONE_MOVABLE`이 있고 node 1에는 `ZONE_NORMAL`, `ZONE_MOVABLE`이 있습니다. 원문 주소 표기는 1GB에서 17GB 범위입니다.
세 번째 예제처럼 memory bank가 interleaving node에 속할 수도 있습니다. RAM 16GB를 4GB bank 네 개로 나눈 x86 machine에서 짝수 bank는 node 0, 홀수 bank는 node 1에 속합니다. 이 경우 node 0의 span은 0~12GB이고 node 1의 span은 4~16GB입니다. Span에는 중간 hole 또는 다른 node 소유 range가 포함될 수 있습니다.
The relation between node and zone extents is determined by the physical memory
map reported by the firmware, architectural constraints for memory addressing
and certain parameters in the kernel command line.
For example, with 32-bit kernel on an x86 UMA machine with 2 Gbytes of RAM the
entire memory will be on node 0 and there will be three zones: ``ZONE_DMA``,
``ZONE_NORMAL`` and ``ZONE_HIGHMEM``::
0 2G
+-------------------------------------------------------------+
| node 0 |
+-------------------------------------------------------------+
0 16M 896M 2G
+----------+-----------------------+--------------------------+
| ZONE_DMA | ZONE_NORMAL | ZONE_HIGHMEM |
+----------+-----------------------+--------------------------+
With a kernel built with ``ZONE_DMA`` disabled and ``ZONE_DMA32`` enabled and
booted with ``movablecore=80%`` parameter on an arm64 machine with 16 Gbytes of
RAM equally split between two nodes, there will be ``ZONE_DMA32``,
``ZONE_NORMAL`` and ``ZONE_MOVABLE`` on node 0, and ``ZONE_NORMAL`` and
``ZONE_MOVABLE`` on node 1::
1G 9G 17G
+--------------------------------+ +--------------------------+
| node 0 | | node 1 |
+--------------------------------+ +--------------------------+
1G 4G 4200M 9G 9320M 17G
+---------+----------+-----------+ +------------+-------------+
| DMA32 | NORMAL | MOVABLE | | NORMAL | MOVABLE |
+---------+----------+-----------+ +------------+-------------+
Memory banks may belong to interleaving nodes. In the example below an x86
machine has 16 Gbytes of RAM in 4 memory banks, even banks belong to node 0
and odd banks belong to node 1::
0 4G 8G 12G 16G
+-------------+ +-------------+ +-------------+ +-------------+
| node 0 | | node 1 | | node 0 | | node 1 |
+-------------+ +-------------+ +-------------+ +-------------+
0 16M 4G
+-----+-------+ +-------------+ +-------------+ +-------------+
| DMA | DMA32 | | NORMAL | | NORMAL | | NORMAL |
+-----+-------+ +-------------+ +-------------+ +-------------+
In this case node 0 will span from 0 to 12 Gbytes and node 1 will span from
4 to 16 Gbytes.
Node allocation policy와 node_states
136-202각 memory node는 `struct pglist_data`의 typedef인 `pg_data_t`로 설명합니다. Page를 할당할 때 Linux는 기본적으로 실행 CPU와 가장 가까운 node에서 memory를 얻는 node-local policy를 사용합니다. Process는 같은 CPU에서 계속 실행되는 경향이 있어 current node memory를 사용할 가능성이 큽니다. User는 `Documentation/admin-guide/mm/numa_memory_policy.rst`의 방법으로 allocation policy를 제어할 수 있습니다.
대부분의 NUMA architecture는 node-structure pointer array를 유지합니다. Architecture-specific code가 firmware physical-memory map을 parse하는 boot 초기에 실제 structure를 할당합니다. Node initialization 대부분은 조금 뒤 `free_area_init()`에서 수행하며 뒤의 `Initialization` section에서 언급합니다.
Kernel은 node structure와 함께 `node_states`라는 `nodemask_t` bitmask array를 유지합니다. 각 bitmask는 `enum node_states`가 정의한 특정 속성을 가진 node set입니다.
- `N_POSSIBLE`: 언젠가 online이 될 수 있는 node입니다.
- `N_ONLINE`: 현재 online인 node입니다.
- `N_NORMAL_MEMORY`: regular memory가 있는 node입니다.
- `N_HIGH_MEMORY`: regular 또는 high memory가 있는 node입니다. `CONFIG_HIGHMEM`이 disable되면 `N_NORMAL_MEMORY`의 alias입니다.
- `N_MEMORY`: regular, high, movable 중 어떤 형태로든 memory가 있는 node입니다.
- `N_CPU`: CPU가 하나 이상 있는 node입니다.
- `N_GENERIC_INITIATOR`: Generic Initiator가 하나 이상 있는 node입니다.
위 속성을 가진 node마다 `node_states[<property>]` bitmask에서 node ID에 해당하는 bit를 set합니다. 예를 들어 normal memory와 CPU가 있는 node 2는 `N_POSSIBLE`, `N_ONLINE`, `N_NORMAL_MEMORY`, `N_HIGH_MEMORY`, `N_MEMORY`, `N_CPU` mask의 bit 2가 set됩니다.
Nodemask operation은 `include/linux/nodemask.h`를 참조하십시오. Nodemask는 `for_each_node()`와 `for_each_online_node()` 같은 node traversal macro를 제공하는 데도 사용합니다.
for_each_online_node(nid) {
pg_data_t *pgdat = NODE_DATA(nid);
foo(pgdat);
}
.. _nodes:
Nodes
=====
As we have mentioned, each node in memory is described by a ``pg_data_t`` which
is a typedef for a ``struct pglist_data``. When allocating a page, by default
Linux uses a node-local allocation policy to allocate memory from the node
closest to the running CPU. As processes tend to run on the same CPU, it is
likely the memory from the current node will be used. The allocation policy can
be controlled by users as described in
Documentation/admin-guide/mm/numa_memory_policy.rst.
Most NUMA architectures maintain an array of pointers to the node
structures. The actual structures are allocated early during boot when
architecture specific code parses the physical memory map reported by the
firmware. The bulk of the node initialization happens slightly later in the
boot process by free_area_init() function, described later in Section
:ref:`Initialization <initialization>`.
Along with the node structures, kernel maintains an array of ``nodemask_t``
bitmasks called ``node_states``. Each bitmask in this array represents a set of
nodes with particular properties as defined by ``enum node_states``:
``N_POSSIBLE``
The node could become online at some point.
``N_ONLINE``
The node is online.
``N_NORMAL_MEMORY``
The node has regular memory.
``N_HIGH_MEMORY``
The node has regular or high memory. When ``CONFIG_HIGHMEM`` is disabled
aliased to ``N_NORMAL_MEMORY``.
``N_MEMORY``
The node has memory(regular, high, movable)
``N_CPU``
The node has one or more CPUs
``N_GENERIC_INITIATOR``
The node has one or more Generic Initiators
For each node that has a property described above, the bit corresponding to the
node ID in the ``node_states[<property>]`` bitmask is set.
For example, for node 2 with normal memory and CPUs, bit 2 will be set in ::
node_states[N_POSSIBLE]
node_states[N_ONLINE]
node_states[N_NORMAL_MEMORY]
node_states[N_HIGH_MEMORY]
node_states[N_MEMORY]
node_states[N_CPU]
For various operations possible with nodemasks please refer to
``include/linux/nodemask.h``.
Among other things, nodemasks are used to provide macros for node traversal,
namely ``for_each_node()`` and ``for_each_online_node()``.
For instance, to call a function foo() for each online node::
for_each_online_node(nid) {
pg_data_t *pgdat = NODE_DATA(nid);
foo(pgdat);
}
struct pglist_data의 일반 field
203-272Node structure `struct pglist_data`는 `include/linux/mmzone.h`에 선언되어 있습니다. 일반 field는 다음과 같습니다.
- `node_zones`: 이 node의 zone 전체 목록입니다. 모든 zone이 populated되지는 않을 수 있습니다. 이 node와 다른 node의 `node_zonelists`가 참조합니다.
- `node_zonelists`: 모든 node의 모든 zone 목록입니다. Allocation이 선호할 zone 순서를 정합니다. Core memory-management structure 초기화 때 `mm/page_alloc.c`의 `build_zonelists()`가 설정합니다.
- `nr_zones`: 이 node에서 populated된 zone 수입니다.
- `node_mem_map`: FLATMEM memory model을 쓰는 UMA system에서 node 0의 physical frame 각각을 나타내는 `struct page` array입니다.
- `node_page_ext`: FLATMEM UMA system에서 node 0의 `struct page` extension array입니다. `CONFIG_PAGE_EXTENSION`을 enable한 kernel에서만 사용할 수 있습니다.
- `node_start_pfn`: 이 node 첫 page frame의 PFN입니다.
- `node_present_pages`: 이 node에 실제 존재하는 physical page 총수입니다.
- `node_spanned_pages`: hole을 포함한 physical-page range 전체 크기입니다.
- `node_size_lock`: node extent를 정의하는 field를 보호합니다. `CONFIG_MEMORY_HOTPLUG` 또는 `CONFIG_DEFERRED_STRUCT_PAGE_INIT` 중 하나 이상을 enable했을 때만 정의됩니다. 두 config를 직접 검사하지 않고 lock을 다루도록 `pgdat_resize_lock()`과 `pgdat_resize_unlock()`을 제공합니다.
- `node_id`: 0부터 시작하는 node ID, 즉 NID입니다.
- `totalreserve_pages`: userspace allocation이 사용할 수 없는 node별 reserve page 수입니다.
- `first_deferred_pfn`: 큰 machine에서 memory initialization을 미룰 때 앞으로 초기화해야 하는 첫 PFN입니다. `CONFIG_DEFERRED_STRUCT_PAGE_INIT`에서만 정의됩니다.
- `deferred_split_queue`: split이 연기된 huge page의 node별 queue입니다. `CONFIG_TRANSPARENT_HUGEPAGE`에서만 정의됩니다.
- `__lruvec`: LRU list와 관련 parameter를 담는 node별 lruvec입니다. Memory cgroup이 disable됐을 때만 사용합니다. 직접 접근하지 말고 `mem_cgroup_lruvec()`로 lruvec을 찾아야 합니다.
Node structure
--------------
The nodes structure ``struct pglist_data`` is declared in
``include/linux/mmzone.h``. Here we briefly describe fields of this
structure:
General
~~~~~~~
``node_zones``
The zones for this node. Not all of the zones may be populated, but it is
the full list. It is referenced by this node's node_zonelists as well as
other node's node_zonelists.
``node_zonelists``
The list of all zones in all nodes. This list defines the order of zones
that allocations are preferred from. The ``node_zonelists`` is set up by
``build_zonelists()`` in ``mm/page_alloc.c`` during the initialization of
core memory management structures.
``nr_zones``
Number of populated zones in this node.
``node_mem_map``
For UMA systems that use FLATMEM memory model the 0's node
``node_mem_map`` is array of struct pages representing each physical frame.
``node_page_ext``
For UMA systems that use FLATMEM memory model the 0's node
``node_page_ext`` is array of extensions of struct pages. Available only
in the kernels built with ``CONFIG_PAGE_EXTENSION`` enabled.
``node_start_pfn``
The page frame number of the starting page frame in this node.
``node_present_pages``
Total number of physical pages present in this node.
``node_spanned_pages``
Total size of physical page range, including holes.
``node_size_lock``
A lock that protects the fields defining the node extents. Only defined when
at least one of ``CONFIG_MEMORY_HOTPLUG`` or
``CONFIG_DEFERRED_STRUCT_PAGE_INIT`` configuration options are enabled.
``pgdat_resize_lock()`` and ``pgdat_resize_unlock()`` are provided to
manipulate ``node_size_lock`` without checking for ``CONFIG_MEMORY_HOTPLUG``
or ``CONFIG_DEFERRED_STRUCT_PAGE_INIT``.
``node_id``
The Node ID (NID) of the node, starts at 0.
``totalreserve_pages``
This is a per-node reserve of pages that are not available to userspace
allocations.
``first_deferred_pfn``
If memory initialization on large machines is deferred then this is the first
PFN that needs to be initialized. Defined only when
``CONFIG_DEFERRED_STRUCT_PAGE_INIT`` is enabled
``deferred_split_queue``
Per-node queue of huge pages that their split was deferred. Defined only when ``CONFIG_TRANSPARENT_HUGEPAGE`` is enabled.
``__lruvec``
Per-node lruvec holding LRU lists and related parameters. Used only when
memory cgroups are disabled. It should not be accessed directly, use
``mem_cgroup_lruvec()`` to look up lruvecs instead.
Node reclaim·compaction·통계 field
273-329Reclaim control은 `Documentation/mm/page_reclaim.rst`도 참조하십시오.
- `kswapd`: node별 kswapd kernel-thread instance입니다.
- `kswapd_wait`, `pfmemalloc_wait`, `reclaim_wait`: memory-reclaim task를 동기화하는 workqueue입니다.
- `nr_writeback_throttled`: dirty page가 clean되기를 기다리며 throttle된 task 수입니다.
- `nr_reclaim_start`: reclaim이 writeback을 기다리며 throttle된 동안 write된 page 수입니다.
- `kswapd_order`: kswapd가 reclaim하려는 order를 제어합니다.
- `kswapd_highest_zoneidx`: kswapd가 reclaim할 가장 높은 zone index입니다.
- `kswapd_failures`: kswapd가 page를 하나도 reclaim하지 못한 실행 횟수입니다.
- `min_unmapped_pages`: reclaim할 수 없도록 남겨 둘 최소 unmapped file-backed page 수입니다. `vm.min_unmapped_ratio` sysctl이 정하며 `CONFIG_NUMA`에서만 정의됩니다.
- `min_slab_pages`: reclaim할 수 없도록 남겨 둘 최소 SLAB page 수입니다. `vm.min_slab_ratio` sysctl이 정하며 `CONFIG_NUMA`에서만 정의됩니다.
- `flags`: reclaim 동작을 제어하는 flag입니다.
Node compaction control field는 다음과 같습니다.
- `kcompactd_max_order`: kcompactd가 달성하려 시도할 page order입니다.
- `kcompactd_highest_zoneidx`: kcompactd가 compact할 가장 높은 zone index입니다.
- `kcompactd_wait`: memory-compaction task를 동기화하는 workqueue입니다.
- `kcompactd`: node별 kcompactd kernel-thread instance입니다.
- `proactive_compact_trigger`: proactive compaction enable 여부를 정하며 `vm.compaction_proactiveness` sysctl로 제어합니다.
Reclaim control
~~~~~~~~~~~~~~~
See also Documentation/mm/page_reclaim.rst.
``kswapd``
Per-node instance of kswapd kernel thread.
``kswapd_wait``, ``pfmemalloc_wait``, ``reclaim_wait``
Workqueues used to synchronize memory reclaim tasks
``nr_writeback_throttled``
Number of tasks that are throttled waiting on dirty pages to clean.
``nr_reclaim_start``
Number of pages written while reclaim is throttled waiting for writeback.
``kswapd_order``
Controls the order kswapd tries to reclaim
``kswapd_highest_zoneidx``
The highest zone index to be reclaimed by kswapd
``kswapd_failures``
Number of runs kswapd was unable to reclaim any pages
``min_unmapped_pages``
Minimal number of unmapped file backed pages that cannot be reclaimed.
Determined by ``vm.min_unmapped_ratio`` sysctl. Only defined when
``CONFIG_NUMA`` is enabled.
``min_slab_pages``
Minimal number of SLAB pages that cannot be reclaimed. Determined by
``vm.min_slab_ratio sysctl``. Only defined when ``CONFIG_NUMA`` is enabled
``flags``
Flags controlling reclaim behavior.
Compaction control
~~~~~~~~~~~~~~~~~~
``kcompactd_max_order``
Page order that kcompactd should try to achieve.
``kcompactd_highest_zoneidx``
The highest zone index to be compacted by kcompactd.
``kcompactd_wait``
Workqueue used to synchronize memory compaction tasks.
``kcompactd``
Per-node instance of kcompactd kernel thread.
``proactive_compact_trigger``
Determines if proactive compaction is enabled. Controlled by
``vm.compaction_proactiveness`` sysctl.
Zone allocation 순서와 PCP
330-371`per_cpu_nodestats`는 node의 CPU별 VM statistic이고 `vm_stat`은 node의 VM statistic입니다.
각 memory zone은 자신이 속한 node의 `node_zones` array element인 `struct zone`으로 설명합니다. `struct zone`은 page allocator의 core data structure입니다. Zone은 physical-memory range를 나타내며 hole을 포함할 수 있습니다.
Page allocator는 allocation에 지정된 GFP flag를 보고 해당 node에서 사용할 수 있는 가장 높은 zone을 결정합니다. 먼저 그 zone에서 할당하고, 요청량을 얻지 못하면 node의 다음 낮은 zone으로 내려가 최하위 zone까지 계속합니다. 예를 들어 `ZONE_DMA32`, `ZONE_NORMAL`, `ZONE_MOVABLE`이 있고 최고 zone이 `ZONE_MOVABLE`이면 순서는 `ZONE_MOVABLE > ZONE_NORMAL > ZONE_DMA32`입니다.
Runtime에 zone의 free page는 Per-CPU Pageset, 즉 PCP 또는 zone free area에 있습니다. PCP는 잦은 allocation과 free 대부분을 각 CPU에서 local하게 처리해, 특히 core가 많은 system에서 성능과 확장성을 높입니다.
Kernel page allocator는 먼저 PCP를 사용하고 실패하면 buddy allocator로 fallback하는 2단계 전략을 씁니다. PCP와 buddy allocator가 관리하는 global free area 사이에서 page를 batch 단위로 옮겨 global buddy allocator와 잦게 상호작용하는 overhead를 줄입니다.
Architecture-specific code는 `free_area_init()`을 호출해 zone을 초기화합니다.
Statistics
~~~~~~~~~~
``per_cpu_nodestats``
Per-CPU VM statistics for the node
``vm_stat``
VM statistics for the node.
.. _zones:
Zones
=====
As we have mentioned, each zone in memory is described by a ``struct zone``
which is an element of the ``node_zones`` array of the node it belongs to.
``struct zone`` is the core data structure of the page allocator. A zone
represents a range of physical memory and may have holes.
The page allocator uses the GFP flags, see :ref:`mm-api-gfp-flags`, specified by
a memory allocation to determine the highest zone in a node from which the
memory allocation can allocate memory. The page allocator first allocates memory
from that zone, if the page allocator can't allocate the requested amount of
memory from the zone, it will allocate memory from the next lower zone in the
node, the process continues up to and including the lowest zone. For example, if
a node contains ``ZONE_DMA32``, ``ZONE_NORMAL`` and ``ZONE_MOVABLE`` and the
highest zone of a memory allocation is ``ZONE_MOVABLE``, the order of the zones
from which the page allocator allocates memory is ``ZONE_MOVABLE`` >
``ZONE_NORMAL`` > ``ZONE_DMA32``.
At runtime, free pages in a zone are in the Per-CPU Pagesets (PCP) or free areas
of the zone. The Per-CPU Pagesets are a vital mechanism in the kernel's memory
management system. By handling most frequent allocations and frees locally on
each CPU, the Per-CPU Pagesets improve performance and scalability, especially
on systems with many cores. The page allocator in the kernel employs a two-step
strategy for memory allocation, starting with the Per-CPU Pagesets before
falling back to the buddy allocator. Pages are transferred between the Per-CPU
Pagesets and the global free areas (managed by the buddy allocator) in batches.
This minimizes the overhead of frequent interactions with the global buddy
allocator.
Architecture specific code calls free_area_init() to initializes zones.
struct zone 일반 field: watermark와 PCP
372-450Zone structure `struct zone`은 `include/linux/mmzone.h`에 정의되어 있습니다.
- `_watermark`: zone watermark입니다. Free page가 min 아래이면 boost를 무시하고 allocation이 direct reclaim과 direct compaction을 일으킬 수 있으며 direct reclaim throttle에도 사용합니다. Low 아래이면 kswapd를 깨웁니다. High 위이고 `sysctl_numa_balancing_mode`의 `NUMA_BALANCING_MEMORY_TIERING` bit가 set되지 않았으면 kswapd가 reclaim을 멈추고 zone이 balanced됩니다. Promo watermark는 memory tiering과 NUMA balancing에 사용하며 해당 bit가 set된 경우 free page가 promo 위이면 kswapd가 reclaim을 멈춥니다. `__setup_per_zone_wmarks()`가 설정합니다. Min은 `vm.min_free_kbytes`, 나머지 세 watermark의 간격은 `vm.watermark_scale_factor`를 고려해 계산합니다.
- `watermark_boost`: 앞으로 fallback할 가능성을 낮추도록 reclaim pressure를 높이고, node 전체가 balanced라 자연스럽게 깨지 않을 kswapd를 지금 깨우기 위해 watermark에 더하는 page 수입니다.
- `nr_reserved_highatomic`: high-order atomic allocation용으로 reserve한 page 수입니다.
- `nr_free_highatomic`: reserved highatomic pageblock의 free page 수입니다.
- `lowmem_reserve`: allocation별로 이 zone에 reserve한 memory 양의 array입니다. Allocation 최고 zone이 `ZONE_MOVABLE`이면 이 zone에서 시도할 때 reserve는 `lowmem_reserve[ZONE_MOVABLE]`입니다. Highmem을 쓸 수 있는 allocation이 lowmem을 너무 많이 소비하지 않게 합니다. Highmem machine의 특수 workload에서는 process memory를 lowmem zone에서 할당하면 `mlock()` 또는 swapspace 부재로 pin될 수 있어 위험합니다. `vm.lowmem_reserve_ratio`가 lower-zone 방어 강도를 정하고, sysctl 변경 시 `setup_per_zone_lowmem_reserve()`가 array를 다시 계산합니다.
- `node`: zone이 속한 node index입니다. 원문 설명상 UMA system에는 node가 하나뿐이므로 `CONFIG_NUMA`일 때만 사용할 수 있습니다.
- `zone_pgdat`: zone이 속한 node의 `struct pglist_data` pointer입니다.
- `per_cpu_pageset`: `setup_zone_pageset()`이 할당하고 초기화한 PCP pointer입니다. 잦은 allocation과 free를 CPU local로 처리해 많은 core가 있는 system의 성능과 확장성을 높입니다.
- `pageset_high_min`: 빠른 접근을 위해 PCP의 `high_min`으로 copy됩니다.
- `pageset_high_max`: 빠른 접근을 위해 PCP의 `high_max`로 copy됩니다.
- `pageset_batch`: 빠른 접근을 위해 PCP의 `batch`로 copy됩니다. `batch`, `high_min`, `high_max`는 lock 한 번으로 PCP가 buddy allocator에서 가져올 element 수를 계산하고, page free 과정에서 PCP가 buddy allocator에 page를 반환할지도 결정합니다.
Zone structure
--------------
The zones structure ``struct zone`` is defined in ``include/linux/mmzone.h``.
Here we briefly describe fields of this structure:
General
~~~~~~~
``_watermark``
The watermarks for this zone. When the amount of free pages in a zone is below
the min watermark, boosting is ignored, an allocation may trigger direct
reclaim and direct compaction, it is also used to throttle direct reclaim.
When the amount of free pages in a zone is below the low watermark, kswapd is
woken up. When the amount of free pages in a zone is above the high watermark,
kswapd stops reclaiming (a zone is balanced) when the
``NUMA_BALANCING_MEMORY_TIERING`` bit of ``sysctl_numa_balancing_mode`` is not
set. The promo watermark is used for memory tiering and NUMA balancing. When
the amount of free pages in a zone is above the promo watermark, kswapd stops
reclaiming when the ``NUMA_BALANCING_MEMORY_TIERING`` bit of
``sysctl_numa_balancing_mode`` is set. The watermarks are set by
``__setup_per_zone_wmarks()``. The min watermark is calculated according to
``vm.min_free_kbytes`` sysctl. The other three watermarks are set according
to the distance between two watermarks. The distance itself is calculated
taking ``vm.watermark_scale_factor`` sysctl into account.
``watermark_boost``
The number of pages which are used to boost watermarks to increase reclaim
pressure to reduce the likelihood of future fallbacks and wake kswapd now
as the node may be balanced overall and kswapd will not wake naturally.
``nr_reserved_highatomic``
The number of pages which are reserved for high-order atomic allocations.
``nr_free_highatomic``
The number of free pages in reserved highatomic pageblocks
``lowmem_reserve``
The array of the amounts of the memory reserved in this zone for memory
allocations. For example, if the highest zone a memory allocation can
allocate memory from is ``ZONE_MOVABLE``, the amount of memory reserved in
this zone for this allocation is ``lowmem_reserve[ZONE_MOVABLE]`` when
attempting to allocate memory from this zone. This is a mechanism the page
allocator uses to prevent allocations which could use ``highmem`` from using
too much ``lowmem``. For some specialised workloads on ``highmem`` machines,
it is dangerous for the kernel to allow process memory to be allocated from
the ``lowmem`` zone. This is because that memory could then be pinned via the
``mlock()`` system call, or by unavailability of swapspace.
``vm.lowmem_reserve_ratio`` sysctl determines how aggressive the kernel is in
defending these lower zones. This array is recalculated by
``setup_per_zone_lowmem_reserve()`` at runtime if ``vm.lowmem_reserve_ratio``
sysctl changes.
``node``
The index of the node this zone belongs to. Available only when
``CONFIG_NUMA`` is enabled because there is only one zone in a UMA system.
``zone_pgdat``
Pointer to the ``struct pglist_data`` of the node this zone belongs to.
``per_cpu_pageset``
Pointer to the Per-CPU Pagesets (PCP) allocated and initialized by
``setup_zone_pageset()``. By handling most frequent allocations and frees
locally on each CPU, PCP improves performance and scalability on systems with
many cores.
``pageset_high_min``
Copied to the ``high_min`` of the Per-CPU Pagesets for faster access.
``pageset_high_max``
Copied to the ``high_max`` of the Per-CPU Pagesets for faster access.
``pageset_batch``
Copied to the ``batch`` of the Per-CPU Pagesets for faster access. The
``batch``, ``high_min`` and ``high_max`` of the Per-CPU Pagesets are used to
calculate the number of elements the Per-CPU Pagesets obtain from the buddy
allocator under a single hold of the lock for efficiency. They are also used
to decide if the Per-CPU Pagesets return pages to the buddy allocator in page
free process.
struct zone 일반 field: extent와 buddy state
451-544- `pageblock_flags`: zone pageblock의 flag pointer입니다. Flag 목록은 `include/linux/pageblock-flags.h`에 있고 `setup_usemap()`이 memory를 할당합니다. Pageblock마다 `NR_PAGEBLOCK_BITS` bit를 차지합니다. `CONFIG_FLATMEM`에서만 정의되며 `CONFIG_SPARSEMEM`에서는 flag를 `mem_section`에 저장합니다.
- `zone_start_pfn`: zone 시작 PFN이며 `calculate_node_totalpages()`가 초기화합니다.
- `managed_pages`: buddy system이 관리하는 present page 수입니다. `managed_pages = present_pages - reserved_pages`이며 `reserved_pages`에는 memblock allocator가 할당한 page가 포함됩니다. Page allocator와 VM scanner가 watermark와 threshold를 계산할 때 사용해야 합니다. `atomic_long_xxx()`로 접근합니다. `free_area_init_core()`에서 초기화하고 memblock allocator가 buddy system에 page를 free할 때 다시 초기화합니다.
- `spanned_pages`: hole을 포함해 zone이 span하는 전체 page 수입니다. `spanned_pages = zone_end_pfn - zone_start_pfn`이며 `calculate_node_totalpages()`가 초기화합니다.
- `present_pages`: zone에 실제 존재하는 physical page 수입니다. `present_pages = spanned_pages - absent_pages`, 여기서 absent page는 hole의 page입니다. Memory hotplug 또는 power-management logic이 `present_pages - managed_pages`로 unmanaged page를 파악할 수 있습니다. Runtime write는 `mem_hotplug_begin/done()`으로 보호해야 합니다. Drift를 허용할 수 없는 reader는 `get_online_mems()`로 안정된 값을 얻어야 합니다. `calculate_node_totalpages()`가 초기화합니다.
- `present_early_pages`: early boot부터 사용 가능한 memory에 있는 present page 수이며 hotplug memory는 제외합니다. `CONFIG_MEMORY_HOTPLUG`에서만 정의되고 `calculate_node_totalpages()`가 초기화합니다.
- `cma_pages`: CMA용 reserve page입니다. CMA가 사용하지 않을 때는 `ZONE_MOVABLE`처럼 동작합니다. `CONFIG_CMA`에서만 정의됩니다.
- `name`: `zone_names` array의 대응 element를 가리키는 zone 이름 pointer입니다.
- `nr_isolate_pageblock`: isolate된 pageblock 수입니다. Pageblock migratetype을 race 상태로 읽어 free-page count가 잘못되는 문제를 해결하는 데 사용합니다. `zone->lock`이 보호하며 `CONFIG_MEMORY_ISOLATION`에서만 정의됩니다.
- `span_seqlock`: `zone_start_pfn`과 `spanned_pages`를 보호하는 seqlock입니다. Main allocator path에서 `zone->lock` 밖에서 읽어야 하지만 write는 매우 드물어 seqlock을 사용합니다. `CONFIG_MEMORY_HOTPLUG`에서만 정의됩니다.
- `initialized`: zone 초기화 여부 flag이며 boot 때 `init_currently_empty_zone()`이 set합니다.
- `free_area`: 2의 거듭제곱인 특정 order마다 element가 있는 free-area array입니다. Buddy allocator는 충분한 가장 작은 block을 찾고, 요청보다 크면 필요한 크기에 이를 때까지 다음 작은 block으로 재귀적으로 split합니다. Page를 free하면 buddy와 merge해 더 큰 block을 만들 수 있습니다. `zone_init_free_lists()`가 초기화합니다.
- `unaccepted_pages`: accept해야 할 page 목록입니다. 목록의 모든 page는 `MAX_PAGE_ORDER`입니다. `CONFIG_UNACCEPTED_MEMORY`에서만 정의됩니다.
- `flags`: `enum zone_flags`가 정의한 하위 3bit를 씁니다. Bit 0 `ZONE_BOOSTED_WATERMARK`는 최근 watermark가 boost됐음을 나타내고 kswapd를 깨울 때 clear합니다. Bit 1 `ZONE_RECLAIM_ACTIVE`는 kswapd가 zone을 scan 중일 수 있음을 뜻합니다. Bit 2 `ZONE_BELOW_HIGH`는 zone이 high watermark 아래임을 뜻합니다.
- `lock`: zone별 page allocator 내부 자료 구조, 특히 `free_area`를 보호하는 main lock입니다.
- `percpu_drift_mark`: free page가 이 지점보다 적으면 per-CPU counter drift 때문에 watermark를 침범하지 않도록 free-page 수를 읽을 때 추가 단계를 수행합니다. `refresh_zone_stat_thresholds()`가 갱신합니다.
``pageblock_flags``
The pointer to the flags for the pageblocks in the zone (see
``include/linux/pageblock-flags.h`` for flags list). The memory is allocated
in ``setup_usemap()``. Each pageblock occupies ``NR_PAGEBLOCK_BITS`` bits.
Defined only when ``CONFIG_FLATMEM`` is enabled. The flags is stored in
``mem_section`` when ``CONFIG_SPARSEMEM`` is enabled.
``zone_start_pfn``
The start pfn of the zone. It is initialized by
``calculate_node_totalpages()``.
``managed_pages``
The present pages managed by the buddy system, which is calculated as:
``managed_pages`` = ``present_pages`` - ``reserved_pages``, ``reserved_pages``
includes pages allocated by the memblock allocator. It should be used by page
allocator and vm scanner to calculate all kinds of watermarks and thresholds.
It is accessed using ``atomic_long_xxx()`` functions. It is initialized in
``free_area_init_core()`` and then is reinitialized when memblock allocator
frees pages into buddy system.
``spanned_pages``
The total pages spanned by the zone, including holes, which is calculated as:
``spanned_pages`` = ``zone_end_pfn`` - ``zone_start_pfn``. It is initialized
by ``calculate_node_totalpages()``.
``present_pages``
The physical pages existing within the zone, which is calculated as:
``present_pages`` = ``spanned_pages`` - ``absent_pages`` (pages in holes). It
may be used by memory hotplug or memory power management logic to figure out
unmanaged pages by checking (``present_pages`` - ``managed_pages``). Write
access to ``present_pages`` at runtime should be protected by
``mem_hotplug_begin/done()``. Any reader who can't tolerant drift of
``present_pages`` should use ``get_online_mems()`` to get a stable value. It
is initialized by ``calculate_node_totalpages()``.
``present_early_pages``
The present pages existing within the zone located on memory available since
early boot, excluding hotplugged memory. Defined only when
``CONFIG_MEMORY_HOTPLUG`` is enabled and initialized by
``calculate_node_totalpages()``.
``cma_pages``
The pages reserved for CMA use. These pages behave like ``ZONE_MOVABLE`` when
they are not used for CMA. Defined only when ``CONFIG_CMA`` is enabled.
``name``
The name of the zone. It is a pointer to the corresponding element of
the ``zone_names`` array.
``nr_isolate_pageblock``
Number of isolated pageblocks. It is used to solve incorrect freepage counting
problem due to racy retrieving migratetype of pageblock. Protected by
``zone->lock``. Defined only when ``CONFIG_MEMORY_ISOLATION`` is enabled.
``span_seqlock``
The seqlock to protect ``zone_start_pfn`` and ``spanned_pages``. It is a
seqlock because it has to be read outside of ``zone->lock``, and it is done in
the main allocator path. However, the seqlock is written quite infrequently.
Defined only when ``CONFIG_MEMORY_HOTPLUG`` is enabled.
``initialized``
The flag indicating if the zone is initialized. Set by
``init_currently_empty_zone()`` during boot.
``free_area``
The array of free areas, where each element corresponds to a specific order
which is a power of two. The buddy allocator uses this structure to manage
free memory efficiently. When allocating, it tries to find the smallest
sufficient block, if the smallest sufficient block is larger than the
requested size, it will be recursively split into the next smaller blocks
until the required size is reached. When a page is freed, it may be merged
with its buddy to form a larger block. It is initialized by
``zone_init_free_lists()``.
``unaccepted_pages``
The list of pages to be accepted. All pages on the list are ``MAX_PAGE_ORDER``.
Defined only when ``CONFIG_UNACCEPTED_MEMORY`` is enabled.
``flags``
The zone flags. The least three bits are used and defined by
``enum zone_flags``. ``ZONE_BOOSTED_WATERMARK`` (bit 0): zone recently boosted
watermarks. Cleared when kswapd is woken. ``ZONE_RECLAIM_ACTIVE`` (bit 1):
kswapd may be scanning the zone. ``ZONE_BELOW_HIGH`` (bit 2): zone is below
high watermark.
``lock``
The main lock that protects the internal data structures of the page allocator
specific to the zone, especially protects ``free_area``.
``percpu_drift_mark``
When free pages are below this point, additional steps are taken when reading
the number of free pages to avoid per-cpu counter drift allowing watermarks
to be breached. It is updated in ``refresh_zone_stat_thresholds()``.
Zone compaction control과 통계
545-609- `compact_cached_free_pfn`: 다음 scan에서 compaction free scanner가 시작할 PFN입니다.
- `compact_cached_migrate_pfn`: 다음 scan에서 compaction migration scanner가 시작할 PFN array입니다. 첫 element는 `MIGRATE_ASYNC`, 두 번째는 `MIGRATE_SYNC` mode에서 사용합니다.
- `compact_init_migrate_pfn`: initial migration PFN입니다. Boot 때 0으로 초기화하고 full compaction이 끝난 뒤에는 zone에서 migratable page가 있는 첫 pageblock으로 설정합니다. Scan이 zone 전체 scan인지 확인하는 데 사용합니다.
- `compact_init_free_pfn`: initial free PFN입니다. Boot 때 0으로, 이후에는 zone에서 free `MIGRATE_MOVABLE` page가 있는 마지막 pageblock으로 설정합니다. Scan 시작인지 확인하는 데 사용합니다.
- `compact_considered`: 마지막 실패 뒤 compaction을 시도한 횟수입니다. Compaction이 page-allocation 성공으로 이어지지 않으면 `defer_compaction()`이 reset합니다. Compaction을 skip해야 할 때 `compaction_deferred()`가 1 증가시킵니다. `compaction_deferred()`는 `compact_zone()` 전에 호출하고, `compact_zone()`이 `COMPACT_SUCCESS`를 반환하면 `compaction_defer_reset()`을, `COMPACT_PARTIAL_SKIPPED` 또는 `COMPACT_COMPLETE`를 반환하면 `defer_compaction()`을 호출합니다.
- `compact_defer_shift`: 다시 시도하기 전 skip할 compaction 수는 `1 << compact_defer_shift`입니다. `defer_compaction()`에서 1 증가하고 direct compaction이 page allocation에 성공하면 `compaction_defer_reset()`에서 reset합니다. 최댓값은 `COMPACT_MAX_DEFER_SHIFT`입니다.
- `compact_order_failed`: compaction에 실패한 최소 order입니다. 성공 시 `compaction_defer_reset()`에서, page-allocation 성공으로 이어지지 않은 실패 시 `defer_compaction()`에서 설정합니다.
- `compact_blockskip_flush`: compaction migration scanner와 free scanner가 만났을 때 true로 set하며, `PB_compact_skip` bit를 clear해야 한다는 뜻입니다.
- `contiguous`: zone에 hole이 없어 contiguous하면 true입니다.
`vm_stat`은 `enum zone_stat_item`이 정의한 항목의 zone VM statistic입니다. `vm_numa_event`는 `enum numa_stat_item`이 정의한 zone VM NUMA-event statistic입니다.
`per_cpu_zonestats`는 zone의 CPU별 VM statistic입니다. VM statistic과 NUMA-event statistic을 CPU별로 기록해 global `vm_stat`과 `vm_numa_event` update를 줄이고 성능을 높입니다.
Compaction control
~~~~~~~~~~~~~~~~~~
``compact_cached_free_pfn``
The PFN where compaction free scanner should start in the next scan.
``compact_cached_migrate_pfn``
The PFNs where compaction migration scanner should start in the next scan.
This array has two elements: the first one is used in ``MIGRATE_ASYNC`` mode,
and the other one is used in ``MIGRATE_SYNC`` mode.
``compact_init_migrate_pfn``
The initial migration PFN which is initialized to 0 at boot time, and to the
first pageblock with migratable pages in the zone after a full compaction
finishes. It is used to check if a scan is a whole zone scan or not.
``compact_init_free_pfn``
The initial free PFN which is initialized to 0 at boot time and to the last
pageblock with free ``MIGRATE_MOVABLE`` pages in the zone. It is used to check
if it is the start of a scan.
``compact_considered``
The number of compactions attempted since last failure. It is reset in
``defer_compaction()`` when a compaction fails to result in a page allocation
success. It is increased by 1 in ``compaction_deferred()`` when a compaction
should be skipped. ``compaction_deferred()`` is called before
``compact_zone()`` is called, ``compaction_defer_reset()`` is called when
``compact_zone()`` returns ``COMPACT_SUCCESS``, ``defer_compaction()`` is
called when ``compact_zone()`` returns ``COMPACT_PARTIAL_SKIPPED`` or
``COMPACT_COMPLETE``.
``compact_defer_shift``
The number of compactions skipped before trying again is
``1<<compact_defer_shift``. It is increased by 1 in ``defer_compaction()``.
It is reset in ``compaction_defer_reset()`` when a direct compaction results
in a page allocation success. Its maximum value is ``COMPACT_MAX_DEFER_SHIFT``.
``compact_order_failed``
The minimum compaction failed order. It is set in ``compaction_defer_reset()``
when a compaction succeeds and in ``defer_compaction()`` when a compaction
fails to result in a page allocation success.
``compact_blockskip_flush``
Set to true when compaction migration scanner and free scanner meet, which
means the ``PB_compact_skip`` bits should be cleared.
``contiguous``
Set to true when the zone is contiguous (in other words, no hole).
Statistics
~~~~~~~~~~
``vm_stat``
VM statistics for the zone. The items tracked are defined by
``enum zone_stat_item``.
``vm_numa_event``
VM NUMA event statistics for the zone. The items tracked are defined by
``enum numa_stat_item``.
``per_cpu_zonestats``
Per-CPU VM statistics for the zone. It records VM statistics and VM NUMA event
statistics on a per-CPU basis. It reduces updates to the global ``vm_stat``
and ``vm_numa_event`` fields of the zone to improve performance.
Pages, Folios와 Initialization 자리표시자
610-635`Pages` section은 incomplete stub입니다. 적절한 field를 나열하고 설명해 달라는 안내만 있습니다.
`Folios` section도 incomplete stub이며 적절한 field 목록과 설명이 아직 필요합니다.
`Initialization` section 역시 incomplete stub이며 적절한 field를 나열하고 설명하라는 안내만 있습니다. 원문에 없는 field 설명은 추가하지 않았습니다.
.. _pages:
Pages
=====
.. admonition:: Stub
This section is incomplete. Please list and describe the appropriate fields.
.. _folios:
Folios
======
.. admonition:: Stub
This section is incomplete. Please list and describe the appropriate fields.
.. _initialization:
Initialization
==============
.. admonition:: Stub
This section is incomplete. Please list and describe the appropriate fields.
요약·해설
physical_memory.rst:1-635Linux physical-memory model은 memory bank를 node로, node 안의 address-constrained range를 zone으로 표현합니다. Node의 `pg_data_t`는 zone·reclaim·compaction state를 모으고, 각 `struct zone`은 watermark·PCP·buddy free area·extent와 statistic을 관리합니다.
Architecture가 보고한 memory range를 node와 zone으로 나누고 page allocator가 page 단위로 관리합니다.
접근 제약과 이동 가능성에 따라 physical-memory range를 구분합니다.
원문의 첫 ASCII layout을 동일한 주소 경계로 구조화했습니다.
원문에 표시된 1GB~17GB 주소와 zone 경계를 그대로 보존했습니다.
4GB bank 네 개가 node 0과 node 1에 번갈아 속하는 원문 구조입니다.
각 property mask의 node-ID bit가 해당 속성 보유 여부를 나타냅니다.
CPU-local fast path를 먼저 사용하고 필요한 경우 global buddy allocator로 이동합니다.
Free-page 수가 각 경계를 지날 때 reclaim·kswapd 동작이 달라집니다.
Span, presence와 buddy 관리 범위를 구분합니다.
Allocation은 충분한 block을 나누고 free는 buddy와 다시 합칩니다.
Migration scanner와 free scanner가 zone 양쪽을 탐색하며 만남 여부와 다음 시작 PFN을 기록합니다.