๐ NUMA (Non-Uniform Memory Access)
๊ด๋ จ ์์ค:mm/numa.c,mm/numa_memblks.c,mm/numa_emulation.c,mm/memory-tiers.c
๊ด๋ จ ํค๋:include/linux/numa.h,include/linux/numa_memblks.h,include/linux/memory-tiers.h,include/linux/mmzone.h,include/linux/node.h
๊ด๋ จ ๋ฌธ์: ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ ๊ฐ์ ยท Buddy Allocator ยท Migration ยท ๋ฉ๋ชจ๋ฆฌ Hotplug ยท ๋ฉ๋ชจ๋ฆฌ ํฐ์ด๋ง
๊ฐ์ (Overview)
NUMA(Non-Uniform Memory Access)๋ ๋ฉํฐ์์ผ ์์คํ
์์ ๊ฐ CPU ์์ผ์ด ๋ก์ปฌ ๋ฉ๋ชจ๋ฆฌ์ ๋น ๋ฅด๊ฒ ์ ๊ทผํ๊ณ ์๊ฒฉ ๋ฉ๋ชจ๋ฆฌ์๋ ๋๋ฆฌ๊ฒ ์ ๊ทผํ๋ ์ํคํ
์ฒ์
๋๋ค. ๋ฆฌ๋
์ค ์ปค๋์ ๋ฌผ๋ฆฌ ๋ฉ๋ชจ๋ฆฌ๋ฅผ Node โ Zone โ Page 3๋จ๊ณ ๊ณ์ธต์ผ๋ก ๊ด๋ฆฌํ๋ฉฐ, ๊ฐ NUMA ๋
ธ๋๋ ๋
๋ฆฝ์ ์ธ pg_data_t, Zone, kswapd๋ฅผ ๊ฐ์ง๋๋ค.
์ผ์ ๋น์ : NUMA๋ ๋ํ ๋์๊ด ์ฒด์ธ๊ณผ ๋น์ทํฉ๋๋ค. ๊ฐ ์ง์ (Node)์ ์์ฒด ์๊ฐ(๋ฌผ๋ฆฌ ๋ฉ๋ชจ๋ฆฌ)๊ฐ ์๊ณ , ์ง์ ๋ด ๋์ถ(๋ก์ปฌ ์ ๊ทผ, ~100ns)์ ๋น ๋ฅด์ง๋ง ๋ค๋ฅธ ์ง์ ์ผ๋ก ์ฑ ์ ๋ณด๋ด๋ ๊ฒ(์๊ฒฉ ์ ๊ทผ, ~200ns+)์ ๋๋ฆฝ๋๋ค. ๋์๊ด ์์คํ (์ปค๋)์ ์์ฃผ ์ฝ๋ ์ฑ ์ ์ธ๊ธฐ ์ง์ ์ ๋ณต์ฌํ์ฌ ์ฑ๋ฅ์ ์ต์ ํํฉ๋๋ค.
Linux 7.0์์๋ NUMA ์ด๊ธฐํ(numa_memblks_init)๋ฅผ ํตํด ACPI SRAT/SLIT์์ ํ์ฑํ ๋
ธ๋ ๊ฑฐ๋ฆฌ ์ ๋ณด์ ๋ฉ๋ชจ๋ฆฌ ๋ธ๋ก์ ๋ฑ๋กํ๊ณ , Memory Tiering(memory-tiers.c)์ ํตํด DRAM, PMEM, HBM ๊ฐ์ ์ด์ง์ ์ธ ๋ฉ๋ชจ๋ฆฌ ๊ณ์ธต์ ์ถ์ ๊ฑฐ๋ฆฌ(abstract distance)๋ก ํตํฉ ๊ด๋ฆฌํฉ๋๋ค. ๋ํ CONFIG_MIGRATION์ด ํ์ฑํ๋๋ฉด ์๋ ๊ณ์ธต ์ด๋(demotion/promotion)์ด ๊ฐ๋ฅํด์ง๋๋ค. ์ปค๋์ ์ถ์ ๊ฑฐ๋ฆฌ ๊ณ์ฐ ์๊ณ ๋ฆฌ์ฆ์ notifier chain์ผ๋ก ํ์ฅ ๊ฐ๋ฅํ๊ฒ ์ค๊ณํ์ฌ, ๋๋ผ์ด๋ฒ๋ณ ๋ง์ถค ๊ฑฐ๋ฆฌ ๊ณ์ฐ์ ์ง์ํฉ๋๋ค.
ํต์ฌ ์ฑ๋ฅ ์์น
| ํญ๋ชฉ | ๊ฐ | ์ค๋ช |
|---|---|---|
| ๋ก์ปฌ ๋ ธ๋ ์ ๊ทผ ์ง์ฐ | ~100ns | ๊ฐ์ ์์ผ์ DDR ๋ฉ๋ชจ๋ฆฌ ์ง์ ์ ๊ทผ |
| ์๊ฒฉ ๋ ธ๋ ์ ๊ทผ ์ง์ฐ | ~200ns+ | ์ธํฐ์ปค๋ฅํธ(QPI/UPI) ๊ฒฝ์ |
| ๋ก์ปฌ vs ์๊ฒฉ ๋น์จ | 2ร~3ร | ์๊ฒฉ ์ ๊ทผ์ด 2~3๋ฐฐ ๋๋ฆผ |
| MEMTIER_CHUNK_SIZE | 128 | ํฐ์ด๋น ์ถ์ ๊ฑฐ๋ฆฌ ๋ฒ์ |
| MEMTIER_ADISTANCE_DRAM | 576 | ๊ธฐ๋ณธ DRAM ์ถ์ ๊ฑฐ๋ฆฌ |
์์ค ํ์ผ ๊ตฌ์กฐ
mm/numa.c โ NODE_DATA ํ ๋น, ๊ธฐ๋ณธ stub ํจ์
mm/numa_memblks.c โ NUMA ๋ฉ๋ชจ๋ฆฌ ๋ธ๋ก ๊ด๋ฆฌ, ๊ฑฐ๋ฆฌ ํ
์ด๋ธ, ์ด๊ธฐํ ์ฝ์ด
mm/numa_emulation.c โ NUMA ์๋ฎฌ๋ ์ด์
(๊ฐ์ NUMA ๊ตฌ์ฑ)
mm/memory-tiers.c โ ๋ฉ๋ชจ๋ฆฌ ํฐ์ด๋ง, ์ถ์ ๊ฑฐ๋ฆฌ, demotion/promotion, hotplug ์ฝ๋ฐฑ
include/linux/numa.h โ NODE_DATA(), numa_valid_node(), NUMA_NO_MEMBLK
include/linux/numa_memblks.h โ numa_memblk, numa_meminfo ๊ตฌ์กฐ์ฒด
include/linux/memory-tiers.h โ memory_dev_type, adistance, tier API
include/linux/mmzone.h โ pglist_data(pg_data_t) ์ ์
include/linux/node.h โ access_coordinate ๊ตฌ์กฐ์ฒด (๋ฉ๋ชจ๋ฆฌ ์ฑ๋ฅ ์ขํ)
์ด๊ธฐํ ํ๋ฆ ๋ค์ด์ด๊ทธ๋จ
๋ฉ๋ชจ๋ฆฌ ํฐ์ด ๊ณ์ธต ๊ตฌ์กฐ
๋น ๋ฅธ ์ ๊ฒ ๋ช ๋ น
# NUMA ๋
ธ๋ ๊ตฌ์ฑ ํ์ธ (๋
ธ๋ ์, CPU, ๋ฉ๋ชจ๋ฆฌ ํฌ๊ธฐ)
numactl -H
# ๊ฐ ๋
ธ๋ ๋ฉ๋ชจ๋ฆฌ ์์ธ
cat /sys/devices/system/node/node0/meminfo
# NUMA ๊ฑฐ๋ฆฌ ๋งคํธ๋ฆญ์ค ํ์ธ (ACPI SLIT ๊ธฐ๋ฐ)
numactl --hardware | grep -A 20 "node distances"
# ๋
ธ๋๋ณ Zone ์ ๋ณด
cat /proc/zoneinfo | grep -E 'Node|zone|spanned|present' | head -40
# ๋ฉ๋ชจ๋ฆฌ ํฐ์ด ๋๋ ํ ๋ฆฌ ํ์ธ
ls /sys/devices/system/memory_tier/
# NUMA ๋ฏธ์ค/hit ํต๊ณ โ ์๊ฒฉ ์ ๊ทผ ๋น์จ ๋ชจ๋ํฐ๋ง
grep -E 'numa_hit|numa_miss|numa_foreign' /proc/vmstat
# NUMA ์๋ ๊ณ์ธต ์ด๋(demotion) ํ์ฑํ ์ํ
cat /sys/kernel/mm/numa/demotion_enabled
# NUMA ๊ด๋ จ ์ปค๋ ์ค์ ํ์ธ
grep -E 'CONFIG_NUMA|CONFIG_NUMA_BALANCING|CONFIG_MIGRATION' /boot/config-$(uname -r)
# ํ์ฌ ํ๋ก์ธ์ค์ NUMA ๋ฉ๋ชจ๋ฆฌ ๋ถํฌ
numastat -p $$
# NUMA ์ ์ฑ
ํ์ธ โ ํ์ฌ ํ๋ก์ธ์ค์ ๋ฉ๋ชจ๋ฆฌ ์ ์ฑ
numactl --show
# NUMA ํํธ ํดํธ ํต๊ณ (AutoNUMA ํ์ฑํ ์)
grep -E 'numa_pte_update|numa_hint_faults|numa_hint_faults_local' /proc/vmstat
# ๋
ธ๋๋ณ ์ด ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋ ๋น๊ต
grep -E 'MemTotal|MemFree|MemAvailable' /proc/meminfo
# ๊ฐ ํฐ์ด์ ๋
ธ๋ ๋ชฉ๋ก ํ์ธ
for tier in /sys/devices/system/memory_tier/memory_tier*/; do
echo "=== $(basename $tier) ==="
cat ${tier}nodelist 2>/dev/null
done
# NUMA ๊ฑฐ๋ฆฌ ์ง์ ์กฐํ (libnuma)
numactl --hardware | grep -E 'node|distance'
# ๋ฉ๋ชจ๋ฆฌ ํซํ๋ฌ๊ทธ๋ก ์ถ๊ฐ๋ ๋
ธ๋ ํ์ธ
dmesg | grep -E 'NUMA|node|memory' | tail -20
# NUMA ์๋ฎฌ๋ ์ด์
ํ์ธ (๋ถํ
ํ๋ผ๋ฏธํฐ)
cat /proc/cmdline | grep -o 'numa=fake=[^ ]*'
# ์ถ์ ๊ฑฐ๋ฆฌ ์๋ฆผ ์ฒด์ธ ๋ฑ๋ก ํ์ธ (์ปค๋ ๋ก๊ทธ)
dmesg | grep -E 'adistance|memory tier|tier'
# NUMA ๋
ธ๋๋ณ ์บ์ ์์ฑ ํ์ธ (HMEM_REPORTING ํ์ฑํ ์)
ls /sys/devices/system/node/node*/cache/
# ๊ธฐ๋ณธ DRAM ์ฑ๋ฅ ๊ธฐ์ค๊ฐ ํ์ธ
dmesg | grep -E 'default.*DRAM|abstract distance'
ํต์ฌ ์๋ฃ๊ตฌ์กฐ
1. numa_memblk โ ๋จ์ผ ๋ฉ๋ชจ๋ฆฌ ๋ธ๋ก
ํ๋์จ์ด/ํ์จ์ด๊ฐ ์ ๊ณตํ๋ ํ๋์ ๋ฌผ๋ฆฌ ๋ฉ๋ชจ๋ฆฌ ๊ตฌ๊ฐ์ ๋ํ๋ ๋๋ค.
/* include/linux/numa_memblks.h:13-17 */
struct numa_memblk {
u64 start; /* ์์ ๋ฌผ๋ฆฌ ์ฃผ์ */
u64 end; /* ๋ ๋ฌผ๋ฆฌ ์ฃผ์ (exclusive) */
int nid; /* ์ด ๋ธ๋ก์ด ์ํ NUMA ๋
ธ๋ ID */
};
start, end: ๋ฌผ๋ฆฌ ์ฃผ์ ๋ฒ์. start == end์ด๋ฉด ๋น ๋ธ๋ก์ผ๋ก ๊ฐ์ฃผnid: NUMA_NO_NODE์ด๋ฉด ์ ํจํ์ง ์์ ๋ธ๋ก2. numa_meminfo โ ์ ์ฒด NUMA ๋ฉ๋ชจ๋ฆฌ ๋ธ๋ก ์ปฌ๋ ์
์์คํ ์ ์ฒด์ NUMA ๋ฉ๋ชจ๋ฆฌ ๋ธ๋ก ๋ฐฐ์ด์ ๊ด๋ฆฌํฉ๋๋ค.
/* include/linux/numa_memblks.h:19-22 */
struct numa_meminfo {
int nr_blks; /* ํ์ฌ ๋ฑ๋ก๋ ๋ธ๋ก ์ */
struct numa_memblk blk[NR_NODE_MEMBLKS]; /* ๋ฉ๋ชจ๋ฆฌ ๋ธ๋ก ๋ฐฐ์ด */
};
NR_NODE_MEMBLKS๋ MAX_NUMNODES 2๋ก ์ ์ (๊ธฐ๋ณธ ์ต๋ 256 2 = 512๊ฐ)numa_memblks.c:17์์ ์ ์ญ numa_meminfo์ numa_reserved_meminfo๋ก ๊ด๋ฆฌ๋จ3. memory_dev_type โ ๋ฉ๋ชจ๋ฆฌ ์ ํ
ํ๋์จ์ด ๋ฉ๋ชจ๋ฆฌ ์ ํ(DRAM, PMEM, HBM ๋ฑ)์ ์ถ์ ๊ฑฐ๋ฆฌ ์ ๋ณด๋ฅผ ๋ด์ต๋๋ค.
/* include/linux/memory-tiers.h:24-34 */
struct memory_dev_type {
/* ๊ฐ์ ํฐ์ด์ ์ํ๋ ๋ฉ๋ชจ๋ฆฌ ์ ํ๋ค์ ๋ฆฌ์คํธ */
struct list_head tier_sibling;
/* ํ ๋๋ผ์ด๋ฒ๊ฐ ๊ด๋ฆฌํ๋ ๋ฉ๋ชจ๋ฆฌ ์ ํ๋ค์ ๋ฆฌ์คํธ */
struct list_head list;
/* ์ด ๋ฉ๋ชจ๋ฆฌ ์ ํ์ ์ถ์ ๊ฑฐ๋ฆฌ (abstract distance) */
int adistance;
/* ๊ฐ์ ์ถ์ ๊ฑฐ๋ฆฌ๋ฅผ ๊ฐ์ง ๋
ธ๋๋ค์ ๋ง์คํฌ */
nodemask_t nodes;
struct kref kref; /* ์ฐธ์กฐ ์นด์ดํธ */
};
adistance: ์์์๋ก ๋น ๋ฅธ ๋ฉ๋ชจ๋ฆฌ. DRAM ๊ธฐ๋ณธ๊ฐ์ MEMTIER_ADISTANCE_DRAM (576)tier_sibling: memory_tier.memory_types ๋ฆฌ์คํธ์ ์ฐ๊ฒฐ๋จnodes: ์ด ๋ฉ๋ชจ๋ฆฌ ์ ํ์ ์ํ NUMA ๋
ธ๋๋ค์ ๋นํธ๋ง์คํฌ4. memory_tier โ ๋ฉ๋ชจ๋ฆฌ ๊ณ์ธต
ํ๋์ ๋ฉ๋ชจ๋ฆฌ ๊ณ์ธต(DRAM tier, PMEM tier ๋ฑ)์ ๋ํ๋ด๋ฉฐ, ์ฌ๋ฌ memory_dev_type์ด ํ๋์ tier์ ์ํ ์ ์์ต๋๋ค.
/* mm/memory-tiers.c:13-27 */
struct memory_tier {
/* ๊ณ์ธต ๋ชฉ๋ก (top tier โ bottom tier ์์) */
struct list_head list;
/* ์ด ๊ณ์ธต์ ์ํ ๋ชจ๋ ๋ฉ๋ชจ๋ฆฌ ์ ํ ๋ชฉ๋ก */
struct list_head memory_types;
/*
* ์ถ์ ๊ฑฐ๋ฆฌ ๋ฒ์์ ์์๊ฐ.
* ๊ฐ tier๋ MEMTIER_CHUNK_SIZE(128) ํฌ๊ธฐ์ ๊ฑฐ๋ฆฌ ๋ฒ์๋ฅผ ์ปค๋ฒ
*/
int adistance_start;
struct device dev; /* sysfs ๋๋ฐ์ด์ค */
/* ์ด ๊ณ์ธต ์๋์ ์๋ ๋ชจ๋ ํฐ์ด์ ๋
ธ๋ ๋ง์คํฌ */
nodemask_t lower_tier_mask;
};
list: ์ ์ญ memory_tiers ๋ฆฌ์คํธ์ ์ฐ๊ฒฐ. top โ bottom ์์๋ก ์ ๋ ฌlower_tier_mask: demotion ์ fallback ๋์ ๋
ธ๋ ๋ง์คํฌ5. pglist_data (pg_data_t) โ NUMA ๋ ธ๋ ๋ฐ์ดํฐ
๊ฐ NUMA ๋ ธ๋์ ๋ชจ๋ ์ํ๋ฅผ ๋ด๋ ์ต์์ ๊ตฌ์กฐ์ฒด์ ๋๋ค.
/* include/linux/mmzone.h:1381-1521 (ํต์ฌ ํ๋ ๋ฐ์ท) */
typedef struct pglist_data {
struct zone node_zones[MAX_NR_ZONES]; /* ์ด ๋
ธ๋์ ์กด๋ค */
struct zonelist node_zonelists[MAX_ZONELISTS]; /* ์ ์ฒด ์์คํ
์กด ๋ฆฌ์คํธ */
int nr_zones; /* ์ฑ์์ง ์กด ์ */
unsigned long node_start_pfn; /* ์์ PFN */
unsigned long node_present_pages; /* ๋ฌผ๋ฆฌ ํ์ด์ง ํฉ๊ณ */
unsigned long node_spanned_pages; /* hole ํฌํจ ์ ์ฒด ๋ฒ์ */
int node_id; /* NUMA ๋
ธ๋ ID */
struct task_struct *kswapd; /* ํ์ด์ง ํ์ ์ค๋ ๋ */
#ifdef CONFIG_NUMA
struct memory_tier __rcu *memtier; /* ์ด ๋
ธ๋์ ๋ฉ๋ชจ๋ฆฌ ํฐ์ด (RCU) */
#endif
/* ... ๋ค๋ฅธ ํ๋๋ค ... */
} pg_data_t;
node_data[MAX_NUMNODES] ๋ฐฐ์ด๋ก ์ ์ญ ๊ด๋ฆฌ (numa.c:8)NODE_DATA(nid) ๋งคํฌ๋ก๋ก ์ ๊ทผ (numa.h:26)memtier: RCU๋ก ๋ณดํธ๋๋ฉฐ, ๋ฉ๋ชจ๋ฆฌ ํฐ์ด๋ง ์์คํ
์์ ๋
ธ๋์ ๊ณ์ธต ์์น๋ฅผ ๋ํ๋6. demotion_nodes โ ๊ณ์ธต ์ด๋ ๋์
CONFIG_MIGRATION ํ์ฑํ ์ ๊ฐ ๋
ธ๋์ demotion(ํ์ ๊ณ์ธต์ผ๋ก ์ด๋) ๋์ ๋
ธ๋๋ฅผ ๊ธฐ๋กํฉ๋๋ค.
/* mm/memory-tiers.c:29-31 */
struct demotion_nodes {
nodemask_t preferred; /* ์ ํธํ๋ demotion ๋์ ๋
ธ๋ ๋ง์คํฌ */
};
node_demotion[] ๋ฐฐ์ด: ๋
ธ๋๋น ํ๋์ demotion_nodespreferred: ๊ฐ์ ๊ฑฐ๋ฆฌ์ ์ฌ๋ฌ ๋์์ด ์์ ๋ ๋๋ค ์ ํ์ฉ7. access_coordinate โ ๋ฉ๋ชจ๋ฆฌ ์ฑ๋ฅ ์ขํ
๋ฉ๋ชจ๋ฆฌ ๋๋ฐ์ด์ค์ ์ฝ๊ธฐ/์ฐ๊ธฐ ์ง์ฐ์๊ฐ๊ณผ ๋์ญํญ์ ๋ํ๋ด๋ ๊ตฌ์กฐ์ฒด์ ๋๋ค.
/* include/linux/node.h:29-34 */
struct access_coordinate {
unsigned int read_bandwidth; /* ์ฝ๊ธฐ ๋์ญํญ (MB/s) */
unsigned int write_bandwidth; /* ์ฐ๊ธฐ ๋์ญํญ (MB/s) */
unsigned int read_latency; /* ์ฝ๊ธฐ ์ง์ฐ (ns) */
unsigned int write_latency; /* ์ฐ๊ธฐ ์ง์ฐ (ns) */
};
mt_perf_to_adistance(): ์ด ์ขํ๋ฅผ ์ถ์ ๊ฑฐ๋ฆฌ(adistance)๋ก ๋ณํdefault_dram_perf)์ ๊ธฐ์ค์ผ๋ก ๋น๋ก ๊ณ์ฐaccess_coordinate_class: ACCESS_COORDINATE_LOCAL(๋
ธ๋ ๊ฐ)๊ณผ ACCESS_COORDINATE_CPU(CPU-๋ฉ๋ชจ๋ฆฌ ๊ฐ) ๋ ๊ฐ์ง ํด๋์คnode_set_perf_attrs(): NUMA ๊ฑฐ๋ฆฌ ๋งคํธ๋ฆญ์ค์ HW ๋ฉ๋ชจ๋ฆฌ ์ฑ๋ฅ ์ขํ ๋ฑ๋ก/* mm/memory-tiers.c:815-819 โ ์ถ์ ๊ฑฐ๋ฆฌ ๊ณ์ฐ ๊ณต์ */
*adist = MEMTIER_ADISTANCE_DRAM *
(perf->read_latency + perf->write_latency) /
(default_dram_perf.read_latency + default_dram_perf.write_latency) *
(default_dram_perf.read_bandwidth + default_dram_perf.write_bandwidth) /
(perf->read_bandwidth + perf->write_bandwidth);
default_dram_perf_error๋ก ์๊ณ ๋ฆฌ์ฆ ๋นํ์ฑํ8. node_memory_type_map โ ๋ ธ๋๋ณ ๋ฉ๋ชจ๋ฆฌ ์ ํ ๋งคํ
๊ฐ NUMA ๋
ธ๋๊ฐ ์ด๋ค memory_dev_type์ ์ํ๋์ง ์ถ์ ํฉ๋๋ค.
/* mm/memory-tiers.c:33-36 */
struct node_memory_type_map {
struct memory_dev_type *memtype; /* ์ด ๋
ธ๋์ ๋ฉ๋ชจ๋ฆฌ ์ ํ */
int map_count; /* ๊ฐ์ ์ ํ์ ๋๋ฐ์ด์ค ์ */
};
node_memory_types[MAX_NUMNODES]: ์ ์ญ ๋ฐฐ์ด๋ก ๋ชจ๋ ๋
ธ๋ ๊ด๋ฆฌmap_count: ๊ฐ์ ๋
ธ๋์ ๊ฐ์ ์ ํ ๋๋ฐ์ด์ค๊ฐ ์ฌ๋ฌ ๊ฐ ์ฐ๊ฒฐ๋ ๋ ์ฐธ์กฐ ์นด์ดํธํต์ฌ ํจ์
1. numa_memblks_init() โ NUMA ์ด๊ธฐํ ์ฝ์ด
/* mm/numa_memblks.c:445-484 */
int __init numa_memblks_init(int (*init_func)(void),
bool memblock_force_top_down)
์ญํ : NUMA ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ์ ์ ์ฒด ์ด๊ธฐํ๋ฅผ ์ํํ๋ ๋ฉ์ธ ์ง์ ์ .
ํ๋ฆ:
1. ๋
ธ๋ ๋ง์คํฌ ์ด๊ธฐํ (nodes_clear)
2. memblock์ NUMA_NO_NODE๋ก ์ด๊ธฐ ๋ฆฌ์
3. init_func() ํธ์ถ โ ์ํคํ
์ฒ๋ณ NUMA ์ ๋ณด ํ์ฑ (์: ACPI SRAT)
4. memblock_set_bottom_up(false) โ top-down ํ ๋น์ผ๋ก ์ ํ
5. numa_cleanup_meminfo() โ ๋ฉ๋ชจ๋ฆฌ ๋ธ๋ก ์ ๋ฆฌ ๋ฐ ๋ณํฉ
6. numa_emulation() โ NUMA ์๋ฎฌ๋ ์ด์
(์ ํ)
7. numa_register_meminfo() โ ์ค์ ๋ฑ๋ก ๋ฐ hotplug ๋ณดํธ
2. numa_set_distance() โ ๋ ธ๋ ๊ฐ ๊ฑฐ๋ฆฌ ์ค์
/* mm/numa_memblks.c:105-125 */
void __init numa_set_distance(int from, int to, int distance)
์ญํ : ๋ NUMA ๋ ธ๋ ๊ฐ์ ๊ฑฐ๋ฆฌ๋ฅผ ๊ฑฐ๋ฆฌ ํ ์ด๋ธ์ ๊ธฐ๋กํฉ๋๋ค.
๋ถ๊ธฐ ๋ก์ง:
numa_alloc_distance()๋ก ์์ฑ ์๋from/to๊ฐ ๋ฒ์ ์ด๊ณผ โ ๊ฒฝ๊ณ ํ ๋ฌด์distance๊ฐ u8 ๋ฒ์ ์ด๊ณผ โ ๊ฒฝ๊ณ ํ ๋ฌด์distance != LOCAL_DISTANCE(10) โ ๊ฒฝ๊ณ ํ ๋ฌด์3. numa_cleanup_meminfo() โ ๋ฉ๋ชจ๋ฆฌ ๋ธ๋ก ์ ๋ฆฌ
/* mm/numa_memblks.c:237-329 */
int __init numa_cleanup_meminfo(struct numa_meminfo *mi)
์ญํ : ๋ฉ๋ชจ๋ฆฌ ๋ธ๋ก์ ์ ๋ฆฌํ๊ณ , ๊ฒน์น๋ ๋ธ๋ก์ ๋ณํฉํฉ๋๋ค.
ํ๋ฆ:
1. ํธ๋ฆฌ๋ฐ ๋จ๊ณ: ๊ฐ ๋ธ๋ก์ DRAM ๋ฒ์๋ก ์๋ฅด๊ณ , ์์ฝ ์์ญ์ numa_reserved_meminfo๋ก ์ด๋
2. ๋ณํฉ ๋จ๊ณ: ๊ฐ์ ๋ ธ๋์ ์ธ์ /๊ฒน์น๋ ๋ธ๋ก์ ๋ณํฉ (๋ค๋ฅธ ๋ ธ๋์ ๊ฒน์น๋ฉด ์๋ฌ)
3. ์ด๊ธฐํ ๋จ๊ณ: ๋ฏธ์ฌ์ฉ ์ฌ๋กฏ์ NUMA_NO_NODE๋ก ์ด๊ธฐํ
4. establish_demotion_targets() โ ๊ณ์ธต ์ด๋ ๋์ ๊ฒฐ์
/* mm/memory-tiers.c:425-518 */
static void establish_demotion_targets(void)
์ญํ : ๋ชจ๋ ๋ฉ๋ชจ๋ฆฌ ๋ ธ๋์ ๋ํด ์๋ demotion(ํ์ ๊ณ์ธต ์ด๋) ๋์์ ์ค์ ํฉ๋๋ค.
ํ๋ฆ:
1. ๊ธฐ์กด demotion ํ๊ฒ ์ ๋ถ ๋นํ์ฑํ
2. ๊ฐ ๋ฉ๋ชจ๋ฆฌ ๋ ธ๋์ ๋ํด:
- ํ์ฌ ๋ ธ๋์ tier์์ ์๋ tier์ ๋ ธ๋๋ฅผ ์ฐพ์
- find_next_best_node()๋ก ๊ฐ์ฅ ๊ฐ๊น์ด ๋์ ๋
ธ๋ ๊ฒฐ์
- ๊ฐ์ ๊ฑฐ๋ฆฌ์ ์ฌ๋ฌ ๋์์ ๋ชจ๋ preferred ๋ง์คํฌ์ ์ถ๊ฐ
3. CPU๊ฐ ์๋ tier๋ฅผ top tier๋ก ์ค์ (top_tier_adistance)
4. ๊ฐ tier์ lower_tier_mask ๊ตฌ์ถ โ ํ์ ํฐ์ด ์ ์ฒด ๋
ธ๋ ๋ง์คํฌ
5. next_demotion_node() โ ๋ค์ demotion ๋ ธ๋ ์กฐํ
/* mm/memory-tiers.c:330-374 */
int next_demotion_node(int node, const nodemask_t *allowed_mask)
์ญํ : ์ง์ ๋ ธ๋์์ ๋ค์ demotion ๋จ๊ณ๋ก ์ด๋ํ ๋์ ๋ ธ๋๋ฅผ ๋ฐํํฉ๋๋ค.
๋ถ๊ธฐ ๋ก์ง:
node_demotion ๋ฏธ์ด๊ธฐํ โ NUMA_NO_NODEpreferred์์ allowed_mask ๋ด ๋
ธ๋ ํ๋๋ฅผ ๋๋ค ์ ํfind_next_best_node()๋ก ๋์ฒด ๋์ ํ์6. numa_fill_memblks() โ ๋ฉ๋ชจ๋ฆฌ ๋ธ๋ก ๊ณต๋ฐฑ ์ฑ์ฐ๊ธฐ
/* mm/numa_memblks.c:509-557 */
int __init numa_fill_memblks(u64 start, u64 end)
์ญํ : ์ง์ ๋ ๋ฌผ๋ฆฌ ์ฃผ์ ๋ฒ์๋ฅผ ์ปค๋ฒํ๋๋ก ๊ธฐ์กด ๋ฉ๋ชจ๋ฆฌ ๋ธ๋ก์ ํ์ฅํ๊ฑฐ๋ ๊ณต๋ฐฑ์ ์ฑ์๋๋ค.
ํ๋ฆ:
1. start~end ๋ฒ์์ ๊ฒน์น๋ ๋ชจ๋ numa_memblk์ ํฌ์ธํฐ ๋ฆฌ์คํธ๋ก ์์ง
2. ์์ ์ฃผ์์์ผ๋ก ์ ๋ ฌ
3. ์ฒซ ๋ฒ์งธ/๋ง์ง๋ง ๋ธ๋ก์ ๊ฒฝ๊ณ๋ฅผ start/end๋ก ํ์ฅ
4. ์ธ์ ๋ธ๋ก ์ฌ์ด์ ๊ณต๋ฐฑ์ ๋ค์ชฝ ๋ธ๋ก์ start๋ฅผ ์๋น๊ฒจ์ ์ฑ์
7. memtier_hotplug_callback() โ ํซํ๋ฌ๊ทธ ์ฝ๋ฐฑ
/* mm/memory-tiers.c:881-904 */
static int __meminit memtier_hotplug_callback(struct notifier_block *self,
unsigned long action, void *_arg)
์ญํ : ๋ฉ๋ชจ๋ฆฌ ๋ ธ๋ ์ถ๊ฐ/์ ๊ฑฐ ์ ๋ฉ๋ชจ๋ฆฌ ํฐ์ด ๊ตฌ์กฐ๋ฅผ ์๋ ๊ฐฑ์ ํฉ๋๋ค.
๋ถ๊ธฐ ๋ก์ง:
NODE_ADDED_FIRST_MEMORY: ์ ๋
ธ๋์ set_node_memory_tier() ์ ์ฉ ํ establish_demotion_targets() ํธ์ถNODE_REMOVED_LAST_MEMORY: clear_node_memory_tier()๋ก ๋
ธ๋ ์ ๊ฑฐ ํ demotion ๋์ ์ฌ์ค์ ํธ์ถ ํ๋ฆ
๋ถํ
์ (arch/x86/kernel/acpi/numa.c ๋๋ DT ๊ธฐ๋ฐ)
โ
โโ numa_memblks_init(acpi_numa_init)
โ โโ ๋ฉ๋ชจ๋ฆฌ ๋ง์คํฌ ์ด๊ธฐํ
โ โโ acpi_numa_init() โ ACPI SRAT ํ์ฑ
โ โ โโ numa_set_distance(from, to, distance)
โ โ โโ numa_add_memblk(nid, start, end)
โ โโ numa_cleanup_meminfo()
โ โ โโ ๋ธ๋ก ํธ๋ฆฌ๋ฐ (DRAM ๋ฒ์ ์ ํ)
โ โ โโ ๊ฒน์น๋ ๋ธ๋ก ๋ณํฉ
โ โ โโ ์์ฝ ์์ญ ๋ถ๋ฆฌ
โ โโ numa_register_meminfo()
โ โโ memblock_set_node() โ memblock์ ๋
ธ๋ ๋งคํ
โ โโ numa_clear_kernel_node_hotplug()
โ โโ alloc_node_data(nid) โ pg_data_t ํ ๋น
โ
late_initcall โ memory_tier_late_init()
โ
โโ memory_tier_init() [subsys_initcall]
โ โโ subsys_virtual_register()
โ โโ node_demotion[] ํ ๋น
โ โโ default_dram_type ์์ฑ
โ
โโ memory_tier_late_init()
โ โโ ๋ฏธ์ด๊ธฐํ ๋
ธ๋์ set_node_memory_tier()
โ โ โโ mt_calc_adistance() โ ์ถ์ ๊ฑฐ๋ฆฌ ๊ณ์ฐ
โ โ โโ find_create_memory_tier() โ tier ์์ฑ/์ฐ๊ฒฐ
โ โโ establish_demotion_targets()
โ โโ disable_all_demotion_targets()
โ โโ ๊ฐ ๋
ธ๋๋ณ preferred/demotion ๋์ ๊ฒฐ์
โ โโ lower_tier_mask ๊ตฌ์ถ
โ
๋ฐํ์ โ ๋ฉ๋ชจ๋ฆฌ ํ์/demotion ์
โ
โโ next_demotion_node(node, allowed_mask)
โ โโ node_demotion[node].preferred์์ ์ ํ
โ โโ fallback: find_next_best_node()
โ
โโ numa_fill_memblks(start, end) โ ๋ฉ๋ชจ๋ฆฌ ๋ธ๋ก ๊ณต๋ฐฑ ์ฑ์ฐ๊ธฐ
โ โโ ๊ฒน์น๋ ๋ธ๋ก ํฌ์ธํฐ ๋ฆฌ์คํธ ์์ง
โ โโ ์์ ์ฃผ์์ ์ ๋ ฌ
โ โโ ๊ณต๋ฐฑ ์ฑ์ฐ๊ธฐ (์ธ์ ๋ธ๋ก start ์กฐ์ )
โ
โโ hotplug ์ฝ๋ฐฑ (memtier_hotplug_callback)
โโ NODE_ADDED_FIRST_MEMORY โ set_node_memory_tier()
โโ NODE_REMOVED_LAST_MEMORY โ clear_node_memory_tier()
์กฐ๊ฑด๋ณ ๋น๊ต
NUMA ์ด๊ธฐํ ๊ฒฝ๋ก ๋น๊ต
| ์กฐ๊ฑด | ์ด๊ธฐํ ํจ์ | ์์ค ์์น | ํน์ง |
|---|---|---|---|
| ACPI NUMA | `acpi_numa_init()` โ `numa_memblks_init()` | `arch/x86/kernel/acpi/numa.c` | SRAT/SLIT ํ ์ด๋ธ์์ ํ์ฑ. `numa_set_distance()` ํธ์ถ |
| Devicetree NUMA | `of_numa_init()` โ `numa_memblks_init()` | `drivers/of/of_numa.c` | DT์ `/numa` ๋ ธ๋์์ ํ์ฑ. ARM/RISC-V |
| NUMA ์๋ฎฌ๋ ์ด์ | `numa_emulation()` | `numa_memblks.c` | `numa=` ๋ถํ ํ๋ผ๋ฏธํฐ๋ก ๊ฐ์ NUMA ๊ตฌ์ฑ. ๋จ์ผ ์์ผ ์์คํ ํ ์คํธ์ฉ |
| ACPI ์คํจ ์ fallback | ๋๋ฏธ NUMA ์ด๊ธฐํ | `arch/x86/mm/numa.c` | ๋ชจ๋ ๋ฉ๋ชจ๋ฆฌ๋ฅผ node 0์ ๋ฐฐ์น |
๋ฉ๋ชจ๋ฆฌ ํฐ์ด๋ง ์๋๋ฆฌ์ค ๋น๊ต
| ์๋๋ฆฌ์ค | ๋ ธ๋ ๊ตฌ์ฑ | adistance | tier ๊ตฌ์กฐ | demotion ๋์ |
|---|---|---|---|---|
| ๋์ผ ์์ผ DRAM | Node 0,1 (DRAM) + Node 2,3 (PMEM) | DRAM: 576, PMEM: 704+ | tier0(DRAM) โ tier1(PMEM) | Node 0โ2, Node 1โ3 (๋ก์ปฌ PMEM ์ฐ์ ) |
| ๋ฉ๋ชจ๋ฆฌ ์ ์ฉ ๋ ธ๋ | Node 0,1 (CPU+DRAM) + Node 2 (DRAM only) | ๋ชจ๋ 576 | tier0(DRAM) | ์์ (๊ฐ์ ํฐ์ด) |
| HBM + DRAM + PMEM | Node 0 (CPU+HBM) + Node 1 (DRAM) + Node 2 (PMEM) | HBM: 320, DRAM: 576, PMEM: 704+ | tier0(HBM) โ tier1(DRAM) โ tier2(PMEM) | Node 0โ1โ2 ๊ณ๋จ์ |
pg_data_t ์ฃผ์ ํ๋ ๋น๊ต (NUMA ๊ด๋ จ)
| ํ๋ | ํ์ | ์ญํ | NUMA ์ํฅ |
|---|---|---|---|
| `node_zones[]` | `struct zone` | ์ด ๋ ธ๋์ ์กด ๋ฐฐ์ด | ๊ฐ ๋ ธ๋๋ง๋ค ๋ ๋ฆฝ์ |
| `node_zonelists[]` | `struct zonelist` | ํ ๋น ์ ์กด ํ์ ์์ | ์๊ฒฉ ๋ ธ๋ ํฌํจ |
| `node_start_pfn` | `unsigned long` | ์์ ๋ฌผ๋ฆฌ ํ๋ ์ ๋ฒํธ | ๋ ธ๋๋ณ ๋ฌผ๋ฆฌ ๋ฉ๋ชจ๋ฆฌ ๋ฒ์ |
| `node_present_pages` | `unsigned long` | ์ค์ ๋ฌผ๋ฆฌ ํ์ด์ง ์ | ๋ ธ๋๋ณ ํฌ๊ธฐ |
| `kswapd` | `task_struct *` | ํ์ด์ง ํ์ ์ค๋ ๋ | ๋ ธ๋๋ณ ๋ ๋ฆฝ ์คํ |
| `memtier` | `memory_tier __rcu *` | ๋ฉ๋ชจ๋ฆฌ ํฐ์ด | ๊ณ์ธต ์ด๋ ๊ธฐ๋ฐ |
NUMA ์ธ์ ํ ๋น API
์ปค๋์ NUMA ํ๊ฒฝ์์ ํน์ ๋ ธ๋์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ ๋นํ๋ API๋ฅผ ์ ๊ณตํฉ๋๋ค.
/* include/linux/gfp.h โ NUMA-aware ํ ๋น */
/* ํน์ ๋
ธ๋์์ ๋ฉ๋ชจ๋ฆฌ ํ ๋น */
struct page *alloc_pages_node(int nid, gfp_t gfp, unsigned int order);
/* ํน์ ๋
ธ๋์์ ์ปค๋ ๋ฉ๋ชจ๋ฆฌ ํ ๋น (Slab ์์์ ๋์) */
void *kmalloc_node(size_t size, gfp_t gfp, int node);
/* NUMA ์ ์ฑ
์ค์ (์ ์ ๊ณต๊ฐ) */
set_mempolicy(MPOL_BIND, &nodemask, maxnode); /* ์ง์ ๋
ธ๋์๋ง ํ ๋น */
set_mempolicy(MPOL_INTERLEAVE, &nodemask, maxnode); /* ๋
ธ๋ ๊ฐ ๊ต์ฐจ ํ ๋น */
alloc_pages_node(): NUMA ๋
ธ๋๋ฅผ ์ง์ ํ์ฌ Buddy Allocator์์ ์ง์ ํ ๋นkmalloc_node(): Slab ์บ์์์ NUMA ์ธ์ ํ ๋น, ๋ด๋ถ์ ์ผ๋ก __kmalloc_node() โ slab_alloc_node() ํธ์ถnumactl --membind=1 ./app ๋๋ set_mempolicy()๋ก NUMA ์ ์ฑ
์ง์ ๊ฐ๋ฅ์ถ์ ๊ฑฐ๋ฆฌ ๊ณ์ฐ (Abstract Distance)
๋ฉ๋ชจ๋ฆฌ ํฐ์ด๋ง ์์คํ ์ ๊ฐ ๋ฉ๋ชจ๋ฆฌ ์ ํ์ ์ถ์ ๊ฑฐ๋ฆฌ(adistance)๋ฅผ ๋ถ์ฌํ์ฌ ๊ณ์ธต์ ๊ฒฐ์ ํฉ๋๋ค.
์ถ์ ๊ฑฐ๋ฆฌ ๊ณต์
adistance = MEMTIER_ADISTANCE_DRAM ร (read_latency + write_latency) / base_latency ร base_bandwidth / (read_bandwidth + write_bandwidth)
MEMTIER_ADISTANCE_DRAM: ๊ธฐ๋ณธ DRAM ์ถ์ ๊ฑฐ๋ฆฌ (576)MEMTIER_CHUNK_SIZE: ํฐ์ด๋น ๊ฑฐ๋ฆฌ ๋ฒ์ (128)์ถ์ ๊ฑฐ๋ฆฌ ๋ฑ๋ก ์ฒด์ธ
์ปค๋์ ์ถ์ ๊ฑฐ๋ฆฌ ๊ณ์ฐ ์๊ณ ๋ฆฌ์ฆ์ notifier chain์ผ๋ก ๊ด๋ฆฌํฉ๋๋ค.
/* mm/memory-tiers.c:847-851 */
int register_mt_adistance_algorithm(struct notifier_block *nb)
{
return blocking_notifier_chain_register(&mt_adistance_algorithms, nb);
}
register_mt_adistance_algorithm()์ผ๋ก ์๊ณ ๋ฆฌ์ฆ ๋ฑ๋กmt_calc_adistance() ํธ์ถ ์ ์ฒด์ธ ์์๋๋ก ์๊ณ ๋ฆฌ์ฆ ์คํNOTIFY_STOP์ผ๋ก ์ค๋จNUMA ์๋ฎฌ๋ ์ด์
๋จ์ผ ์์ผ ์์คํ
์์๋ numa_emulation ๊ธฐ๋ฅ์ ํตํด ๊ฐ์ NUMA ๊ตฌ์ฑ์ ์๋ฎฌ๋ ์ด์
ํ ์ ์์ต๋๋ค.
๋ถํ ํ๋ผ๋ฏธํฐ
# 2๊ฐ์ ๊ฐ์ NUMA ๋
ธ๋ ์์ฑ (๊ฐ 512MB)
numa=fake=2@512M
# ํน์ ๋ฉ๋ชจ๋ฆฌ ๋ธ๋ก์ ํน์ ๋
ธ๋์ ๋ฐฐ์น
numa=force
numa_memmap=0x10000000@0x10000000 # 256MB~512MB๋ฅผ node 1์ ๋ฐฐ์น
๋์ ์๋ฆฌ
/* mm/numa_memblks.c:481 โ numa_emulation() ํธ์ถ ์์น */
numa_emulation(&numa_meminfo, numa_distance_cnt);
/* mm/numa_emulation.c:49-78 โ emu_setup_memblk() ํต์ฌ ๋ก์ง */
static int __init emu_setup_memblk(struct numa_meminfo *ei,
struct numa_meminfo *pi,
int nid, int phys_blk, u64 size)
{
struct numa_memblk *eb = &ei->blk[ei->nr_blks];
struct numa_memblk *pb = &pi->blk[phys_blk];
eb->start = pb->start;
eb->end = pb->start + size;
eb->nid = nid;
if (emu_nid_to_phys[nid] == NUMA_NO_NODE)
emu_nid_to_phys[nid] = pb->nid;
pb->start += size;
if (pb->start >= pb->end)
numa_remove_memblk_from(phys_blk, pi);
/* ... */
}
numa_memblks_init() ๋ง์ง๋ง ๋จ๊ณ์์ ํธ์ถsplit_nodes_interleave(): ๋ฌผ๋ฆฌ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ง์ ์๋งํผ ๊ท ๋ฑ ๋ถํ split_nodes_size(): ํน์ ํฌ๊ธฐ ๋จ์๋ก ๋ถํ emu_nid_to_phys[]: ๊ฐ์ ๋
ธ๋ ID โ ๋ฌผ๋ฆฌ ๋
ธ๋ ID ๋งคํ ๋ฐฐ์ด์ถ์ ๊ฑฐ๋ฆฌ notifier chain ์์ธ
์ปค๋์ ์ถ์ ๊ฑฐ๋ฆฌ ๊ณ์ฐ ์๊ณ ๋ฆฌ์ฆ์ blocking notifier chain์ผ๋ก ๊ด๋ฆฌํ์ฌ ๋๋ผ์ด๋ฒ๋ณ ํ์ฅ์ ์ง์ํฉ๋๋ค.
/* mm/memory-tiers.c:875-878 โ mt_calc_adistance() */
int mt_calc_adistance(int node, int *adist)
{
return blocking_notifier_call_chain(&mt_adistance_algorithms, node, adist);
}
์๊ณ ๋ฆฌ์ฆ ๋ฑ๋ก ํ๋ฆ:
1. ๋๋ผ์ด๋ฒ๊ฐ register_mt_adistance_algorithm(&nb)๋ก ์ฝ๋ฐฑ ๋ฑ๋ก
2. set_node_memory_tier() ํธ์ถ ์ mt_calc_adistance() ์คํ
3. ์ฒด์ธ ์์๋๋ก ์ฝ๋ฐฑ ํธ์ถ โ ๊ฒฐ๊ณผ ์ ๊ณต ์ NOTIFY_STOP ๋ฐํ
4. ๊ฒฐ๊ณผ๊ฐ ์์ผ๋ฉด ๊ธฐ๋ณธ๊ฐ(MEMTIER_ADISTANCE_DRAM) ์ฌ์ฉ
์๊ณ ๋ฆฌ์ฆ ์ฝ๋ฐฑ ์๊ทธ๋์ฒ:
/* include/linux/memory-tiers.h โ ์ฝ๋ฐฑ ํ๋กํ ํ์
*/
int (*algorithm_notifier)(struct notifier_block *nb,
unsigned long nid, void *data);
/* data๋ int *adist ํฌ์ธํฐ โ ์ฌ๊ธฐ์ ๊ฒฐ๊ณผ ๊ธฐ๋ก */
๋ฉ๋ชจ๋ฆฌ ํฐ์ด Hotplug ์ฝ๋ฐฑ
๋ฉ๋ชจ๋ฆฌ ๋ ธ๋๊ฐ ๋ฐํ์์ ์ถ๊ฐ/์ ๊ฑฐ๋ ๋ ๋ฉ๋ชจ๋ฆฌ ํฐ์ด ๊ตฌ์กฐ๋ฅผ ์๋ ๊ฐฑ์ ํฉ๋๋ค.
/* mm/memory-tiers.c:881-904 โ memtier_hotplug_callback() */
static int __meminit memtier_hotplug_callback(struct notifier_block *self,
unsigned long action, void *_arg)
{
struct node_notify *nn = _arg;
switch (action) {
case NODE_REMOVED_LAST_MEMORY:
mutex_lock(&memory_tier_lock);
if (clear_node_memory_tier(nn->nid))
establish_demotion_targets();
mutex_unlock(&memory_tier_lock);
break;
case NODE_ADDED_FIRST_MEMORY:
mutex_lock(&memory_tier_lock);
memtier = set_node_memory_tier(nn->nid);
if (!IS_ERR(memtier))
establish_demotion_targets();
mutex_unlock(&memory_tier_lock);
break;
}
return notifier_from_errno(0);
}
hotplug_node_notifier()๋ก ๋ฑ๋ก โ MEMTIER_HOTPLUG_PRI ์ฐ์ ์์NODE_ADDED_FIRST_MEMORY: ์ ๋
ธ๋์ set_node_memory_tier() ์ ์ฉ โ establish_demotion_targets() ํธ์ถNODE_REMOVED_LAST_MEMORY: clear_node_memory_tier()๋ก ๋
ธ๋ ์ ๊ฑฐ โ demotion ๋์ ์ฌ์ค์ clear_node_memory_tier()๋ synchronize_rcu()๋ก RCU ๋ณดํธ ํ์์ tier ํด์ ๋ฉ๋ชจ๋ฆฌ ์ ์ฑ (Memory Policy)
NUMA ์์คํ ์์ ์ปค๋๊ณผ ์ ์ ํ๋ก๊ทธ๋จ์ ๋ฉ๋ชจ๋ฆฌ ํ ๋น ์์น๋ฅผ ์ ์ดํ๋ ์ ์ฑ ์ ์ฌ์ฉํฉ๋๋ค.
| ์ ์ฑ | ๋์ | ์ฉ๋ |
|---|---|---|
| `MPOL_DEFAULT` (๊ธฐ๋ณธ) | ์คํ CPU์ ๋ก์ปฌ ๋ ธ๋์ ํ ๋น | ์ผ๋ฐ์ ์ธ ์ํฌ๋ก๋ |
| `MPOL_BIND` | ์ง์ ๋ ๋ ธ๋์๋ง ํ ๋น | DB ์๋ฒ, HPC โ ํน์ ๋ ธ๋ ๊ณ ์ |
| `MPOL_INTERLEAVE` | ๋ ธ๋ ๊ฐ ๋ผ์ด๋๋ก๋น ๊ต์ฐจ ํ ๋น | ๋์ฉ๋ ๊ณต์ ๋ฉ๋ชจ๋ฆฌ โ ๊ท ๋ฑ ๋ถ์ฐ |
| `MPOL_PREFERRED` | ์ ํธ ๋ ธ๋ ์ฐ์ , ๋ถ๊ฐ ์ ๋ค๋ฅธ ๋ ธ๋ | ์ ์ฐํ NUMA ์ ํธ๋ |
| `MPOL_LOCAL` | ๋ก์ปฌ ๋ ธ๋ ๊ฐ์ | ์ง์ฐ ์ต์ํ๊ฐ ์ค์ํ ์ํฌ๋ก๋ |
MPOL_BIND ์ฌ์ฉ ์ numactl --membind=0,1 ./app์ผ๋ก ์ฌ๋ฌ ๋
ธ๋ ์ง์ ๊ฐ๋ฅMPOL_INTERLEAVE๋ ๋ฉ๋ชจ๋ฆฌ ๋์ญํญ์ด ๊ท ๋ฑํ๊ฒ ํ์ํ ์ ํ๋ฆฌ์ผ์ด์
(์: ๋ํ ํด์ ํ
์ด๋ธ)์ ์ ์ฉMPOL_DEFAULT ํ๋ก์ธ์ค์ ํ์ด์ง๊ฐ ์๋์ผ๋ก ์ฌ๋ฐ๋ฅธ ๋
ธ๋๋ก ์ด๋AutoNUMA (NUMA Balancing)
์ปค๋ 3.13๋ถํฐ ๋์ ๋ ์๋ NUMA ๋ฐธ๋ฐ์ฑ์ ์ ๊ทผ ํจํด ๊ธฐ๋ฐ์ผ๋ก ํ์ด์ง๋ฅผ ์๋ ๋ง์ด๊ทธ๋ ์ด์ ํฉ๋๋ค.
๋์ ์๋ฆฌ:
1. ์ปค๋์ด ์ฃผ๊ธฐ์ ์ผ๋ก PTE๋ฅผ PROT_NONE์ผ๋ก ์ค์
2. ํ๋ก์ธ์ค๊ฐ ํด๋น ํ์ด์ง์ ์ ๊ทผํ๋ฉด NUMA ํํธ ํดํธ ๋ฐ์
3. ์ปค๋์ด ์ด๋ CPU๊ฐ ์ ๊ทผํ๋์ง ์ถ์
4. ์๊ฒฉ ๋ ธ๋์ ํ์ด์ง๋ฅผ ๋ก์ปฌ ๋ ธ๋๋ก ์๋ ๋ง์ด๊ทธ๋ ์ด์
5. ํ์คํฌ ์์ฒด๋ฅผ ๋ฐ์ดํฐ๊ฐ ์๋ ๋
ธ๋๋ก ์ด๋ (task_numa_placement())
ํ์ฑํ/๋นํ์ฑํ:
# AutoNUMA ํ์ฑํ ์ํ ํ์ธ
cat /proc/sys/kernel/numa_balancing
# ํ์ฑํ (๊ฐ: 2 = ์๋ ๋ฐธ๋ฐ์ฑ)
echo 2 > /proc/sys/kernel/numa_balancing
# NUMA ํํธ ํดํธ ํต๊ณ ํ์ธ
grep -E 'numa_pte_update|numa_hint_faults' /proc/vmstat
์ฃผ์: DB์ฒ๋ผ ๋ช ์์ NUMA binding์ ์ฌ์ฉํ๋ ์ ํ๋ฆฌ์ผ์ด์ ์์๋ AutoNUMA๋ฅผ ๋นํ์ฑํํ๋ ๊ฒ์ด ๋ฐ๋์งํฉ๋๋ค. ๋ช ์์ ์ ์ฑ ๊ณผ ์๋ ๋ฐธ๋ฐ์ฑ์ด ์ถฉ๋ํ ์ ์์ต๋๋ค.
NUMA ๋ฉ๋ชจ๋ฆฌ ์ ์ฑ / AutoNUMA ๋น๊ต
| ์ ์ฑ /๊ธฐ๋ฅ | ๋์ | ํ ๋น ์์น | ๋ง์ด๊ทธ๋ ์ด์ | ์ ํฉํ ์ํฌ๋ก๋ |
|---|---|---|---|---|
| `MPOL_DEFAULT` | ๋ก์ปฌ ๋ ธ๋ ์ฐ์ | ์คํ CPU์ ๋ก์ปฌ ๋ ธ๋ | AutoNUMA์ ์ํด ์๋ | ์ผ๋ฐ ์ฑ |
| `MPOL_BIND` | ์ง์ ๋ ธ๋ ์ ์ฉ | ์ง์ ๋ ๋ ธ๋๋ง | ์๋ `mbind()` | DB, HPC |
| `MPOL_INTERLEAVE` | ๋ ธ๋ ๊ฐ ๊ต์ฐจ | ๋ผ์ด๋๋ก๋น | ์์ | ๋ํ ๊ณต์ ๋ฉ๋ชจ๋ฆฌ |
| `MPOL_PREFERRED` | ์ ํธ ๋ ธ๋ ์ฐ์ | ์ ํธ ๋ ธ๋, ์์ผ๋ฉด ๋ก์ปฌ | ์์ | ์ ์ฐํ ์ ํธ๋ |
| AutoNUMA | PTE PROT_NONE ํธ๋ฆญ | ์ ๊ทผ ํจํด ๊ธฐ๋ฐ ์๋ | ์ปค๋ ์๋ ๋ง์ด๊ทธ๋ ์ด์ | ๋ฒ์ฉ ์ํฌ๋ก๋ |
| NUMA ๋นํ์ฑํ | `numa_balancing=0` | ์ ์ฑ /_scheduler ๊ฒฐ์ | ์์ | ์๋ NUMA ๊ณ ์ ์ฑ |
minzkn.com ๋น๊ต
์ฐธ๊ณ : minzkn.com์ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ ๊ฐ์ ํ์ด์ง ๋ด NUMA ๊ด๋ จ ์น์ ๊ณผ ๋น๊ตํฉ๋๋ค.
ํต์ฌ ๊ฐ๋ ๋น๊ต
| ํญ๋ชฉ | minzkn.com | ์ฐ๋ฆฌ ๋ฌธ์ | ์ํ |
|---|---|---|---|
| NUMA ๊ธฐ๋ณธ ๊ฐ๋ (๋ก์ปฌ/์๊ฒฉ) | โ "๊ฐ ์ง์ ์ ์์ฒด ์๊ฐ" ๋น์ | โ ๋์๊ด ์ฒด์ธ ๋น์ + ์์ค ์ฝ๋ | โ ๋ณด๊ฐ |
| Node/Zone/Page ๊ณ์ธต | โ 3๋จ๊ณ ๊ณ์ธต ์ค๋ช | โ `pg_data_t` ์์ค ๋ถ์ | โ ๋ณด๊ฐ |
| NUMA ๊ฑฐ๋ฆฌ ๋งคํธ๋ฆญ์ค | โ ACPI SLIT ์ธ๊ธ | โ `numa_set_distance()` ์ฝ๋ | โ ๋ณด๊ฐ |
| ํ๊ฒฝ๋ณ ์๋๋ฆฌ์ค | โ ๋ฒ ์ด๋ฉํ, ์๋ฒ ๋๋, NUMA, VM, ์ปจํ ์ด๋ | โ ์กฐ๊ฑด๋ณ ๋น๊ต ํ | โ ๋ณด๊ฐ |
| ๋ฉ๋ชจ๋ฆฌ ํฐ์ด๋ง | โ DRAM/PMEM/HBM ๊ณ์ธต | โ `memory_dev_type`, `adistance` ์ฝ๋ | โ ๋ณด๊ฐ |
| Memory Hotplug | โ ํซํ๋ฌ๊ทธ ๊ฐ๋ | โ `memtier_hotplug_callback` ์ฝ๋ | โ ๋ณด๊ฐ |
| NUMA ์๋ฎฌ๋ ์ด์ | โ ์์ | โ `numa_emulation.c` ๋ถ์ | โ ์ ๊ท |
| ์ถ์ ๊ฑฐ๋ฆฌ notifier chain | โ ์์ | โ `register_mt_adistance_algorithm` | โ ์ ๊ท |
| access_coordinate ๊ตฌ์กฐ์ฒด | โ ์์ | โ `include/linux/node.h` ๋ถ์ | โ ์ ๊ท |
ํ๊ฒฝ๋ณ NUMA ์๋๋ฆฌ์ค ๋น๊ต (minzkn.com ๊ธฐ๋ฐ ๋ณด๊ฐ)
| ํ๊ฒฝ | ๋ฉ๋ชจ๋ฆฌ๋งต ์ ๋ ฅ | ์ปค๋ ๋ด๋ถ ๋ณํ | ํ์ธ ๋ฐฉ๋ฒ | |
|---|---|---|---|---|
| ๋ฒ ์ด๋ฉํ x86_64 | ACPI SRAT/SLIT, E820/EFI | memblock โ Node/Zone โ zonelist | `numactl -H`, `/proc/iomem` | |
| ์๋ฒ ๋๋ ARM64 SoC | Device Tree `/memory` | DT ๊ธฐ๋ฐ NUMA ์ด๊ธฐํ | `ls /sys/firmware/devicetree/base/numa` | |
| ๋ํ NUMA ์๋ฒ | ACPI SRAT/HMAT, CXL | Node๋ณ pg_data_t, kswapd | `cat /sys/devices/system/node/node*/meminfo` | |
| KVM/QEMU VM | ๊ฐ์ง E820/EFI, virtio | ๊ฒ์คํธ ๋ฌผ๋ฆฌ ์ฃผ์ โ ํธ์คํธ 2๋จ๊ณ ๋ณํ | `dmesg | grep virtio` |
| ์ปจํ ์ด๋ | ํธ์คํธ ์ปค๋ ๊ณต์ , memcg | ๋ณ๋ ์ปค๋ ๋ฉ๋ชจ๋ฆฌ๋งต ์์ | `cat /sys/fs/cgroup/memory.numa_stat` | |
| CXL/PMEM/DAX | ACPI CEDT/CFMWS | ZONE_NORMAL ๋๋ ZONE_MOVABLE | `cat /proc/iomem`, `lsmem` |
์ถ๊ฐ ์ฐธ๊ณ : DDR5/HBM ํ๋์จ์ด ์ํฅ
minzkn.com์ DDR5/HBM ํ๋์จ์ด ๊ตฌ์กฐ์ NUMA ์ฑ๋ฅ์ ๊ด๊ณ๋ฅผ ๋ค๋ฃน๋๋ค:
| ํ๋์จ์ด | ํน์ง | NUMA ์ํฅ |
|---|---|---|
| DDR5 ์๋ธ์ฑ๋ | DIMM ๋ด๋ถ 32+32bit ๋ถํ | ์ฑ๋๋ณ NUMA ๊ฑฐ๋ฆฌ ์ฐจ์ด |
| HBM TSV ์ ์ธต | 1024๋นํธ ์์ด๋ ์ธํฐํ์ด์ค | ๊ทน๋๋ก ๋น ๋ฅธ ๋ก์ปฌ ์ ๊ทผ (Tier 0) |
| On-Die ECC | ์นฉ ๋ด๋ถ ์ค๋ฅ ๋ณดํธ | ์์คํ ECC์ ๋ณ๊ฐ โ ์ฑ๋ฅ ์ํฅ ์ต์ |