๏ปฟ# vmpressure ๐Ÿ“Š

๊ด€๋ จ ์†Œ์Šค: mm/vmpressure.c, include/linux/vmpressure.h, mm/vmscan.c, mm/memcontrol.c

๊ฐœ์š” (Overview)

vmpressure๋Š” Linux ์ปค๋„์˜ ๋ฉ”๋ชจ๋ฆฌ ์••๋ ฅ ์•Œ๋ฆผ ํ”„๋ ˆ์ž„์›Œํฌ๋กœ, vmscan ๋ฆฌํด๋ ˆ์ด๋จธ๊ฐ€ ์Šค์บ”/ํšŒ์ˆ˜ํ•œ ํŽ˜์ด์ง€ ๋น„์œจ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์‚ฌ์šฉ์ž ๊ณต๊ฐ„์— ๋ฉ”๋ชจ๋ฆฌ ์••๋ ฅ ์ˆ˜์ค€์„ ํ†ต๋ณดํ•ฉ๋‹ˆ๋‹ค. ๋ฆฌํด๋ ˆ์ด๋จธ๊ฐ€ ํŽ˜์ด์ง€๋ฅผ ๋งŽ์ด ์Šค์บ”ํ–ˆ์ง€๋งŒ ์ ๊ฒŒ ํšŒ์ˆ˜ํ•˜๋ฉด ๋ฉ”๋ชจ๋ฆฌ ์••๋ ฅ์ด ๋†’๋‹ค๋Š” ๋œป์ด๋ฉฐ, ์ด ์ •๋ณด๋ฅผ eventfd๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉ์ž ํ”„๋กœ์„ธ์Šค์— ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค. cgroup v2์—์„œ๋Š” ๋ชจ๋“  memcg์— ๋Œ€ํ•ด ๊ธฐ๋ณธ์œผ๋กœ ํ™œ์„ฑํ™”๋˜๋ฉฐ, PSI(Pressure Stall Information)์™€ ํ•จ๊ป˜ ๋ฉ”๋ชจ๋ฆฌ ์••๋ ฅ ๋ชจ๋‹ˆํ„ฐ๋ง์˜ ์ด์ค‘ ๊ฒฝ๋กœ๋ฅผ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค.

์ผ์ƒ ๋น„์œ : vmpressure๋Š” ์••๋ ฅ์†ฅ์˜ ์•ˆ์ „๋ฐธ๋ธŒ์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋ฐฅ์†ฅ ์•ˆ์˜ ์••๋ ฅ(๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰)์ด ์ผ์ • ์ˆ˜์ค€ ์ด์ƒ์œผ๋กœ ๋†’์•„์ง€๋ฉด ๋ฐธ๋ธŒ๊ฐ€ ์ž‘๋™ํ•˜์—ฌ ์‚ฌ์šฉ์ž์—๊ฒŒ "์••๋ ฅ์ด ๋†’์•„์ง€๊ณ  ์žˆ๋‹ค"๊ณ  ์•Œ๋ ค์ค๋‹ˆ๋‹ค. low๋Š” ์ฆ๊ธฐ๊ฐ€ ์‚ด์ง ๋‚˜๊ธฐ ์‹œ์ž‘ํ•  ๋•Œ, medium์€ ๋ณธ๊ฒฉ์ ์œผ๋กœ ๊น€์ด ๋‚  ๋•Œ, critical์€ ํ„ฐ์ง€๊ธฐ ์ง์ „์˜ ์œ„ํ—˜ ์ˆ˜์ค€์ž…๋‹ˆ๋‹ค.

vmpressure๋Š” ์„ธ ๊ฐ€์ง€ ์••๋ ฅ ์ˆ˜์ค€(low/medium/critical)๊ณผ ์„ธ ๊ฐ€์ง€ ์•Œ๋ฆผ ๋ชจ๋“œ(default/hierarchy/local)๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์Šค์บ”/ํšŒ์ˆ˜ ๋น„์œจ ๊ณ„์‚ฐ์€ SWAP_CLUSTER_MAX * 16 ์œˆ๋„์šฐ(๊ธฐ๋ณธ 512ํŽ˜์ด์ง€ โ‰ˆ 2MB)์—์„œ ์ˆ˜ํ–‰๋˜๋ฉฐ, ๋ฆฌํด๋ ˆ์ด๋จธ์˜ ์Šค์บ” ์šฐ์„ ์ˆœ์œ„(prio) ๋ณ€ํ™”๋ฅผ ๊ฐ์ง€ํ•˜์—ฌ critical ๋ ˆ๋ฒจ์„ ๋ณด์กฐ์ ์œผ๋กœ ํƒ์ง€ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฌธ์„œ์—์„œ๋Š” vmpressure์˜ ํ•ต์‹ฌ ์ž๋ฃŒ๊ตฌ์กฐ, ์•Œ๊ณ ๋ฆฌ์ฆ˜, ์•Œ๋ฆผ ๋ฉ”์ปค๋‹ˆ์ฆ˜, memcg ํ†ตํ•ฉ์„ ๋ถ„์„ํ•ฉ๋‹ˆ๋‹ค.

