๐ŸŒ 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_SIZE128ํ‹ฐ์–ด๋‹น ์ถ”์ƒ ๊ฑฐ๋ฆฌ ๋ฒ”์œ„
MEMTIER_ADISTANCE_DRAM576๊ธฐ๋ณธ 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 ์ดˆ๊ธฐํ™” ์ „์ฒด ํ๋ฆ„

๋ฉ”๋ชจ๋ฆฌ ํ‹ฐ์–ด ๊ณ„์ธต ๊ตฌ์กฐ

๋ฉ”๋ชจ๋ฆฌ ํ‹ฐ์–ด ๊ณ„์ธต ๊ตฌ์กฐ & Demotion/Promotion ํ๋ฆ„

๋น ๋ฅธ ์ ๊ฒ€ ๋ช…๋ น

# 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_nodes
  • preferred: ๊ฐ™์€ ๊ฑฐ๋ฆฌ์˜ ์—ฌ๋Ÿฌ ๋Œ€์ƒ์ด ์žˆ์„ ๋•Œ ๋žœ๋ค ์„ ํƒ์šฉ
  • 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)๋กœ ๋ณ€ํ™˜
  • ๊ธฐ๋ณธ DRAM ์„ฑ๋Šฅ(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);
  • ์ง€์—ฐ์‹œ๊ฐ„์— ๋น„๋ก€ํ•˜๊ณ  ๋Œ€์—ญํญ์— ๋ฐ˜๋น„๋ก€ํ•˜์—ฌ ์ถ”์ƒ ๊ฑฐ๋ฆฌ ๊ณ„์‚ฐ
  • ๊ธฐ๋ณธ DRAM ๋Œ€๋น„ 10% ์ด์ƒ ์„ฑ๋Šฅ ์ฐจ์ด๊ฐ€ ๋‚˜๋ฉด 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_NODE
  • preferred์—์„œ allowed_mask ๋‚ด ๋…ธ๋“œ ํ•˜๋‚˜๋ฅผ ๋žœ๋ค ์„ ํƒ
  • preferred๊ฐ€ ์—†์œผ๋ฉด 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์— ๋ฐฐ์น˜

    ๋ฉ”๋ชจ๋ฆฌ ํ‹ฐ์–ด๋ง ์‹œ๋‚˜๋ฆฌ์˜ค ๋น„๊ต

    ์‹œ๋‚˜๋ฆฌ์˜ค๋…ธ๋“œ ๊ตฌ์„ฑadistancetier ๊ตฌ์กฐdemotion ๋Œ€์ƒ
    ๋“€์–ผ ์†Œ์ผ“ DRAMNode 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)๋ชจ๋‘ 576tier0(DRAM)์—†์Œ (๊ฐ™์€ ํ‹ฐ์–ด)
    HBM + DRAM + PMEMNode 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)
  • ์ž‘์„์ˆ˜๋ก ๋น ๋ฅธ ๋ฉ”๋ชจ๋ฆฌ (HBM < DRAM < PMEM)
  • ์ถ”์ƒ ๊ฑฐ๋ฆฌ ๋“ฑ๋ก ์ฒด์ธ

    ์ปค๋„์€ ์ถ”์ƒ ๊ฑฐ๋ฆฌ ๊ณ„์‚ฐ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ 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 ๋งคํ•‘ ๋ฐฐ์—ด
  • ํ…Œ์ŠคํŠธ/๋””๋ฒ„๊น…์šฉ โ€” ํ”„๋กœ๋•์…˜์—์„œ๋Š” ACPI SRAT ์‚ฌ์šฉ
  • ์ถ”์ƒ ๊ฑฐ๋ฆฌ 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๋Š” ๋ฉ”๋ชจ๋ฆฌ ๋Œ€์—ญํญ์ด ๊ท ๋“ฑํ•˜๊ฒŒ ํ•„์š”ํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜(์˜ˆ: ๋Œ€ํ˜• ํ•ด์‹œ ํ…Œ์ด๋ธ”)์— ์œ ์šฉ
  • AutoNUMA๊ฐ€ ํ™œ์„ฑํ™”๋˜๋ฉด 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`์„ ํ˜ธ ๋…ธ๋“œ ์šฐ์„ ์„ ํ˜ธ ๋…ธ๋“œ, ์—†์œผ๋ฉด ๋กœ์ปฌ์—†์Œ์œ ์—ฐํ•œ ์„ ํ˜ธ๋„
    AutoNUMAPTE 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_64ACPI SRAT/SLIT, E820/EFImemblock โ†’ Node/Zone โ†’ zonelist`numactl -H`, `/proc/iomem`
    ์ž„๋ฒ ๋””๋“œ ARM64 SoCDevice Tree `/memory`DT ๊ธฐ๋ฐ˜ NUMA ์ดˆ๊ธฐํ™”`ls /sys/firmware/devicetree/base/numa`
    ๋Œ€ํ˜• NUMA ์„œ๋ฒ„ACPI SRAT/HMAT, CXLNode๋ณ„ pg_data_t, kswapd`cat /sys/devices/system/node/node*/meminfo`
    KVM/QEMU VM๊ฐ€์งœ E820/EFI, virtio๊ฒŒ์ŠคํŠธ ๋ฌผ๋ฆฌ ์ฃผ์†Œ โ†’ ํ˜ธ์ŠคํŠธ 2๋‹จ๊ณ„ ๋ณ€ํ™˜`dmesggrep virtio`
    ์ปจํ…Œ์ด๋„ˆํ˜ธ์ŠคํŠธ ์ปค๋„ ๊ณต์œ , memcg๋ณ„๋„ ์ปค๋„ ๋ฉ”๋ชจ๋ฆฌ๋งต ์—†์Œ`cat /sys/fs/cgroup/memory.numa_stat`
    CXL/PMEM/DAXACPI CEDT/CFMWSZONE_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์™€ ๋ณ„๊ฐœ โ€” ์„ฑ๋Šฅ ์˜ํ–ฅ ์ตœ์†Œ

    ๊ด€๋ จ ๋ฌธ์„œ

  • ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ๊ฐœ์š” โ€” ์ „์ฒด ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ์กฐ๊ฐ๋„
  • Buddy Allocator โ€” NUMA ์ธ์‹ ๋ฌผ๋ฆฌ ํŽ˜์ด์ง€ ํ• ๋‹น
  • Migration โ€” ํŽ˜์ด์ง€ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜๊ณผ demotion์˜ ์‹ค์ œ ์‹คํ–‰์ฒด
  • ๋ฉ”๋ชจ๋ฆฌ Hotplug โ€” ๋Ÿฐํƒ€์ž„ ๋ฉ”๋ชจ๋ฆฌ ์ถ”๊ฐ€/์ œ๊ฑฐ
  • ๋ฉ”๋ชจ๋ฆฌ ํ‹ฐ์–ด๋ง โ€” ๋ฉ”๋ชจ๋ฆฌ ๊ณ„์ธต ๊ตฌ์กฐ์˜ ์‹ฌํ™” ๋ถ„์„