DAMON (Data Access Monitor)
๊ด๋ จ ์์ค: mm/damon/ ๋๋ ํ ๋ฆฌ (core.c, reclaim.c, lru_sort.c, vaddr.c, paddr.c, ops-common.c, modules-common.c, sysfs.c)
๊ด๋ จ ๋ฌธ์: ํ์ด์ง ํ์ (vmscan) ยท ํ์ด์ง Migration ยท ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ ๊ฐ์
๊ฐ์ (Overview)
DAMON(Data Access Monitor)๋ Linux 5.15์์ SeongJae Park์ด ๋์ ํ ๋ฉ๋ชจ๋ฆฌ ์ ๊ทผ ํจํด ๋ชจ๋ํฐ๋ง ํ๋ ์์ํฌ์ ๋๋ค. ๋ฌผ๋ฆฌ ๋๋ ๊ฐ์ ์ฃผ์ ๊ณต๊ฐ์ ์ํ๋ง ๊ธฐ๋ฐ์ผ๋ก ๋ชจ๋ํฐ๋งํ์ฌ ํซ/์ฝ๋ ์์ญ์ ๊ตฌ๋ถํ๊ณ , ์ ๊ทผ ํจํด์ ๊ธฐ๋ฐํ ์๋ํ๋ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ ์์ (DAMOS: Data Access Monitoring-based Operation Scheme)์ ์ํํฉ๋๋ค. ์ค๋ฒํค๋๊ฐ 1% ๋ฏธ๋ง์ผ๋ก ๋ฎ์ ํ๋ก๋์ ์์คํ ์์๋ ์ฌ์ฉ ๊ฐ๋ฅํฉ๋๋ค.
DAMON์ ํต์ฌ ์ค๊ณ ์์น์ "์ ํํ ๋ชจ๋ํฐ๋ง์ ๋ถํ์ํ๊ณ , ์ถฉ๋ถํ ์ ํํ ์ถ์ ์ด๋ฉด ๋๋ค"์
๋๋ค. ์ ์ฒด ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ ๋ฐ ์ถ์ ํ๋ ๋์ ์ํ๋ง๊ณผ ์์ญ(region)์ ์ ์์ ๋ณํฉ/๋ถํ ์ ํตํด ๋์ ์ ํ๋์ ๋ฎ์ ์ค๋ฒํค๋๋ฅผ ๋์์ ๋ฌ์ฑํฉ๋๋ค. ๋ด์ฅ ๋ชจ๋์ธ damon_reclaim(์ฝ๋ ํ์ด์ง ์๋ ํ์)๊ณผ damon_lru_sort(LRU ๋ฆฌ์คํธ ์๋ ์ ๋ ฌ)๊ฐ ๋ํ์ ์ธ ํ์ฉ ์ฌ๋ก์
๋๋ค.
๋์๊ด์ผ๋ก ๋น์ ํ๋ฉด, DAMON์ ๋ชจ๋ ์ฑ
์ ๋์ถ ๊ธฐ๋ก์ ์ผ์ผ์ด ์ธ์ง ์๊ณ ์์ฃผ ์ฐพ๋ ์๊ฐ๋ง ๋น ๋ฅด๊ฒ ํ์ํด ์ฐ์ ์ ๋ฆฌํ๋ ๋ฐฉ์์ ๊ฐ๊น์ต๋๋ค. ํ์ฅ์์๋ damo ๊ฐ์ ์ฌ์ฉ์ ๊ณต๊ฐ ๋๊ตฌ๋ก ๋์๊ณผ ์คํด์ ๋ค๋ฃจ๊ณ , DAMOS_MIGRATE_HOT/DAMOS_MIGRATE_COLD๋ NUMA ํฐ์ด๋ง๊ณผ ํจ๊ป ํซ ๋ฐ์ดํฐ ์ด๋์ ํ์ฉ๋ฉ๋๋ค. ์ด๋ฐ ํ๋ฆ์ MGLRU๋ ๋ฉ๋ชจ๋ฆฌ ํฐ์ด๋ง ๋ฌธ์์ ๊ฐ์ด ๋ณด๋ฉด ๋ ๋๋ ทํด์ง๋๋ค.
# ์์ค ํ์ผ ๊ฒฝ๋ก
mm/damon/core.c โ ํต์ฌ ๋ชจ๋ํฐ๋ง ๋ฃจํ, ์์ญ ๊ด๋ฆฌ, DAMOS ๋ก์ง
mm/damon/reclaim.c โ DAMON ๊ธฐ๋ฐ ํ์ด์ง ํ์ ๋ชจ๋
mm/damon/lru_sort.c โ DAMON ๊ธฐ๋ฐ LRU ์ ๋ ฌ ๋ชจ๋
mm/damon/vaddr.c โ ๊ฐ์ ์ฃผ์ ๊ณต๊ฐ ๋ชจ๋ํฐ๋ง ์ฐ์ฐ
mm/damon/paddr.c โ ๋ฌผ๋ฆฌ ์ฃผ์ ๊ณต๊ฐ ๋ชจ๋ํฐ๋ง ์ฐ์ฐ
mm/damon/ops-common.c โ ๊ณตํต ์ฐ์ฐ (PTE young/clear, folio ์ฒ๋ฆฌ)
mm/damon/sysfs.c โ sysfs ์ธํฐํ์ด์ค
mm/damon/modules-common.c โ ๋ชจ๋ ๊ณตํต ์ ํธ๋ฆฌํฐ
include/linux/damon.h โ ํต์ฌ ์๋ฃ๊ตฌ์กฐ ๋ฐ API ์ ์
๋น ๋ฅธ ์ ๊ฒ ๋ช ๋ น
# DAMON sysfs ์ธํฐํ์ด์ค ํ์ธ
ls /sys/kernel/mm/damon/
# DAMON_RECLAIM ํ์ฑํ
echo Y > /sys/module/damon_reclaim/parameters/enabled
# DAMON_RECLAIM ํ๋ผ๋ฏธํฐ ํ์ธ
cat /sys/module/damon_reclaim/parameters/min_age
cat /sys/module/damon_reclaim/parameters/monitor_region_start
cat /sys/module/damon_reclaim/parameters/monitor_region_end
# DAMON_LRU_SORT ํ์ฑํ (์ปค๋ 6.0+)
echo Y > /sys/module/damon_lru_sort/parameters/enabled
# kdamond ์ค๋ ๋ ํ์ธ
ps aux | grep kdamond
# DAMON tracepoint ์ด๋ฒคํธ ํ์ธ
sudo perf list | grep damon
# DAMOS ํต๊ณ ํ์ธ (sysfs)
cat /sys/kernel/mm/damon/admin/kdamonds/nr_kdamonds
ls /sys/kernel/mm/damon/admin/kdamonds/0/contexts/
# ๋ฉ๋ชจ๋ฆฌ ์๋ ฅ ํ์ธ (PSI)
cat /proc/pressure/memory
# ๋ฌผ๋ฆฌ ์ฃผ์ ์์ญ ํ์ธ (DAMON_RECLAIM ๋์)
sudo cat /proc/iomem | head -20
ํต์ฌ ์๋ฃ๊ตฌ์กฐ
struct damon_region
๋ชจ๋ํฐ๋ง ๋์ ๋ฉ๋ชจ๋ฆฌ ์์ญ์ ๋ํ๋ ๋๋ค. ๊ฐ ์์ญ์ ์์/๋ ์ฃผ์, ์ ๊ทผ ๋น๋, ๋์ด(age)๋ฅผ ์ถ์ ํฉ๋๋ค.
/* include/linux/damon.h:76-86 */
struct damon_region {
struct damon_addr_range ar; /* ์์ ์ฃผ์ (inclusive), ๋ ์ฃผ์ (exclusive) */
unsigned long sampling_addr; /* ๋ค์ ์ ๊ทผ ํ์ธ์ ์ํ ์ํ๋ง ์ฃผ์ */
unsigned int nr_accesses; /* ํ์ฌ ์ง๊ณ ๊ตฌ๊ฐ์์์ ์ ๊ทผ ํ์ */
unsigned int nr_accesses_bp; /* ์ ๊ทผ ๋น๋ (basis point, 1/10000) */
struct list_head list; /* ํ์ ์์ญ ์ฐ๊ฒฐ์ฉ ๋ฆฌ์คํธ */
unsigned int age; /* ์ ๊ทผ ํจํด ์ ์ง ์๊ฐ (์ง๊ณ ๊ตฌ๊ฐ ๋จ์) */
unsigned int last_nr_accesses; /* ์ด์ ์ง๊ณ ๊ตฌ๊ฐ์ ์ ๊ทผ ํ์ */
};
ํ๋ ์ค๋ช :
ar: ์์ญ์ ๋ฌผ๋ฆฌ/๊ฐ์ ์ฃผ์ ๋ฒ์ [start, end)sampling_addr: ๋งค ์ํ๋ง ๊ตฌ๊ฐ๋ง๋ค ๋๋ค์ผ๋ก ์ ํ๋๋ ํ์ธ ๋์ ์ฃผ์nr_accesses: ํ์ฌ aggr_interval ๋ด์์ ์ ๊ทผ์ด ๊ฐ์ง๋ ์ํ๋ง ํ์. aggr_interval๋ง๋ค 0์ผ๋ก ๋ฆฌ์
๋จnr_accesses_bp: nr_accesses๋ฅผ basis point๋ก ํํํ ๊ฐ. ์ด๋ ํฉ(moving sum) ๋ฐฉ์์ผ๋ก ์
๋ฐ์ดํธ๋์ด, aggr_interval์ด ๋๋ฌด ๊ธธ ๋๋ ์ฆ์ ์ ๊ทผ ์ ๋ณด๋ฅผ ์ป์ ์ ์์age: ์ธ์ ์์ญ ๋ณํฉ ์ ๊ฐ์คํ๊ท ์ผ๋ก ๊ณ์ฐ๋จ. ์ ๊ทผ ํจํด์ด ๋ณํ๋ฉด 0์ผ๋ก ๋ฆฌ์
struct damon_target
๋ชจ๋ํฐ๋ง ๋์(ํ๋ก์ธ์ค์ ๊ฐ์ ์ฃผ์ ๊ณต๊ฐ ๋๋ ๋ฌผ๋ฆฌ ์ฃผ์ ๊ณต๊ฐ ์ ์ฒด)์ ๋ํ๋ ๋๋ค.
/* include/linux/damon.h:105-111 */
struct damon_target {
struct pid *pid; /* ๋์ ํ๋ก์ธ์ค์ PID (๋ฌผ๋ฆฌ ์ฃผ์๋ NULL) */
unsigned int nr_regions; /* ์ด ๋์์ ์์ญ ์ */
struct list_head regions_list; /* damon_region ์ฐ๊ฒฐ ๋ฆฌ์คํธ ํค๋ */
struct list_head list; /* ๋ค๋ฅธ ๋์๊ณผ์ ์ฐ๊ฒฐ์ฉ ๋ฆฌ์คํธ */
bool obsolete; /* commit ์ ํ๊ธฐ ๋์ ํ์ */
};
struct damos (DAMOS Scheme)
๋ฐ์ดํฐ ์ ๊ทผ ๋ชจ๋ํฐ๋ง ๊ธฐ๋ฐ ๋์ ๊ณํ์ ์ ์ํฉ๋๋ค. ์ ๊ทผ ํจํด ์กฐ๊ฑด์ ๋ง๋ ์์ญ์ ํน์ ์์ ์ ์ํํ๋ ๊ท์น์ ๋๋ค.
/* include/linux/damon.h:545-580 */
struct damos {
struct damos_access_pattern pattern; /* ๋์ ์ ๊ทผ ํจํด (ํฌ๊ธฐ, ์ ๊ทผ ๋น๋, ๋์ด ๋ฒ์) */
enum damos_action action; /* ์ ์ฉํ ๋์ (PAGEOUT, COLD, HUGEPAGE ๋ฑ) */
unsigned long apply_interval_us; /* ๋์ ์ ์ฉ ์ฃผ๊ธฐ (๋ง์ดํฌ๋ก์ด) */
/* ๋ด๋ถ ์ฌ์ฉ ํ๋ */
unsigned long next_apply_sis; /* ๋ค์ ์ ์ฉ ์์ (์ํ๋ง ๊ตฌ๊ฐ ๊ธฐ์ค) */
bool walk_completed; /* DAMOS walk ์๋ฃ ์ฌ๋ถ */
bool core_filters_allowed; /* ์ฝ์ด ํํฐ ํต๊ณผ ์ฌ๋ถ */
/* ๊ณต๊ฐ ํ๋ */
struct damos_quota quota; /* ์์ ์ ํ (์๊ฐ/ํฌ๊ธฐ) */
struct damos_watermarks wmarks; /* ์ํฐ๋งํฌ ๊ธฐ๋ฐ ์๋ ํ์ฑํ/๋นํ์ฑํ */
struct list_head core_filters; /* ์ฝ์ด ๋ ์ด์ด ํํฐ ๋ชฉ๋ก */
struct list_head ops_filters; /* ์ฐ์ฐ ๋ ์ด์ด ํํฐ ๋ชฉ๋ก */
void *last_applied; /* ๋ง์ง๋ง ์ ์ฉ๋ ์ฐ์ฐ ๋์ (์ค๋ณต ๋ฐฉ์ง) */
struct damos_stat stat; /* ์ ์ฉ ํต๊ณ */
struct list_head list; /* ๋ค๋ฅธ ์คํด๊ณผ์ ์ฐ๊ฒฐ์ฉ ๋ฆฌ์คํธ */
};
struct damon_ctx
๋ชจ๋ํฐ๋ง ์ปจํ ์คํธ. ํ๋์ kdamond ์ค๋ ๋๊ฐ ๊ด๋ฆฌํ๋ ์ต์์ ๊ฐ์ฒด์ ๋๋ค.
/* include/linux/damon.h:780 ๊ธฐ์ค ํต์ฌ ํ๋ */
struct damon_ctx {
struct damon_attrs attrs; /* ๋ชจ๋ํฐ๋ง ์์ฑ (์ํ/์ง๊ณ/์ฐ์ฐ ์
๋ฐ์ดํธ ์ฃผ๊ธฐ) */
unsigned long passed_sample_intervals; /* ๊ฒฝ๊ณผํ ์ํ๋ง ๊ตฌ๊ฐ ์ */
unsigned long next_aggregation_sis; /* ๋ค์ ์ง๊ณ ์์ */
unsigned long next_ops_update_sis; /* ๋ค์ ์ฐ์ฐ ์
๋ฐ์ดํธ ์์ */
/* kdamond ์ค๋ ๋ ๊ด๋ฆฌ */
struct task_struct *kdamond; /* ๋ชจ๋ํฐ๋ง ์ค๋ ๋ */
struct mutex kdamond_lock;
/* DAMOS ํธ์ถ ์ ์ด */
struct list_head call_controls; /* damon_call ์์ฒญ ๋ชฉ๋ก */
/* ๋์ ๋ฐ ์คํด */
struct list_head adaptive_targets; /* damon_target ๋ชฉ๋ก */
struct list_head schemes; /* damos ์คํด ๋ชฉ๋ก */
/* ์ฐ์ฐ (๊ฐ์/๋ฌผ๋ฆฌ ์ฃผ์๋ณ ๊ตฌํ) */
struct damon_operations ops;
};
struct damos_access_pattern
DAMOS๊ฐ ์์ญ์ ๋์์ ์ ์ฉํ๊ธฐ ์ํ ์ ๊ทผ ํจํด ํํฐ์ ๋๋ค.
/* include/linux/damon.h:468-475 */
struct damos_access_pattern {
unsigned long min_sz_region; /* ์ต์ ์์ญ ํฌ๊ธฐ */
unsigned long max_sz_region; /* ์ต๋ ์์ญ ํฌ๊ธฐ */
unsigned int min_nr_accesses; /* ์ต์ ์ ๊ทผ ๋น๋ */
unsigned int max_nr_accesses; /* ์ต๋ ์ ๊ทผ ๋น๋ */
unsigned int min_age_region; /* ์ต์ ๋์ด */
unsigned long max_age_region; /* ์ต๋ ๋์ด */
};
struct damos_watermarks
์์คํ ์ํ์ ๋ฐ๋ฅธ DAMOS ์คํด์ ์๋ ํ์ฑํ/๋นํ์ฑํ๋ฅผ ์ ์ดํฉ๋๋ค.
/* include/linux/damon.h:317-326 */
struct damos_watermarks {
enum damos_wmark_metric metric; /* ์ํฐ๋งํฌ ๋ฉํธ๋ฆญ (FREE_MEM_RATE ๋ฑ) */
unsigned long interval; /* ํ์ธ ์ฃผ๊ธฐ (๋ง์ดํฌ๋ก์ด) */
unsigned long high; /* ์ํ์ โ ์ด๊ณผ ์ ๋นํ์ฑํ */
unsigned long mid; /* ์ค๊ฐ์ โ ์ดํ์ผ ๋ ํ์ฑํ ๊ฐ๋ฅ */
unsigned long low; /* ํํ์ โ ๋ฏธ๋ง ์ ๋นํ์ฑํ */
bool activated; /* ํ์ฌ ํ์ฑํ ์ํ */
};
struct damos_quota
DAMOS ๋์์ ๊ณต๊ฒฉ์ฑ์ ์ ์ดํ๋ ์์ ์ ํ์ ๋๋ค.
/* include/linux/damon.h:258-285 */
struct damos_quota {
unsigned long reset_interval; /* ์ถฉ์ ๋ฆฌ์
์ฃผ๊ธฐ (๋ฐ๋ฆฌ์ด) */
unsigned long ms; /* ์ต๋ ์ฌ์ฉ ๊ฐ๋ฅ ์๊ฐ (๋ฐ๋ฆฌ์ด) */
unsigned long sz; /* ์ต๋ ์ ์ฉ ๊ฐ๋ฅ ํฌ๊ธฐ (๋ฐ์ดํธ) */
struct list_head goals; /* ์ฟผํฐ ์๋ ์กฐ์ ๋ชฉํ ๋ชฉ๋ก */
unsigned long esz; /* ์ ํจ ํฌ๊ธฐ ์ฟผํฐ (๋ด๋ถ ๊ณ์ฐ) */
unsigned int weight_sz; /* ํฌ๊ธฐ ๊ฐ์ค์น (์ฐ์ ์์) */
unsigned int weight_nr_accesses; /* ์ ๊ทผ ๋น๋ ๊ฐ์ค์น */
unsigned int weight_age; /* ๋์ด ๊ฐ์ค์น */
};
struct damon_operations
๋ชจ๋ํฐ๋ง ๋์ ์ฃผ์ ๊ณต๊ฐ ์ข ๋ฅ๋ณ ์ฐ์ฐ ๊ตฌํ์ฒด์ ๋๋ค.
/* include/linux/damon.h:643-656 */
struct damon_operations {
enum damon_ops_id id; /* ์ฐ์ฐ ์ธํธ ID (VADDR, FVADDR, PADDR) */
void (*init)(struct damon_ctx *context); /* ์ด๊ธฐํ */
void (*update)(struct damon_ctx *context); /* ๋์ ์
๋ฐ์ดํธ */
void (*prepare_access_checks)(struct damon_ctx *context); /* ์ ๊ทผ ๊ฒ์ฌ ์ค๋น */
unsigned int (*check_accesses)(struct damon_ctx *context); /* ์ ๊ทผ ๊ฒ์ฌ ์คํ */
int (*get_scheme_score)(struct damon_ctx *context,
struct damon_target *t, struct damon_region *r,
struct damos *scheme);
unsigned long (*apply_scheme)(struct damon_ctx *context,
struct damon_target *t, struct damon_region *r,
struct damos *scheme, unsigned long *sz_filter_passed);
bool (*target_valid)(struct damon_target *t); /* ๋์ ์ ํจ์ฑ ๊ฒ์ฌ */
void (*cleanup_target)(struct damon_target *t); /* ๋์ ์ ๋ฆฌ */
};
enum damos_action
DAMOS๊ฐ ์ํํ ์ ์๋ ๋์ ๋ชฉ๋ก์ ๋๋ค.
/* include/linux/damon.h:135-147 */
enum damos_action {
DAMOS_WILLNEED, /* madvise(MADV_WILLNEED) โ ์ฌ์ ๋ก๋ */
DAMOS_COLD, /* madvise(MADV_COLD) โ ์ฝ๋ ํ์ */
DAMOS_PAGEOUT, /* ํ์ด์ง ํ์ (swap out) */
DAMOS_HUGEPAGE, /* madvise(MADV_HUGEPAGE) โ THP ์ ๋ */
DAMOS_NOHUGEPAGE, /* madvise(MADV_NOHUGEPAGE) โ THP ์ต์ */
DAMOS_LRU_PRIO, /* LRU ์ฐ์ ์์ ์ํฅ */
DAMOS_LRU_DEPRIO, /* LRU ์ฐ์ ์์ ํํฅ */
DAMOS_MIGRATE_HOT, /* ํซ ์์ญ ๋ง์ด๊ทธ๋ ์ด์
*/
DAMOS_MIGRATE_COLD, /* ์ฝ๋ ์์ญ ๋ง์ด๊ทธ๋ ์ด์
*/
DAMOS_STAT, /* ํต๊ณ๋ง ๊ธฐ๋ก (๋์ ์์) */
NR_DAMOS_ACTIONS,
};
ํต์ฌ ํจ์
kdamond_fn() โ ๋ชจ๋ํฐ๋ง ๋ฐ๋ชฌ ๋ฉ์ธ ๋ฃจํ
kdamond ์ค๋ ๋์ ํต์ฌ ๋ฃจํ์ ๋๋ค. ์ํ๋ง โ ์ ๊ทผ ๊ฒ์ฌ โ ์์ญ ๋ณํฉ/๋ถํ โ DAMOS ์ ์ฉ์ ๋ฐ๋ณตํฉ๋๋ค.
/* mm/damon/core.c:2746-2850 */
static int kdamond_fn(void *data)
{
struct damon_ctx *ctx = data;
/* ... ์ด๊ธฐํ ... */
while (!kdamond_need_stop(ctx)) {
/* ์ํฐ๋งํฌ ๊ธฐ๋ฐ ํ์ฑํ ๋๊ธฐ */
if (kdamond_wait_activation(ctx))
break;
/* 1๋จ๊ณ: ์ ๊ทผ ๊ฒ์ฌ ์ค๋น (PTE dirty/young ๋นํธ ๋ฆฌ์
๋ฑ) */
if (ctx->ops.prepare_access_checks)
ctx->ops.prepare_access_checks(ctx);
/* ์ํ๋ง ๊ตฌ๊ฐ๋งํผ ๋๊ธฐ */
kdamond_usleep(sample_interval);
ctx->passed_sample_intervals++;
/* 2๋จ๊ณ: ์ ๊ทผ ๊ฒ์ฌ (PTE dirty/young ๋นํธ ํ์ธ) */
if (ctx->ops.check_accesses)
max_nr_accesses = ctx->ops.check_accesses(ctx);
/* 3๋จ๊ณ: ์ง๊ณ ๊ตฌ๊ฐ ๊ฒฝ๊ณผ ์ ์ธ์ ์์ญ ๋ณํฉ */
if (ctx->passed_sample_intervals >= next_aggregation_sis)
kdamond_merge_regions(ctx, max_nr_accesses / 10, sz_limit);
/* 4๋จ๊ณ: DAMOS ์คํด ์ ์ฉ */
kdamond_call(ctx, false);
if (!list_empty(&ctx->schemes))
kdamond_apply_schemes(ctx);
/* 5๋จ๊ณ: ์ง๊ณ ๋ฆฌ์
๋ฐ ์์ญ ๋ถํ */
if (ctx->passed_sample_intervals >= next_aggregation_sis) {
kdamond_reset_aggregated(ctx);
kdamond_split_regions(ctx);
}
/* 6๋จ๊ณ: ์ฐ์ฐ ์
๋ฐ์ดํธ (VMA ๋ณ๊ฒฝ ๋ฐ์ ๋ฑ) */
if (ctx->passed_sample_intervals >= next_ops_update_sis) {
if (ctx->ops.update)
ctx->ops.update(ctx);
}
}
/* ... ์ ๋ฆฌ ... */
}
๋์ ํ๋ฆ ์์ฝ:
1. prepare_access_checks: ์ํ ์ฃผ์์ PTE dirty/young ๋นํธ๋ฅผ ๋ฆฌ์
2. sample_interval๋งํผ ๋๊ธฐ
3. check_accesses: ๋นํธ๊ฐ ์ค์ ๋์์ผ๋ฉด ์ ๊ทผ์ผ๋ก ๊ธฐ๋ก
4. aggr_interval ๊ฒฝ๊ณผ ์ ์ธ์ ์์ญ ๋ณํฉ (์ ๊ทผ ๋น๋ ์ ์ฌ)
5. DAMOS ์คํด ์ ์ฉ (ํจํด ๋งค์นญ + ํํฐ + ์ฟผํฐ ๊ฒ์ฌ)
6. ์ง๊ณ ๋ฆฌ์ + ๋๋ฌด ์ ์ ์์ญ์ ๋ถํ
damon_do_apply_schemes() โ DAMOS ์คํด ์ ์ฉ
์์ญ์ DAMOS ์คํด์ ๋์์ ์ ์ฉํ๋ ํต์ฌ ํจ์์ ๋๋ค.
/* mm/damon/core.c:1998-2030 */
static void damon_do_apply_schemes(struct damon_ctx *c,
struct damon_target *t,
struct damon_region *r)
{
struct damos *s;
damon_for_each_scheme(s, c) {
/* ์ ์ฉ ์์ ํ์ธ */
if (c->passed_sample_intervals < s->next_apply_sis)
continue;
/* ์ํฐ๋งํฌ ํ์ฑํ ํ์ธ */
if (!s->wmarks.activated)
continue;
/* ์ฟผํฐ ์ด๊ณผ ํ์ธ */
if (quota->esz && quota->charged_sz >= quota->esz)
continue;
/* ์ด์ ์ ์ถฉ์ ๋ ์์ญ ์คํต */
if (damos_skip_charged_region(t, &r, s, c->min_region_sz))
continue;
/* ์ ๊ทผ ํจํด ๋งค์นญ */
if (damos_valid_target(c, t, r, s))
damos_apply_scheme(c, t, r, s);
}
}
ํ๋จ ์กฐ๊ฑด ์์: ์์ โ ์ํฐ๋งํฌ โ ์ฟผํฐ โ ์ถฉ์ ์ด๋ ฅ โ ํจํด ๋งค์นญ โ ์ ์ฉ
__damos_valid_target() โ ์ ๊ทผ ํจํด ๋งค์นญ
์์ญ์ด DAMOS ์คํด์ ์ ๊ทผ ํจํด ์กฐ๊ฑด์ ๋ง์กฑํ๋์ง ํ์ธํฉ๋๋ค.
/* mm/damon/core.c:1678-1690 */
static bool __damos_valid_target(struct damon_region *r, struct damos *s)
{
unsigned long sz;
unsigned int nr_accesses = r->nr_accesses_bp / 10000;
sz = damon_sz_region(r);
return s->pattern.min_sz_region <= sz &&
sz <= s->pattern.max_sz_region &&
s->pattern.min_nr_accesses <= nr_accesses &&
nr_accesses <= s->pattern.max_nr_accesses &&
s->pattern.min_age_region <= r->age &&
r->age <= s->pattern.max_age_region;
}
kdamond_merge_regions() โ ์์ญ ๋ณํฉ
์ธ์ ํ ์์ญ ์ค ์ ๊ทผ ๋น๋๊ฐ ์ ์ฌํ ๊ฒ์ ๋ณํฉํ์ฌ ๋ชจ๋ํฐ๋ง ์ค๋ฒํค๋๋ฅผ ์ค์ ๋๋ค.
/* mm/damon/core.c:2463-2481 */
static void kdamond_merge_regions(struct damon_ctx *c, unsigned int threshold,
unsigned long sz_limit)
{
struct damon_target *t;
unsigned int nr_regions;
unsigned int max_thres;
max_thres = c->attrs.aggr_interval /
(c->attrs.sample_interval ? c->attrs.sample_interval : 1);
do {
nr_regions = 0;
damon_for_each_target(t, c) {
damon_merge_regions_of(t, threshold, sz_limit);
nr_regions += damon_nr_regions(t);
}
threshold = max(1, threshold * 2);
} while (nr_regions > c->attrs.max_nr_regions &&
threshold / 2 < max_thres);
}
๋ณํฉ ๊ธฐ์ค: ์ธ์ + nr_accesses ์ฐจ์ด โค threshold + ํฉ์ฐ ํฌ๊ธฐ โค sz_limit. ์์ญ ์๊ฐ max_nr_regions๋ฅผ ์ด๊ณผํ๋ฉด threshold๋ฅผ 2๋ฐฐ์ฉ ์ฌ๋ ค๊ฐ๋ฉฐ ๋ฐ๋ณต ๋ณํฉ.
damos_wmark_wait_us() โ ์ํฐ๋งํฌ ๊ธฐ๋ฐ ํ์ฑํ
์์คํ ๋ฉ๋ชจ๋ฆฌ ์ํ์ ๋ฐ๋ผ DAMOS ์คํด์ ํ์ฑํ/๋นํ์ฑํ๋ฅผ ๊ฒฐ์ ํฉ๋๋ค.
/* mm/damon/core.c:2615-2641 */
static unsigned long damos_wmark_wait_us(struct damos *scheme)
{
unsigned long metric;
if (damos_get_wmark_metric_value(scheme->wmarks.metric, &metric))
return 0;
/* high ์ด๊ณผ ๋๋ low ๋ฏธ๋ง โ ๋นํ์ฑํ */
if (metric > scheme->wmarks.high || scheme->wmarks.low > metric) {
scheme->wmarks.activated = false;
return scheme->wmarks.interval;
}
/* mid~high ๊ตฌ๊ฐ์ด๊ณ ๋นํ์ฑ ์ํ โ ๋๊ธฐ */
if ((scheme->wmarks.high >= metric && metric >= scheme->wmarks.mid) &&
!scheme->wmarks.activated)
return scheme->wmarks.interval;
scheme->wmarks.activated = true;
return 0;
}
์ํฐ๋งํฌ ์ํ ๋ค์ด์ด๊ทธ๋จ:
metric > high โ ๋นํ์ฑํ (๋ฉ๋ชจ๋ฆฌ ์ฌ์ )
mid โค metric โค high โ ๋นํ์ฑ ์ํ ์ ์ง (์ค๊ฐ ์์ญ)
low โค metric โค mid โ ํ์ฑํ (๋ฉ๋ชจ๋ฆฌ ์๋ฐ ์์)
metric < low โ ๋นํ์ฑํ (๋ฉ๋ชจ๋ฆฌ ๊ทน์ฌํ ๋ถ์กฑ โ ๋ค๋ฅธ ๋ฉ์ปค๋์ฆ ๋์)
damon_reclaim_new_scheme() โ ํ์ ์คํด ๊ตฌ์ฑ
DAMON_RECLAIM ๋ชจ๋์ด ์ฌ์ฉํ๋ ๊ธฐ๋ณธ ํ์ ์คํด์ ๊ตฌ์ฑํฉ๋๋ค.
/* mm/damon/reclaim.c:163-189 */
static struct damos *damon_reclaim_new_scheme(void)
{
struct damos_access_pattern pattern = {
.min_sz_region = PAGE_SIZE, /* ์ต์ ์์ญ: ํ์ด์ง ํฌ๊ธฐ */
.max_sz_region = ULONG_MAX, /* ์ต๋ ์์ญ: ์ ํ ์์ */
.min_nr_accesses = 0, /* ์ ๊ทผ ์์ */
.max_nr_accesses = 0, /* ์ ๊ทผ ์์ */
.min_age_region = min_age / /* ์ต์ ๋์ด (์ง๊ณ ๊ตฌ๊ฐ ํ์ฐ) */
damon_reclaim_mon_attrs.aggr_interval,
.max_age_region = UINT_MAX,
};
return damon_new_scheme(
&pattern,
DAMOS_PAGEOUT, /* ์ฝ๋ ํ์ด์ง๋ฅผ ์ค์์์ */
0, /* ๋งค ์ง๊ณ ๊ตฌ๊ฐ๋ง๋ค ์ ์ฉ */
&damon_reclaim_quota, /* ์ฟผํฐ ์ ์ฉ */
&damon_reclaim_wmarks, /* ์ํฐ๋งํฌ ์ ์ฉ */
NUMA_NO_NODE);
}
ํธ์ถ ํ๋ฆ
kdamond_fn() [kdamond ์ค๋ ๋ ๋ฉ์ธ ๋ฃจํ]
โโโ kdamond_wait_activation()
โ โโโ damos_wmark_wait_us() โโ ์ํฐ๋งํฌ ๊ธฐ๋ฐ ๋๊ธฐ
โโโ ops.prepare_access_checks()
โ โโโ [vaddr] damon_va_prepare_access_checks()
โ โ โโโ damon_ptep_mkold() โโ PTE young ๋นํธ ๋ฆฌ์
โ โโโ [paddr] damon_pa_prepare_access_checks()
โ โโโ damon_pa_mkold() โโ ํ์ด์ง young ๋นํธ ๋ฆฌ์
โโโ ops.check_accesses()
โ โโโ [vaddr] damon_va_check_accesses()
โ โ โโโ damon_va_young() โโ PTE dirty/young ํ์ธ
โ โโโ [paddr] damon_pa_check_accesses()
โ โโโ damon_pa_young() โโ ํ์ด์ง young ํ์ธ
โโโ kdamond_merge_regions()
โ โโโ damon_merge_regions_of()
โ โโโ damon_merge_two_regions() โโ ์ธ์ ์์ญ ๋ณํฉ
โโโ kdamond_call() โโ ์ธ๋ถ ์์ฒญ ์ฒ๋ฆฌ (damon_call)
โโโ kdamond_apply_schemes()
โ โโโ damos_adjust_quota() โโ ์ฟผํฐ ์ ํจ ํฌ๊ธฐ ๊ณ์ฐ
โ โโโ damon_do_apply_schemes()
โ โโโ damos_valid_target() โโ ํจํด ๋งค์นญ
โ โ โโโ __damos_valid_target() โโ ํฌ๊ธฐ/๋น๋/๋์ด ์กฐ๊ฑด
โ โโโ damos_apply_scheme()
โ โโโ damos_core_filter_out() โโ ์ฝ์ด ํํฐ ์ ์ฉ
โ โโโ ops.apply_scheme() โโ ์ค์ ๋์ ์ ์ฉ
โ โ โโโ [paddr] damon_pa_apply_scheme()
โ โ โ โโโ damos_pa_filter_out() โโ ํํฐ ํ์ธ
โ โ โโโ [vaddr] damon_va_apply_scheme()
โ โโโ damos_update_stat() โโ ํต๊ณ ์
๋ฐ์ดํธ
โโโ kdamond_reset_aggregated() โโ ์ง๊ณ ๋ฆฌ์
โโโ kdamond_split_regions() โโ ์์ญ ๋ถํ (์ ํ๋ ํฅ์)
์กฐ๊ฑด๋ณ ๋น๊ต
๋ชจ๋ํฐ๋ง ์ฐ์ฐ ์ ํ ๋น๊ต
| ํญ๋ชฉ | DAMON_OPS_VADDR | DAMON_OPS_PADDR |
|---|---|---|
| ๋์ | ํ๋ก์ธ์ค ๊ฐ์ ์ฃผ์ ๊ณต๊ฐ | ๋ฌผ๋ฆฌ ์ฃผ์ ๊ณต๊ฐ ์ ์ฒด |
| ์๋ณ์ | `target->pid` | `target->pid = NULL` |
| ์ ๊ทผ ๊ฒ์ฌ | PTE young/dirty ๋นํธ | ํ์ด์ง young ๋นํธ |
| ์์ญ ์ด๊ธฐํ | VMA ๊ธฐ๋ฐ 3์์ญ ๋ถํ | ์ ์ฒด ๋ฌผ๋ฆฌ ๋ฉ๋ชจ๋ฆฌ 1์์ญ |
| ํํฐ ์ง์ | ADDR, TARGET | ANON, MEMCG, ADDR, TARGET, YOUNG, ACTIVE, HUGEPAGE_SIZE, UNMAPPED |
| ๋ํ ์ฌ์ฉ์ | ํ๋ก์ธ์ค๋ณ ํ๋กํ์ผ๋ง | DAMON_RECLAIM, DAMON_LRU_SORT |
| ๊ตฌํ ํ์ผ | `mm/damon/vaddr.c` | `mm/damon/paddr.c` |
DAMOS ๋์ ๋น๊ต
| ๋์ | ์ค๋ช | ์ฌ์ฉ ์ |
|---|---|---|
| `DAMOS_PAGEOUT` | ์ฝ๋ ํ์ด์ง๋ฅผ ์ค์์ผ๋ก ํ์ | DAMON_RECLAIM |
| `DAMOS_LRU_PRIO` | LRU ๋ฆฌ์คํธ์์ ์ฐ์ ์์ ์ํฅ | ํซ ํ์ด์ง ๋ณดํธ |
| `DAMOS_LRU_DEPRIO` | LRU ๋ฆฌ์คํธ์์ ์ฐ์ ์์ ํํฅ | DAMON_LRU_SORT |
| `DAMOS_COLD` | `madvise(MADV_COLD)` ํธ์ถ | ์ฝ๋ ํ์ด์ง ํ์ |
| `DAMOS_HUGEPAGE` | `madvise(MADV_HUGEPAGE)` ํธ์ถ | THP ์ ๋ |
| `DAMOS_MIGRATE_HOT` | ํซ ์์ญ ๋ง์ด๊ทธ๋ ์ด์ | NUMA ํฐ์ด๋ง |
| `DAMOS_STAT` | ํต๊ณ๋ง ๊ธฐ๋ก | ํ๋กํ์ผ๋ง |
์ํฐ๋งํฌ ์ํ๋ณ ๋์
| ๋ฉ๋ชจ๋ฆฌ ์ํ | metric ๋ฒ์ | ์คํด ๋์ |
|---|---|---|
| ๋ฉ๋ชจ๋ฆฌ ์ฌ์ | `metric > high` | ๋นํ์ฑํ |
| ์ค๊ฐ (์ด์ ๋นํ์ฑ) | `mid โค metric โค high` | ์ ์ง (๋นํ์ฑ) |
| ์ค๊ฐ (์ด์ ํ์ฑ) | `low โค metric โค mid` | ํ์ฑํ |
| ๋ฉ๋ชจ๋ฆฌ ๋ถ์กฑ | `metric < low` | ๋นํ์ฑํ |
์ฟผํฐ ์๋ ์กฐ์ ๋ฉํธ๋ฆญ ๋น๊ต
| ๋ฉํธ๋ฆญ | ์๋ฏธ | ๋์ |
|---|---|---|
| `DAMOS_QUOTA_USER_INPUT` | ์ฌ์ฉ์ ์ง์ ๊ฐ | ์ปค์คํ ํผ๋๋ฐฑ |
| `DAMOS_QUOTA_SOME_MEM_PSI_US` | ์์คํ ์์ค ์ผ๋ถ ๋ฉ๋ชจ๋ฆฌ PSI (๋ง์ดํฌ๋ก์ด) | ์ ์ฒด ์์คํ |
| `DAMOS_QUOTA_NODE_MEM_USED_BP` | ๋ ธ๋๋ณ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ ๋น์จ | ํน์ NUMA ๋ ธ๋ |
| `DAMOS_QUOTA_NODE_MEM_FREE_BP` | ๋ ธ๋๋ณ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ ๋น์จ | ํน์ NUMA ๋ ธ๋ |
| `DAMOS_QUOTA_NODE_MEMCG_USED_BP` | ์ปจํ ์ด๋๋ณ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ ๋น์จ | ํน์ memcg |
| `DAMOS_QUOTA_ACTIVE_MEM_BP` | ํ์ฑ LRU ๋ฉ๋ชจ๋ฆฌ ๋น์จ | LRU ๋ฐธ๋ฐ์ค |
์ด์ ๋ฐฉ์ ๋น๊ต
| ํญ๋ชฉ | `DAMON_RECLAIM` | `DAMON_LRU_SORT` | ์ง์ DAMOS |
|---|---|---|---|
| ๋ชฉ์ | ์ฝ๋ ํ์ด์ง๋ฅผ ์ค์ฌ ํ์ ์๋ฐ ์ํ | LRU ์ฐ์ ์์๋ฅผ ์ฌ๋ฐฐ์น | ์ํฌ๋ก๋์ ๋ง์ถ ์ ์ฑ ์๋ํ |
| ๋ํ ์ก์ | `DAMOS_PAGEOUT` | `DAMOS_LRU_DEPRIO` / `DAMOS_LRU_PRIO` | `DAMOS_MIGRATE_HOT/COLD`, `DAMOS_HUGEPAGE` ๋ฑ |
| ์ค์ ์์น | `/sys/module/damon_reclaim/parameters/*` | `/sys/module/damon_lru_sort/parameters/*` | `/sys/kernel/mm/damon/admin/kdamonds/*` |
| ํจ๊ป ๋ณด๋ ์งํ | PSI, `pgscan`, `pgsteal` | LRU ๊ท ํ, ์ฌ์ฐธ์กฐ์จ | quota, watermarks, stat |
๊ด๋ จ ๋ฌธ์
์ฐธ๊ณ ์๋ฃ
Documentation/mm/damon/