์†Œ์Šค ํŒŒ์ผ ๊ฒฝ๋กœ

mm/vmpressure.c                 โ† ๋ฉ”์ธ ๊ตฌํ˜„ (481์ค„)
include/linux/vmpressure.h      โ† struct vmpressure, API ์„ ์–ธ (52์ค„)
mm/vmscan.c                     โ† vmpressure() ํ˜ธ์ถœ ์ง€์  (4๊ณณ)
mm/memcontrol.c                 โ† memcg_to_vmpressure(), ์ดˆ๊ธฐํ™”/์ •๋ฆฌ
mm/memcontrol-v1.c              โ† cgroup v1 ์ด๋ฒคํŠธ ๋“ฑ๋ก

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

# 1. vmpressure ๊ด€๋ จ ์ปค๋„ ์‹ฌ๋ณผ ํ™•์ธ
cat /proc/kallsyms | grep -E "vmpressure|memcg_to_vmpressure"

# 2. memcg ์ด๋ฒคํŠธ vmpressure ๋“ฑ๋ก ์—ฌ๋ถ€ ํ™•์ธ
ls /sys/fs/cgroup/memory/*.event 2>/dev/null; cat /sys/fs/cgroup/cgroup.events 2>/dev/null

# 3. vmpressure ์ž„๊ณ„๊ฐ’ ํ™•์ธ (์ปค๋„ ์ƒ์ˆ˜)
cat /proc/kallsyms | grep -E "vmpressure_level_med|vmpressure_level_critical"

# 4. PSI ํ†ต๊ณ„์™€ vmpressure ๋น„๊ต
cat /proc/pressure/memory

# 5. vmscan์—์„œ vmpressure ํ˜ธ์ถœ๋ถ€ grep
grep -rn "vmpressure\b" mm/vmscan.c

# 6. memcg vmpressure ์ดˆ๊ธฐํ™” ํ™•์ธ
grep -rn "vmpressure_init\|vmpressure_cleanup" mm/memcontrol.c

# 7. cgroup v1 vs v2 ์ด๋ฒคํŠธ ๋ฉ”์ปค๋‹ˆ์ฆ˜ ๋น„๊ต
grep -rn "vmpressure_register_event\|vmpressure_unregister_event" mm/

# 8. vmpressure ์œˆ๋„์šฐ ํฌ๊ธฐ ํ™•์ธ (SWAP_CLUSTER_MAX * 16)
cat /proc/kallsyms | grep -E "vmpressure_win"

# 9. cgroup v2 memory ์ด๋ฒคํŠธ ํŒŒ์ผ ํ™•์ธ
ls /sys/fs/cgroup/*.events 2>/dev/null | head -5

# 10. ์Šค์บ” ์šฐ์„ ์ˆœ์œ„ ์ž„๊ณ„๊ฐ’ ํ™•์ธ (prio โ‰ค 3 = LRU 12.5% ์Šค์บ”)
cat /proc/kallsyms | grep -E "vmpressure_level_critical_prio"

# 11. vmscan.c์—์„œ proactive ํ”Œ๋ž˜๊ทธ์™€ ํ•จ๊ป˜ vmpressure ํ˜ธ์ถœ ์—ฌ๋ถ€ ํ™•์ธ
grep -n "proactive.*vmpressure\|vmpressure.*proactive" mm/vmscan.c

# 12. mem_cgroup_set_socket_pressure() ํ˜ธ์ถœ๋ถ€ ํ™•์ธ
grep -rn "socket_pressure" mm/memcontrol.c

ํ•ต์‹ฌ ์ž๋ฃŒ๊ตฌ์กฐ

struct vmpressure

memcg๋‹น ํ•˜๋‚˜์˜ vmpressure ๊ตฌ์กฐ์ฒด๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ์Šค์บ”/ํšŒ์ˆ˜ ์นด์šดํ„ฐ์™€ ์ด๋ฒคํŠธ ์•Œ๋ฆผ ๋ฆฌ์ŠคํŠธ๋ฅผ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

// include/linux/vmpressure.h:13-28
struct vmpressure {
	/* ๋ ˆ๊ฑฐ์‹œ cgroup ๋ชจ๋“œ (tree=true)์šฉ ์Šค์บ”/ํšŒ์ˆ˜ ์นด์šดํ„ฐ */
	unsigned long scanned;          /* memcg ์ž์ฒด ์Šค์บ” ํŽ˜์ด์ง€ ์ˆ˜ */
	unsigned long reclaimed;        /* memcg ์ž์ฒด ํšŒ์ˆ˜ ํŽ˜์ด์ง€ ์ˆ˜ */

	/* ํŠธ๋ฆฌ ์ „์ฒด ํ†ตํ•ฉ ๋ชจ๋“œ (tree=true)์šฉ ์นด์šดํ„ฐ */
	unsigned long tree_scanned;     /* ์„œ๋ธŒํŠธ๋ฆฌ ์ „์ฒด ์Šค์บ” ํŽ˜์ด์ง€ ์ˆ˜ */
	unsigned long tree_reclaimed;   /* ์„œ๋ธŒํŠธ๋ฆฌ ์ „์ฒด ํšŒ์ˆ˜ ํŽ˜์ด์ง€ ์ˆ˜ */

	spinlock_t sr_lock;             /* scanned/reclaimed ๋™๊ธฐํ™” ๋ฝ */

	struct list_head events;        /* vmpressure_event ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ */
	struct mutex events_lock;       /* ์ด๋ฒคํŠธ ๋ฆฌ์ŠคํŠธ ๋ณดํ˜ธ ๋ฎคํ…์Šค */

	struct work_struct work;        /* ์ง€์—ฐ๋œ ์ด๋ฒคํŠธ ์•Œ๋ฆผ ์›Œํฌํ ์ž‘์—… */
};

struct vmpressure_event

์‚ฌ์šฉ์ž๊ฐ€ eventfd๋ฅผ ํ†ตํ•ด ๋“ฑ๋กํ•œ ์•Œ๋ฆผ ๊ตฌ๋…์ž…๋‹ˆ๋‹ค. memcg์˜ memory.pressure_level ์ธํ„ฐํŽ˜์ด์Šค์™€ ์—ฐ๋™๋ฉ๋‹ˆ๋‹ค.

// mm/vmpressure.c:150-155
struct vmpressure_event {
	struct eventfd_ctx *efd;        /* ์•Œ๋ฆผ ๋Œ€์ƒ eventfd ์ปจํ…์ŠคํŠธ */
	enum vmpressure_levels level;  /* ํŠธ๋ฆฌ๊ฑฐ ์ตœ์†Œ ์••๋ ฅ ์ˆ˜์ค€ */
	enum vmpressure_modes mode;    /* ์•Œ๋ฆผ ์ „ํŒŒ ๋ชจ๋“œ */
	struct list_head node;         /* vmpressure.events ์—ฐ๊ฒฐ ๋…ธ๋“œ */
};

enum vmpressure_levels

์••๋ ฅ ์ˆ˜์ค€์€ ์Šค์บ”/ํšŒ์ˆ˜ ๋น„์œจ์— ๋”ฐ๋ผ ์„ธ ๋‹จ๊ณ„๋กœ ๋ถ„๋ฅ˜๋ฉ๋‹ˆ๋‹ค.

// mm/vmpressure.c:85-90
enum vmpressure_levels {
	VMPRESSURE_LOW = 0,      /* ํšŒ์ˆ˜ ํšจ์œจ ์–‘ํ˜ธ (< 60%) */
	VMPRESSURE_MEDIUM,       /* ์ฃผ์˜ ์ˆ˜์ค€ (โ‰ฅ 60%) */
	VMPRESSURE_CRITICAL,     /* ์œ„ํ—˜ ์ˆ˜์ค€ (โ‰ฅ 95%) */
	VMPRESSURE_NUM_LEVELS,
};

enum vmpressure_modes

์•Œ๋ฆผ ๋ชจ๋“œ๋Š” ์ด๋ฒคํŠธ์˜ ์ „ํŒŒ ๋ฒ”์œ„๋ฅผ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค.

// mm/vmpressure.c:92-97
enum vmpressure_modes {
	VMPRESSURE_NO_PASSTHROUGH = 0, /* ๊ธฐ๋ณธ: ํ˜„์žฌ memcg๋งŒ ์•Œ๋ฆผ */
	VMPRESSURE_HIERARCHY,          /* ์ƒ์œ„ memcg๋กœ ์•Œ๋ฆผ ์ „ํŒŒ */
	VMPRESSURE_LOCAL,              /* ๋กœ์ปฌ: ์กฐ์ƒ์€ ์•Œ๋ฆผ ๋ฌด์‹œ */
	VMPRESSURE_NUM_MODES,
};

์••๋ ฅ ์ž„๊ณ„๊ฐ’ ์ƒ์ˆ˜

// mm/vmpressure.c:38,46-47,68
static const unsigned long vmpressure_win = SWAP_CLUSTER_MAX * 16;  /* ์œˆ๋„์šฐ: 512ํŽ˜์ด์ง€ โ‰ˆ 2MB */
static const unsigned int vmpressure_level_med = 60;                /* medium ์ž„๊ณ„๊ฐ’ */
static const unsigned int vmpressure_level_critical = 95;           /* critical ์ž„๊ณ„๊ฐ’ */
static const unsigned int vmpressure_level_critical_prio = ilog2(100 / 10); /* prio โ‰ค 3 */

ํ•ต์‹ฌ ํ•จ์ˆ˜

vmpressure() โ€” ์Šค์บ”/ํšŒ์ˆ˜ ๋น„์œจ ๊ธฐ๋ฐ˜ ์••๋ ฅ ๊ณ„์‚ฐ (๋ฉ”์ธ ์—”ํŠธ๋ฆฌ)

vmscan ๋ฆฌํด๋ ˆ์ด๋จธ๊ฐ€ ๊ฐ ํšŒ์ˆ˜ ์‚ฌ์ดํด์—์„œ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ๋‘ ๊ฐ€์ง€ ๊ฒฝ๋กœ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

// mm/vmpressure.c:239-322
void vmpressure(gfp_t gfp, struct mem_cgroup *memcg, bool tree,
		unsigned long scanned, unsigned long reclaimed)
{
	/* memcg ๋น„ํ™œ์„ฑํ™” ์‹œ ๋ฌด์‹œ */
	if (mem_cgroup_disabled())
		return;

	/* cgroup v1 legacy ๋ชจ๋“œ์—์„œ tree=false๋Š” ๋ฌด์‹œ (์ธ_kernel ์‚ฌ์šฉ์ž ์—†์Œ) */
	if (!cgroup_subsys_on_dfl(memory_cgrp_subsys) && !tree)
		return;

	vmpr = memcg_to_vmpressure(memcg);

	/* DMA ๋“ฑ ์‚ฌ์šฉ์ž ๋„์›€์ด ๋ถˆ๊ฐ€๋Šฅํ•œ ์˜์—ญ์˜ ์••๋ ฅ์€ ๋ฌด์‹œ */
	if (!(gfp & (__GFP_HIGHMEM | __GFP_MOVABLE | __GFP_IO | __GFP_FS)))
		return;

	/* ์Šค์บ”๋œ ํŽ˜์ด์ง€๊ฐ€ 0์ด๋ฉด ์•„์ง ์•ˆ์ •์  (prio ์ƒ์Šน ์‹œ ์žฌํ˜ธ์ถœ๋จ) */
	if (!scanned)
		return;

	if (tree) {
		/* tree ๋ชจ๋“œ: ์„œ๋ธŒํŠธ๋ฆฌ ์ „์ฒด ํ†ตํ•ฉ โ†’ ์›Œํฌํ์—์„œ ์ง€์—ฐ ์•Œ๋ฆผ */
		spin_lock(&vmpr->sr_lock);
		scanned = vmpr->tree_scanned += scanned;
		vmpr->tree_reclaimed += reclaimed;
		spin_unlock(&vmpr->sr_lock);

		if (scanned < vmpressure_win)
			return;
		schedule_work(&vmpr->work);  /* ์œˆ๋„์šฐ ๋„๋‹ฌ ์‹œ ์›Œํฌํ ์Šค์ผ€์ค„ */
	} else {
		/* non-tree ๋ชจ๋“œ: ์ธ_kernel ์•Œ๋ฆผ (์†Œ์ผ“ ํ• ๋‹น๊ธฐ ๋“ฑ) */
		if (!memcg || mem_cgroup_is_root(memcg))
			return;

		spin_lock(&vmpr->sr_lock);
		scanned = vmpr->scanned += scanned;
		reclaimed = vmpr->reclaimed += reclaimed;
		if (scanned < vmpressure_win) {
			spin_unlock(&vmpr->sr_lock);
			return;
		}
		vmpr->scanned = vmpr->reclaimed = 0;
		spin_unlock(&vmpr->sr_lock);

		level = vmpressure_calc_level(scanned, reclaimed);
		if (level > VMPRESSURE_LOW)
			mem_cgroup_set_socket_pressure(memcg);
	}
}

๋ถ„๊ธฐ ๋กœ์ง:

1. cgroup_subsys_on_dfl() โ†’ cgroup v2์ด๋ฉด ๋ชจ๋“  ๋ชจ๋“œ ํ—ˆ์šฉ, v1์ด๋ฉด tree=true๋งŒ ํ—ˆ์šฉ

2. GFP ํ”Œ๋ž˜๊ทธ ๊ฒ€์‚ฌ โ†’ DMA ์ „์šฉ ํŽ˜์ด์ง€ ํšŒ์ˆ˜ ์‹œ ์‚ฌ์šฉ์ž ์•Œ๋ฆผ ๋ถˆํ•„์š”

3. tree ํ”Œ๋ž˜๊ทธ โ†’ tree ๋ชจ๋“œ: ์›Œํฌํ ์ง€์—ฐ ์•Œ๋ฆผ, non-tree: ์ฆ‰์‹œ ์†Œ์ผ“ ์•Œ๋ฆผ

vmpressure_prio() โ€” ์Šค์บ” ์šฐ์„ ์ˆœ์œ„ ๊ธฐ๋ฐ˜ critical ํƒ์ง€

๋ฆฌํด๋ ˆ์ด๋จธ์˜ ์Šค์บ” ๊นŠ์ด๊ฐ€ ๊ธฐ์ค€ ์ดํ•˜๋กœ ๋‚ด๋ ค๊ฐ€๋ฉด critical์„ ๊ฐ•์ œํ•ฉ๋‹ˆ๋‹ค.

// mm/vmpressure.c:335-352
void vmpressure_prio(gfp_t gfp, struct mem_cgroup *memcg, int prio)
{
	/* prio > 3์ด๋ฉด ์•„์ง ์ถฉ๋ถ„ํžˆ ๊นŠ์ด ์Šค์บ”ํ•˜์ง€ ์•Š์Œ โ€” ๋ฌด์‹œ */
	if (prio > vmpressure_level_critical_prio)
		return;

	/* prio โ‰ค 3์ด๋ฉด LRU์˜ ์•ฝ 12.5% ์Šค์บ” โ†’ critical ๊ฐ•์ œ ์•Œ๋ฆผ */
	vmpressure(gfp, memcg, true, vmpressure_win, 0);
}

์ฐธ๊ณ : vmpressure_level_critical_prio = ilog2(10) = 3. ๋ฆฌํด๋ ˆ์ด๋จธ๋Š” lru_size >> prio ํŽ˜์ด์ง€๋ฅผ ์Šค์บ”ํ•˜๋ฏ€๋กœ, prio=3์ด๋ฉด LRU์˜ 12.5%๋ฅผ ์Šค์บ”ํ•œ ์…ˆ์ž…๋‹ˆ๋‹ค.

vmpressure_calc_level() โ€” ์Šค์บ”/ํšŒ์ˆ˜ ๋น„์œจ ๊ณ„์‚ฐ

์••๋ ฅ ํผ์„ผํŠธ๋ฅผ ๊ณ„์‚ฐํ•˜๊ณ  ์ˆ˜์ค€์„ ํŒ์ •ํ•ฉ๋‹ˆ๋‹ค.

// mm/vmpressure.c:120-148
static enum vmpressure_levels vmpressure_calc_level(unsigned long scanned,
						    unsigned long reclaimed)
{
	unsigned long scale = scanned + reclaimed;
	unsigned long pressure = 0;

	/* slab ๋“ฑ์—์„œ reclaimed > scanned ๊ฐ€๋Šฅ โ€” ์ด ๊ฒฝ์šฐ pressure = 0 */
	if (reclaimed >= scanned)
		goto out;

	/* ์••๋ ฅ = (์Šค์บ”๋œ ๊ฒƒ ์ค‘ ํšŒ์ˆ˜ ์‹คํŒจํ•œ ๋น„์œจ) ร— 100 */
	pressure = scale - (reclaimed * scale / scanned);
	pressure = pressure * 100 / scale;

out:
	return vmpressure_level(pressure);  /* 60/95 ์ž„๊ณ„๊ฐ’์œผ๋กœ ํŒ์ • */
}

vmpressure_work_fn() โ€” ์ง€์—ฐ๋œ ์ด๋ฒคํŠธ ์•Œ๋ฆผ ์ฒ˜๋ฆฌ

์›Œํฌํ์—์„œ ์‹คํ–‰๋˜๋ฉฐ, ์œˆ๋„์šฐ ๋„๋‹ฌ ํ›„ ์ƒ์œ„ memcg๊นŒ์ง€ ์ „ํŒŒํ•ฉ๋‹ˆ๋‹ค.

// mm/vmpressure.c:180-216
static void vmpressure_work_fn(struct work_struct *work)
{
	struct vmpressure *vmpr = work_to_vmpressure(work);

	spin_lock(&vmpr->sr_lock);
	scanned = vmpr->tree_scanned;
	if (!scanned) {
		spin_unlock(&vmpr->sr_lock);
		return;
	}
	reclaimed = vmpr->tree_reclaimed;
	vmpr->tree_scanned = 0;      /* ์นด์šดํ„ฐ ์ดˆ๊ธฐํ™” */
	vmpr->tree_reclaimed = 0;
	spin_unlock(&vmpr->sr_lock);

	level = vmpressure_calc_level(scanned, reclaimed);

	/* ํ˜„์žฌ memcg โ†’ ๋ถ€๋ชจ memcg ์ˆœ์„œ๋กœ ์ด๋ฒคํŠธ ์ „ํŒŒ */
	do {
		if (vmpressure_event(vmpr, level, ancestor, signalled))
			signalled = true;
		ancestor = true;       /* ์ดํ›„ ๋ฐ˜๋ณต๋ถ€ํ„ฐ๋Š” ancestor=true */
	} while ((vmpr = vmpressure_parent(vmpr)));
}

vmpressure_register_event() โ€” eventfd ์•Œ๋ฆผ ๊ตฌ๋… ๋“ฑ๋ก

cgroup์˜ memory.pressure_level ์ธํ„ฐํŽ˜์ด์Šค์—์„œ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.

// mm/vmpressure.c:374-422
int vmpressure_register_event(struct mem_cgroup *memcg,
			      struct eventfd_ctx *eventfd, const char *args)
{
	/* args ํŒŒ์‹ฑ: "critical,hierarchy" ๊ฐ™์€ ์‰ผํ‘œ ๊ตฌ๋ถ„ ๋ฌธ์ž์—ด */
	token = strsep(&spec, ",");
	level = match_string(vmpressure_str_levels, VMPRESSURE_NUM_LEVELS, token);

	token = strsep(&spec, ",");
	if (token)
		mode = match_string(vmpressure_str_modes, VMPRESSURE_NUM_MODES, token);

	ev = kzalloc_obj(*ev);
	ev->efd = eventfd;
	ev->level = level;
	ev->mode = mode;

	mutex_lock(&vmpr->events_lock);
	list_add(&ev->node, &vmpr->events);
	mutex_unlock(&vmpr->events_lock);
}

vmpressure ํ˜ธ์ถœ ํ๋ฆ„
vmpressure ์ž๋ฃŒ๊ตฌ์กฐ ๊ด€๊ณ„๋„

ํ˜ธ์ถœ ํ๋ฆ„

[์‚ฌ์šฉ์ž็ฉบ้—ด] epoll_wait() / eventfd_read()
โ†‘ eventfd_signal()
[์ปค๋„: ์ด๋ฒคํŠธ ์•Œ๋ฆผ]
vmpressure_event()
โ† vmpressure_work_fn()     โ† schedule_work() โ† vmpressure(tree=true)
โ† vmpressure() non-tree    โ† mem_cgroup_set_socket_pressure()

[์ปค๋„: ๋ฆฌํด๋ ˆ์ด ๊ฒฝ๋กœ โ€” MGLRU]
vmscan.c: shrink_one() (L4931)
โ””โ”€ vmpressure(gfp, memcg, false, scanned, reclaimed)   โ† non-tree ์•Œ๋ฆผ

[์ปค๋„: ๋ฆฌํด๋ ˆ์ด ๊ฒฝ๋กœ โ€” ๊ธฐ์กด LRU]
vmscan.c: shrink_node_memcgs() (L6027)
โ””โ”€ vmpressure(gfp, memcg, false, scanned, reclaimed)   โ† non-tree ์•Œ๋ฆผ
vmscan.c: shrink_node() (L6069)
โ””โ”€ vmpressure(gfp, memcg, true, scanned, reclaimed)    โ† tree ์•Œ๋ฆผ

[์ปค๋„: ์šฐ์„ ์ˆœ์œ„ ๋ณ€ํ™” ๊ฐ์ง€]
vmscan.c: do_try_to_free_pages() (L6359)
โ””โ”€ vmpressure_prio(gfp, memcg, prio)
โ””โ”€ vmpressure(gfp, memcg, true, vmpressure_win, 0)

[์ดˆ๊ธฐํ™”/์ •๋ฆฌ]
memcontrol.c: mem_cgroup_css_alloc() (L3792)
โ””โ”€ vmpressure_init(&memcg->vmpressure)
โ””โ”€ INIT_WORK(&vmpr->work, vmpressure_work_fn)
memcontrol.c: mem_cgroup_css_free() (L3967)
โ””โ”€ vmpressure_cleanup(&memcg->vmpressure)
โ””โ”€ flush_work(&vmpr->work)

์กฐ๊ฑด๋ณ„ ๋น„๊ต

์••๋ ฅ ์ˆ˜์ค€ ํŒ์ • ๊ธฐ์ค€

์ˆ˜์ค€์Šค์บ”/ํšŒ์ˆ˜ ๋น„์œจ์˜๋ฏธ์‚ฌ์šฉ์ž ์•Œ๋ฆผ
`LOW`< 60% ํšŒ์ˆ˜ ์‹คํŒจ๋ฆฌํด๋ ˆ์ด๋จธ๊ฐ€ ์ถฉ๋ถ„ํžˆ ํšŒ์ˆ˜ ์ค‘์•Œ๋ฆผ ์—†์Œ
`MEDIUM`60%~95% ํšŒ์ˆ˜ ์‹คํŒจ๋ฉ”๋ชจ๋ฆฌ ํ™•๋ณด ์–ด๋ ค์›€ ์‹œ์ž‘eventfd ์‹ ํ˜ธ
`CRITICAL`โ‰ฅ 95% ํšŒ์ˆ˜ ์‹คํŒจ ๋˜๋Š” prio โ‰ค 3๋ฉ”๋ชจ๋ฆฌ ๋ถ€์กฑ ์ž„๋ฐ•eventfd ์‹ ํ˜ธ

์•Œ๋ฆผ ๋ชจ๋“œ ๋น„๊ต

๋ชจ๋“œํ˜„์žฌ memcg๋ถ€๋ชจ memcg์šฉ๋„
`default` (NO_PASSTHROUGH)์•Œ๋ฆผ์•Œ๋ฆผ (signalled=false์ผ ๋•Œ๋งŒ)์ผ๋ฐ˜ ์‚ฌ์šฉ์ž ์•ฑ
`hierarchy`์•Œ๋ฆผ์•Œ๋ฆผ (์กฐ์ƒ๋„)๊ณ„์ธต์  ๋ชจ๋‹ˆํ„ฐ๋ง
`local`์•Œ๋ฆผ๋ฌด์‹œํŠน์ • memcg๋งŒ ์ถ”์ 

tree ๋ชจ๋“œ vs non-tree ๋ชจ๋“œ

ํ•ญ๋ชฉtree=truetree=false
๋Œ€์ƒcgroup subtree ์ „์ฒด๋‹จ์ผ memcg
์นด์šดํ„ฐ`tree_scanned/reclaimed``scanned/reclaimed`
์•Œ๋ฆผ ๋ฐฉ์‹์›Œํฌํ ์ง€์—ฐ (์œˆ๋„์šฐ ๋„๋‹ฌ ํ›„)์ฆ‰์‹œ ๊ณ„์‚ฐ
์‚ฌ์šฉ์ž ์•Œ๋ฆผeventfd ์‹œ๊ทธ๋„`mem_cgroup_set_socket_pressure()`
cgroup ๋ฒ„์ „v1, v2 ๋ชจ๋‘v2๋งŒ
ํ˜ธ์ถœ ์ง€์ `shrink_node()` (tree ๊ฒฝ๋กœ)`shrink_one()`, `shrink_node_memcgs()` (๋น„-ํŠธ๋ฆฌ ๊ฒฝ๋กœ)

vmscan ํ˜ธ์ถœ ์ง€์ 

ํŒŒ์ผ:๋ผ์ธํ˜ธ์ถœ ํ•จ์ˆ˜๋ชจ๋“œํ˜ธ์ถœ ์ปจํ…์ŠคํŠธ
`vmscan.c:4931``vmpressure()``false` (non-tree)`shrink_one()` โ€” MGLRU ๊ฒฝ๋กœ
`vmscan.c:6027``vmpressure()``false` (non-tree)`shrink_node_memcgs()` โ€” ๊ธฐ์กด LRU ๊ฒฝ๋กœ
`vmscan.c:6069``vmpressure()``true` (tree)`shrink_node()` โ€” ์„œ๋ธŒํŠธ๋ฆฌ ์ „์ฒด
`vmscan.c:6359``vmpressure_prio()``true``do_try_to_free_pages()` โ€” ์šฐ์„ ์ˆœ์œ„ ๋ณ€ํ™”

cgroup v1 vs v2 ๋™์ž‘ ๋น„๊ต

ํ•ญ๋ชฉcgroup v1cgroup v2
tree=true ํ˜ธ์ถœํ—ˆ์šฉํ—ˆ์šฉ
tree=false ํ˜ธ์ถœ๋ฌด์‹œ (`!cgroup_subsys_on_dfl()` ์ฒดํฌ)ํ—ˆ์šฉ
์ด๋ฒคํŠธ ๋“ฑ๋ก`memory.pressure_level` (๋ณ„๋„)`memory.pressure_level` (๊ธฐ๋ณธ)
in-kernel ์‚ฌ์šฉ์ž์—†์Œ์†Œ์ผ“ ํ• ๋‹น๊ธฐ ๋“ฑ
memcg ๋ฃจํŠธ`mem_cgroup_is_root()` โ†’ non-tree ๋ฌด์‹œ๋™์ผ

PSI(Pressure Stall Information)์™€์˜ ๊ด€๊ณ„

Linux 4.20์—์„œ ๋„์ž…๋œ PSI๋Š” ์‹œ๊ฐ„ ๊ธฐ๋ฐ˜์˜ ๋ฉ”๋ชจ๋ฆฌ ์••๋ ฅ ์ธก์ • ๋ฐ˜๋ฉด, vmpressure๋Š” ์Šค์บ”/ํšŒ์ˆ˜ ๋น„์œจ ๊ธฐ๋ฐ˜์ž…๋‹ˆ๋‹ค. ๋‘ ์‹œ์Šคํ…œ์€ ์„œ๋กœ ๋ณด์™„์ ์œผ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค:

  • PSI: CPU/๋ฉ”๋ชจ๋ฆฌ/IO ์ž์›์—์„œ ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋Œ€๊ธฐํ•œ ์‹œ๊ฐ„ ๋น„์œจ์„ ์ธก์ • (ฮผs ๋‹จ์œ„)
  • vmpressure: ๋ฆฌํด๋ ˆ์ด๋จธ์˜ ํšŒ์ˆ˜ ํšจ์œจ์„ฑ์„ ์ธก์ • (๋น„์œจ ๋‹จ์œ„)
  • memcg v2์—์„œ๋Š” PSI์™€ vmpressure๊ฐ€ ๋ชจ๋‘ ํ™œ์„ฑํ™”๋˜๋ฉฐ, memory.pressure_level (vmpressure)๊ณผ /proc/pressure/memory (PSI)๊ฐ€ ๊ฐ๊ฐ ๋‹ค๋ฅธ ๊ด€์ ์—์„œ ๋ฉ”๋ชจ๋ฆฌ ์••๋ ฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

    ํ•ญ๋ชฉvmpressurePSI
    ์ธก์ • ๋‹จ์œ„ํšŒ์ˆ˜ ์‹คํŒจ ๋น„์œจ (%)๋Œ€๊ธฐ ์‹œ๊ฐ„ (ฮผs)
    ํŠธ๋ฆฌ๊ฑฐ๋ฆฌํด๋ ˆ์ด๋จธ ์Šค์บ”/ํšŒ์ˆ˜ํ”„๋กœ์„ธ์Šค ๋Œ€๊ธฐ
    ์•Œ๋ฆผ ๋ฐฉ์‹eventfdํŒŒ์ผ ์ฝ๊ธฐ (`/proc/pressure/memory`)
    ๋„์ž… ์ปค๋„3.114.20

    ๊ด€๋ จ ๋ฌธ์„œ

  • ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ๊ฐœ์š”
  • ํŽ˜์ด์ง€ ํšŒ์ˆ˜ (vmscan)
  • Memory Cgroup
  • Swap / zswap
  • OOM Killer