DAMON (Data Access MONitor)

리눅스 커널의 DAMON(Data Access MONitor) 서브시스템을 심층 분석합니다. 리전(region) 기반 적응적 샘플링으로 오버헤드(Overhead)를 최소화하면서 메모리 접근 패턴을 모니터링하고, DAMOS(Data Access-aware Memory Operation Schemes)를 통해 콜드 페이지(Page) 회수, THP 프로모션, LRU 정렬, NUMA 마이그레이션을 자동으로 수행하는 구조를 커널 소스(mm/damon/)와 최신 공식 문서 기준으로 분석합니다. kdamond 커널 스레드(Kernel Thread), 최신 sysfs/admin 인터페이스, intervals_goal 자동 튜닝, DAMON_STAT, damo 유저스페이스 도구, MGLRU 비교, 파라미터 튜닝까지 포괄합니다.

전제 조건: 메모리 관리(Memory Management) 개요페이지 할당자(Page Allocator) 문서를 먼저 읽으세요. DAMON은 페이지 테이블(Page Table) 접근 비트(PTE Access Bit) 기반으로 동작하므로 가상 메모리(Virtual Memory) 구조의 기본 이해가 필요합니다.
일상 비유: DAMON은 도서관 사서의 열람 빈도 조사와 비슷합니다. 모든 책의 열람 횟수를 매번 세는 대신, 서가를 구역(리전)으로 나누어 대표 책 몇 권만 샘플링합니다. 자주 열람되는 구역은 더 세분화하고, 거의 열람되지 않는 구역은 크게 묶어서 효율적으로 관리합니다. DAMOS는 이 조사 결과를 바탕으로 "6개월 이상 안 빌린 책은 창고로"(pageout) 같은 자동 정책을 적용하는 것입니다.

핵심 요약

  • 저오버헤드 접근 모니터링 -- PTE 접근 비트 샘플링으로 전체 페이지 스캔 없이 메모리 접근 패턴을 추적합니다. 일반적으로 CPU 오버헤드 1% 미만.
  • 적응적 리전 -- 접근 빈도가 비슷한 연속 페이지를 하나의 리전으로 병합하고, 패턴이 달라지면 자동으로 분할합니다. min_nr_regions~max_nr_regions 범위 내에서 동적 조절.
  • DAMOS 자동 정책 -- 모니터링 결과에 기반해 pageout, hugepage collapse, LRU 우선순위(Priority) 조정 등의 액션을 자동 수행합니다.
  • 다중 Operations Set -- vaddr(가상 주소 공간(Address Space)), fvaddr(고정 가상 주소(Virtual Address)), paddr(물리 주소(Physical Address)) 세 가지 모니터링 대상을 지원합니다.
  • sysfs 인터페이스 -- /sys/kernel/mm/damon/을 통해 유저스페이스에서 전체 DAMON 설정을 제어할 수 있습니다.

단계별 이해

  1. PTE 접근 비트 이해
    CPU가 메모리 페이지에 접근하면 하드웨어가 자동으로 PTE의 Access Bit를 설정합니다. DAMON은 이 비트를 주기적으로 확인하고 리셋하여 접근 여부를 감지합니다.
  2. 리전 모델 파악
    연속된 주소 범위를 리전으로 묶고, 각 리전의 접근 횟수(nr_accesses)와 나이(age)를 추적하는 구조를 이해합니다.
  3. 샘플링/집계 주기 구분
    sampling_interval(샘플링 주기)과 aggr_interval(집계 주기)의 관계와 리전 분할/병합 타이밍을 파악합니다.
  4. DAMOS 스킴 설정
    접근 빈도와 나이 조건에 매칭되는 리전에 대해 어떤 액션을 수행할지 정의합니다.
  5. 실전 적용과 모니터링
    damo 도구로 워크로드를 프로파일링(Profiling)하고, sysfs로 DAMOS 스킴을 설정하여 메모리 효율을 최적화합니다.
관련 커널 소스: mm/damon/core.c (핵심 모니터링 로직), mm/damon/ops-common.c (공통 연산), mm/damon/vaddr.c (가상 주소 모니터링), mm/damon/paddr.c (물리 주소 모니터링), mm/damon/sysfs.c (sysfs 인터페이스), mm/damon/reclaim.c (프로액티브 회수), mm/damon/lru_sort.c (LRU 정렬), mm/damon/stat.c (단순 통계 모듈). SeongJae Park이 DAMON의 주요 개발자이며, v5.15에서 커널에 최초 머지되었습니다.

DAMON 개요

DAMON(Data Access MONitor)은 리눅스 커널 v5.15에서 도입된 데이터 접근 모니터링 프레임워크입니다. 기존의 메모리 관리 메커니즘(LRU, kswapd)이 모든 페이지를 균일하게 처리하는 것과 달리, DAMON은 실제 접근 패턴을 정밀하게 추적하여 데이터 기반 메모리 최적화를 가능하게 합니다.

왜 DAMON이 필요한가

기존 메커니즘한계DAMON의 해결
LRU 리스트접근 빈도 구분 불가 (active/inactive 이진 분류)nr_accesses로 접근 빈도 정량화
kswapd/직접 회수(Direct Reclaim)메모리 압박 시에만 동작 (사후 대응)DAMOS로 사전 예방적 회수 가능
/proc/PID/pagemap전체 페이지 테이블 순회 필요 (고비용)리전 기반 샘플링으로 O(regions) 비용
perf mem하드웨어 PMU 의존, 오프라인 분석커널 내장, 실시간(Real-time) 자동 대응
idle page tracking사용자 도구 폴링(Polling) 필요, DAMOS 부재모니터링 + 자동 액션 통합

소스 트리 구조

mm/damon/
├── core.c          # 핵심: kdamond, 리전 관리, 샘플링/집계 루프
├── ops-common.c    # Operations Set 공통 헬퍼
├── vaddr.c         # vaddr operations: PTE 접근 비트 기반
├── paddr.c         # paddr operations: 물리 주소 기반
├── sysfs.c         # /sys/kernel/mm/damon/ 인터페이스
├── sysfs-schemes.c # DAMOS sysfs 스킴 관리
├── dbgfs.c         # debugfs 인터페이스 (레거시)
├── reclaim.c       # DAMON_RECLAIM 모듈
├── lru_sort.c      # DAMON_LRU_SORT 모듈
└── stat.c          # DAMON_STAT 모듈
역사: DAMON은 SeongJae Park(AWS)이 2019년부터 개발을 시작하여, 33번의 RFC/패치(Patch) 시리즈를 거쳐 v5.15(2021.10)에 머지되었습니다. v5.16에서 DAMOS, v5.18에서 sysfs 인터페이스, v6.0에서 DAMON_LRU_SORT가 추가되었습니다. Meta, Google, Amazon 등에서 대규모 프로덕션 환경에 적용 중입니다.

최신 커널 체크포인트

kernel.org에는 stable 6.19.11(2026-04-02 게시)과 mainline 7.0-rc7(2026-04-05 게시)가 올라와 있습니다. 최신 DAMON 문서는 기존의 "리전 기반 샘플링 + DAMOS" 설명을 넘어서, 자동 튜닝된 모니터링 간격, 계층 분리된 필터, 세밀한 스킴 통계, 가중치 기반 다중 마이그레이션 목적지, DAMON_STAT 같은 운영 편의 기능을 공식 인터페이스로 제공합니다.

영역최신 공식 문서에서 확인되는 항목실무 의미
kdamond 제어refresh_ms, update_tuned_intervals, update_schemes_effective_quotas, update_schemes_tried_regions주기적 갱신과 원샷 디버깅을 분리하여 자동화 스크립트를 단순화할 수 있습니다.
모니터링 품질intervals_goal/access_bp, aggrs, min_sample_us, max_sample_us고정 5ms/100ms에 머물지 않고 워크로드별로 샘플링/집계 간격을 자동 조정할 수 있습니다.
DAMOS 제어quotas/goals/*/target_metric,target_value,current_value,nid,path, effective_bytesPSI뿐 아니라 NUMA 노드, memcg, active/inactive 비율을 목표로 한 피드백 제어가 가능합니다.
필터링core_filters/, ops_filters/, filters/필터 평가 순서를 명시적으로 제어할 수 있고, 신규 구성에서는 core_filtersops_filters를 쓰는 편이 안전합니다.
마이그레이션dests/nr_dests, 0/id, 0/weightmigrate_hot/migrate_cold 액션에 단일 target_nid가 아니라 여러 목적지를 가중치로 줄 수 있습니다.
관찰 결과stats/nr_snapshots,max_nr_snapshots, tried_regions/, DAMON_STAT스킴이 실제로 어디까지 시도되었는지와 시스템 전체 유휴 시간 분위수를 더 쉽게 수집할 수 있습니다.
최신 DAMON 제어와 피드백 경로 damo / 운영 스크립트 시작, 보고서, 자동화 /sys/kernel/mm/damon/admin/ state, refresh_ms, avail_operations, commit 계열 제어 kdamond 모니터링 루프 실행 monitoring_attrs sample/aggr/update_us intervals_goal: access_bp, aggrs min_sample_us, max_sample_us targets / operations avail_operations, operations, addr_unit pid_target, obsolete_target, 초기 regions schemes access_pattern, apply_interval_us quotas/goals, core_filters, ops_filters dests, watermarks, stats, tried_regions 즉시 피드백 update_tuned_intervals update_schemes_stats / effective_quotas 행동 추적 update_schemes_tried_regions tried_regions/total_bytes와 리전 세부 정보 DAMON_STAT 시스템 전체 물리 메모리 관찰 estimated_memory_bandwidth memory_idle_ms_percentiles
최신 공식 문서 기준 DAMON의 제어면과 피드백면: sysfs는 설정뿐 아니라 자동 튜닝 결과, 스킴 통계, tried_regions, effective_quotas까지 노출합니다.

아키텍처

DAMON은 4계층 아키텍처로 구성됩니다: kdamond(커널 스레드) → context(모니터링 컨텍스트) → target(모니터링 대상) → region(주소 범위). 이 계층 구조가 DAMON의 유연성과 확장성을 제공합니다.

DAMON 4계층 아키텍처 kdamond 커널 스레드 (모니터링 루프 실행) damon_ctx[0] ops: vaddr | 스킴: DAMOS[0..n] damon_ctx[1] ops: paddr | 스킴: DAMOS[0..m] target[0] (PID 1234) 가상 주소 공간 target[1] (PID 5678) 가상 주소 공간 target[0] (시스템) 물리 주소 공간 리전 리스트 R0: hot nr_acc=9 R1: cold nr_acc=0 R2: warm nr_acc=3 R0 R1 R2 R3 DAMOS 자동 액션 pageout (콜드) hugepage (핫) lru_prio (워밍) lru_deprio (쿨링) sysfs: /sys/kernel/mm/damon/admin/ kdamonds/ → contexts/ → schemes/ → targets/ → regions/ * 하나의 kdamond가 여러 context를, 각 context가 여러 target과 DAMOS scheme을 관리
DAMON의 4계층 구조: kdamond → context → target → region, DAMOS는 context 레벨에서 자동 액션 정의
/* include/linux/damon.h - 핵심 자료 구조 관계 (단순화) */

struct damon_region {
    unsigned long ar.start;           /* 리전 시작 주소 */
    unsigned long ar.end;             /* 리전 끝 주소 */
    unsigned int  nr_accesses;        /* 집계 주기 내 접근 횟수 */
    unsigned int  age;                /* nr_accesses 불변 지속 집계 횟수 */
    struct list_head list;            /* target 내 리전 연결 리스트 */
};

struct damon_target {
    struct pid *pid;                   /* vaddr: 모니터링 대상 PID */
    unsigned int nr_regions;           /* 현재 리전 수 */
    struct list_head regions_list;    /* damon_region 연결 리스트 */
    struct list_head list;            /* context 내 target 연결 리스트 */
};

struct damon_ctx {
    struct damon_attrs attrs;         /* 샘플링/집계/갱신 주기 */
    struct damon_operations ops;      /* operations set (vaddr/paddr) */
    struct list_head adaptive_targets; /* damon_target 리스트 */
    struct list_head schemes;         /* DAMOS 스킴 리스트 */
    struct damon_callback callback;   /* 사용자 콜백 */
};
설명 damon_region은 연속된 주소 범위의 접근 패턴을 추적하는 기본 단위입니다. nr_accesses는 하나의 집계 주기(aggr_interval) 동안 접근이 감지된 샘플링 횟수이며, agenr_accesses 값이 변하지 않은 채 지속된 집계 주기 수입니다. damon_target은 프로세스(Process)(vaddr) 또는 물리 주소 범위(paddr)를 나타내며, 내부에 리전 리스트를 유지합니다. damon_ctx가 모니터링의 전체 설정(Operations Set, DAMOS 스킴, 콜백(Callback))을 보유합니다.

리전 기반 적응적 샘플링

DAMON의 핵심 혁신은 리전 기반 적응적 샘플링(Region-based Adaptive Sampling)입니다. 모든 페이지를 순회하는 대신, 각 리전에서 하나의 랜덤 페이지만 샘플링하여 접근 여부를 확인합니다.

샘플링 알고리즘

DAMON의 모니터링 루프는 세 가지 시간 단위로 동작합니다:

파라미터기본값역할
sample_interval5ms각 리전에서 랜덤 페이지 1개의 PTE 접근 비트 확인 주기
aggr_interval100msnr_accesses 집계 및 DAMOS 스킴 적용 주기
update_interval60s모니터링 대상 리전 초기화/갱신 주기 (VMA 변경 반영)
DAMON 모니터링 루프 타임라인 t sample_interval (5ms) S S S S S S S S S S aggr_interval (100ms) = 20 samples 다음 aggr_interval 각 샘플링 주기에서의 동작: Region 0 Region 1 R2 Region 3 Region 4 = 랜덤 샘플 포인트 1. 각 리전에서 랜덤 주소 선택 2. PTE Access Bit 확인 후 클리어 3. Access Bit=1이면 해당 리전 nr_accesses++ 집계 결과 (aggr_interval 종료 시): R0: nr_accesses=18/20 (hot) R1: nr_accesses=2/20 (cold) R2: nr_accesses=10/20 (warm) R3: nr_accesses=0/20 (cold) R4: nr_accesses=15/20 (hot) → DAMOS 스킴 적용
DAMON은 각 리전에서 랜덤 페이지 1개만 샘플링하여 전체 리전의 접근 빈도를 추정합니다

리전 분할과 병합

DAMON은 각 aggr_interval 종료 시 리전을 동적으로 분할/병합하여 정밀도를 자동 조절합니다:

/* mm/damon/core.c - damon_merge_regions_of() (단순화) */
static void damon_merge_regions_of(
    struct damon_target *t,
    unsigned int threshold,      /* nr_accesses 차이 임계값 */
    unsigned long sz_limit)      /* 병합 후 최대 크기 */
{
    struct damon_region *r, *prev = NULL;

    damon_for_each_region(r, t) {
        if (prev && prev->ar.end == r->ar.start &&
            abs(prev->nr_accesses - r->nr_accesses) <= threshold &&
            damon_sz_region(prev) + damon_sz_region(r) <= sz_limit) {
            prev->ar.end = r->ar.end;
            prev->nr_accesses =
                (prev->nr_accesses + r->nr_accesses) / 2;
            damon_destroy_region(r, t);
        } else {
            prev = r;
        }
    }
}
설명 인접한 두 리전의 nr_accesses 차이가 임계값 이하이고, 병합 후 크기가 제한 이내이면 하나로 합칩니다. 이 과정으로 접근 패턴이 균일한 대규모 영역은 하나의 리전으로 합쳐져 오버헤드가 줄고, 패턴이 변하는 경계 지점은 분할되어 정밀도가 높아집니다.
병합(Merge) — 인접 리전의 nr_accesses가 유사하면 병합 병합 전 R0 nr_accesses: 15 R1 nr_accesses: 14 R2 nr_accesses: 0 R3 nr_accesses: 1 R4 nr_accesses: 0 |15-14|≤임계값 모두 Cold 병합 후 R0+R1 (Hot 병합) nr_accesses: (15+14)/2 = 14 R2+R3+R4 (Cold 병합) nr_accesses: 0 분할(Split) — 접근 패턴 변화 시 리전 세분화 분할 전 — 대형 Cold 리전 내 일부 영역에 접근 발생 R (Cold, nr_accesses: 0) 크기가 크고 내부 접근 패턴이 불균일 접근 급증 감지! Split 분할 후 R-a (Cold) nr_accesses: 0 R-b (Hot) nr_accesses: 12 R-c (Cold) nr_accesses: 0
DAMON 리전 병합(Merge)과 분할(Split): 인접 리전의 nr_accesses가 유사하면 병합하여 오버헤드를 줄이고, 접근 패턴이 변하면 분할하여 정밀도를 높입니다

샘플링 오버헤드 분석

파라미터워크로드 300MB RSS일반 페이지 스캔DAMON 리전 샘플링
모니터링 대상 페이지 수76,80076,800 PTE 확인~100 리전 × 1 PTE = ~100
샘플링 당 비용-O(페이지 수)O(리전 수)
CPU 오버헤드-~5-10%<1%
정밀도-정확통계적 추정 (95%+)
최적 리전 수: min_nr_regions=10, max_nr_regions=1000이 기본값입니다. 리전 수가 많을수록 정밀하지만 오버헤드가 증가합니다. 대부분의 워크로드에서 기본값이 적절하며, 매우 큰 워크로드(수십 GB RSS)에서는 max_nr_regions=2000까지 늘릴 수 있습니다.

Operations Set

DAMON은 Operations Set 추상화를 통해 다양한 주소 공간 타입을 지원합니다. 각 Operations Set은 리전 초기화, 접근 비트 확인, DAMOS 액션 실행 등의 콜백을 구현합니다.

Operations Set대상접근 감지 방식용도
vaddr프로세스 가상 주소 공간PTE Access Bit특정 프로세스의 메모리 접근 패턴 분석
fvaddr고정 가상 주소 범위PTE Access Bit사용자 지정 주소 범위 모니터링
paddr물리 주소 공간rmap을 통한 PTE 확인시스템 전체 메모리 패턴, DAMON_RECLAIM
/* include/linux/damon.h - Operations Set 인터페이스 */
struct damon_operations {
    enum damon_ops_id id;
    /* 모니터링 대상 리전 초기화 */
    void (*init)(struct damon_ctx *ctx);
    /* 모니터링 대상 갱신 (VMA 변경 반영) */
    void (*update)(struct damon_ctx *ctx);
    /* 리전의 접근 준비 (Access Bit 클리어) */
    void (*prepare_access_checks)(struct damon_ctx *ctx);
    /* 리전의 접근 확인 (Access Bit 읽기) */
    unsigned int (*check_accesses)(struct damon_ctx *ctx);
    /* 리셋 (집계 완료 후) */
    void (*reset_aggregated)(struct damon_ctx *ctx);
    /* DAMOS 액션 적용 (pageout, hugepage 등) */
    unsigned long (*apply_scheme)(struct damon_ctx *ctx,
                                  struct damon_target *t,
                                  struct damon_region *r,
                                  struct damos *s);
    /* 스킴 스코어 계산 (우선순위 결정) */
    int (*get_scheme_score)(struct damos *s,
                           struct damon_region *r);
};
설명 damon_operations는 Strategy 패턴으로 구현되어, 동일한 모니터링 로직에 다른 주소 공간 구현을 끼워넣을 수 있습니다. prepare_access_checks()에서 PTE 접근 비트를 클리어하고, 다음 check_accesses()에서 비트가 다시 설정되었는지 확인합니다. vaddrmm_struct의 페이지 테이블을 직접 워크하고, paddrfolio_get_anon_vma() + rmap_walk()로 물리 페이지의 매핑(Mapping)을 역추적(Backtrace)합니다.

vaddr 동작 상세

/* mm/damon/vaddr.c - PTE Access Bit 확인 (단순화) */
static void damon_va_check_access(
    struct damon_ctx *ctx,
    struct damon_target *t,
    struct damon_region *r,
    struct mm_struct *mm)
{
    unsigned long addr;
    pte_t *pte;

    /* 리전 내 랜덤 주소 선택 */
    addr = r->sampling_addr;

    /* 페이지 테이블 워크로 PTE 획득 */
    pte = damon_get_pte(mm, addr);
    if (!pte)
        return;

    /* Access Bit 확인 */
    if (pte_young(*pte)) {
        r->nr_accesses++;
        /* Access Bit 클리어 (다음 확인을 위해) */
        pte_mkold(*pte);
    }
}

paddr 동작 상세

paddr Operations Set은 물리 주소 공간을 직접 모니터링합니다. 물리 페이지에 대한 접근 여부를 확인하려면 rmap(reverse mapping)을 통해 해당 물리 페이지를 매핑하는 모든 PTE를 역추적해야 합니다.

/* mm/damon/paddr.c - 물리 주소 접근 확인 (단순화) */
static bool damon_pa_young(unsigned long paddr,
                           unsigned long *folio_sz)
{
    struct folio *folio;
    bool young = false;

    folio = damon_get_folio(PHYS_PFN(paddr));
    if (!folio)
        return false;

    *folio_sz = folio_size(folio);

    /* 1. folio 자체의 reference bit 확인 */
    if (folio_test_young(folio) ||
        !folio_test_idle(folio)) {
        young = true;
        goto out;
    }

    /* 2. rmap으로 모든 매핑의 PTE 확인 */
    if (folio_mapped(folio)) {
        struct damon_young_walk_private pvt = {
            .young = false,
            .folio_sz = folio_sz,
        };
        rmap_walk(folio, &damon_young_rwc);
        young = pvt.young;
    }

out:
    folio_put(folio);
    return young;
}
설명 paddr ops에서 접근 확인은 vaddr보다 복잡합니다. 물리 페이지가 여러 프로세스에 공유 매핑되어 있을 수 있으므로, rmap_walk()으로 모든 역방향 매핑의 PTE를 검사해야 합니다. 하나라도 Access Bit가 설정되어 있으면 해당 물리 페이지는 "accessed"로 판정합니다. 이 과정이 비용이 더 들지만, 시스템 전체의 물리 메모리(Physical Memory) 접근 패턴을 파악할 수 있는 장점이 있습니다. DAMON_RECLAIMpaddr ops를 사용하는 이유가 바로 이것입니다.

fvaddr Operations Set

fvaddr(fixed virtual address)는 vaddr의 변형으로, VMA 변경에 따른 리전 재초기화를 하지 않습니다. 사용자가 지정한 고정 주소 범위만 모니터링하므로, 특정 메모리 영역(예: 공유 메모리 세그먼트, mmap 파일)의 접근 패턴을 추적할 때 유용합니다.

# fvaddr 사용 예시: 특정 mmap 영역만 모니터링
echo fvaddr > .../contexts/0/operations

# 대상 프로세스 설정
echo 1 > .../contexts/0/targets/nr_targets
echo $(pidof my-app) > .../contexts/0/targets/0/pid_target

# 초기 리전 수동 설정 (mmap 영역 주소)
echo 1 > .../contexts/0/targets/0/regions/nr_regions
echo 0x7f0000000000 > .../contexts/0/targets/0/regions/0/start
echo 0x7f0100000000 > .../contexts/0/targets/0/regions/0/end
DAMON 오퍼레이션 세트 비교: vaddr vs paddr vaddr ops (가상 주소) 프로세스 (PID) mm_struct 페이지 테이블 워크 PTE Access Bit 확인 비트 초기화 (clear) 직접 접근, 빠름 프로세스 단위 모니터링 paddr ops (물리 주소) 물리 주소 범위 folio 조회 (lookup) folio_test_young() 확인 rmap_walk() 역매핑 모든 매핑된 PTE 순회 하나라도 accessed → young rmap 경유, 상대적으로 느림 시스템 전체 모니터링 vs vs
vaddr ops는 프로세스 페이지 테이블을 직접 워크하여 빠르게 확인하고, paddr ops는 folio → rmap_walk()로 모든 매핑 PTE를 역추적하여 시스템 전체를 모니터링

콜백 기반 모니터링

DAMON은 모니터링 루프의 주요 지점에서 콜백 함수를 호출할 수 있습니다. 이를 통해 커널 내부 모듈이나 BPF 프로그램이 DAMON의 모니터링 데이터를 활용할 수 있습니다.

/* include/linux/damon.h - 콜백 구조체 */
struct damon_callback {
    void *private;

    /* 각 샘플링 주기 후 호출 */
    int (*after_wmarks_check)(struct damon_ctx *ctx);
    /* 각 집계 주기 후 호출 */
    int (*after_aggregation)(struct damon_ctx *ctx);
    /* kdamond 종료 전 호출 */
    void (*before_terminate)(struct damon_ctx *ctx);
};
설명 after_aggregation은 가장 자주 사용되는 콜백입니다. 이 시점에서 모든 리전의 nr_accesses가 확정되어 있으므로 접근 패턴 분석에 적합합니다. 콜백이 0이 아닌 값을 반환하면 kdamond가 모니터링을 중단합니다. 이를 통해 특정 조건(예: 충분한 데이터 수집)에서 자동 종료가 가능합니다. DAMON_RECLAIM과 DAMON_LRU_SORT는 이 콜백 메커니즘을 사용하지 않고 DAMOS를 직접 활용합니다.
콜백호출 시점활용 예시
after_wmarks_check워터마크(Watermark) 확인 후모니터링 시작/중지 제어
after_aggregation집계 완료 후접근 패턴 기록, 히트맵 생성, BPF 프로그램
before_terminatekdamond 종료 전리소스 정리, 최종 통계 출력

DAMOS (Data Access-aware Memory Operation Schemes)

DAMOS는 DAMON의 모니터링 결과를 자동으로 메모리 관리 액션에 연결하는 프레임워크입니다. "접근 빈도가 N 이하이고 age가 M 이상인 리전에 대해 pageout을 수행하라"와 같은 선언적 정책을 정의할 수 있습니다.

DAMOS 스킴 처리 파이프라인 리전 접근 데이터 nr_accesses, age 리전 크기 패턴 매칭 min/max accesses min/max age 필터링 anon/memcg/addr young/target 쿼터 확인 time/size limit 우선순위 정렬 액션 실행 pageout/hugepage/... 예시: 콜드 페이지 자동 회수 스킴 1. 리전 R3: nr_accesses=0, age=50, size=4MB 2. 패턴: min_accesses=0, max_accesses=0, min_age=10 → 매칭! 3. 필터: anon_only=false → 통과 4. 쿼터: time=100ms 남음, size=20MB 남음 → 통과 → pageout 실행! 워터마크 기반 활성화/비활성화 메모리 < low → 스킴 활성화 low ≤ 메모리 ≤ high → 유지 메모리 > high → 스킴 비활성화
DAMOS는 패턴 매칭 → 필터링 → 쿼터 확인 → 액션 실행의 5단계 파이프라인(Pipeline)으로 동작합니다
/* include/linux/damon.h - DAMOS 스킴 구조체 (단순화) */
struct damos {
    /* 패턴 매칭 조건 */
    struct damos_access_pattern pattern;  /* min/max nr_accesses, age, size */

    /* 수행할 액션 */
    enum damos_action action;             /* DAMOS_PAGEOUT, DAMOS_HUGEPAGE 등 */

    /* 적용 제한 */
    struct damos_quota quota;              /* time/size 쿼터 */

    /* 활성화 조건 */
    struct damos_watermarks wmarks;        /* free memory 기반 활성화 */

    /* 필터 리스트 */
    struct list_head filters;              /* damos_filter 연결 리스트 */

    /* 통계 */
    struct damos_stat stat;                /* 적용 횟수/크기 */
};

DAMOS 액션

DAMOS가 지원하는 메모리 관리 액션은 다음과 같습니다:

액션커널 버전설명주요 용도
DAMOS_PAGEOUTv5.16+매칭된 리전의 페이지를 스왑(Swap)/디스크로 방출콜드 페이지 프로액티브 회수
DAMOS_HUGEPAGEv5.16+매칭된 리전을 THP로 프로모션 (khugepaged 힌트)핫 페이지 THP 통합
DAMOS_NOHUGEPAGEv5.16+매칭된 리전의 THP 프로모션 억제콜드/랜덤 접근 영역 THP 방지
DAMOS_LRU_PRIOv6.0+LRU 리스트에서 우선순위 상향 (활성화)핫 페이지 보호
DAMOS_LRU_DEPRIOv6.0+LRU 리스트에서 우선순위 하향 (비활성화)콜드 페이지 빠른 회수 대상화
DAMOS_STATv5.16+통계만 수집, 실제 액션 없음모니터링 전용, 정책 시뮬레이션
DAMOS_MIGRATE_HOTv6.9+핫 페이지를 빠른 NUMA 노드로 이동NUMA 티어링 프로모션
DAMOS_MIGRATE_COLDv6.9+콜드 페이지를 느린 NUMA 노드로 이동NUMA 티어링 디모션
/* mm/damon/paddr.c - pageout 액션 구현 (단순화) */
static unsigned long damon_pa_pageout(
    struct damon_region *r)
{
    unsigned long addr, applied = 0;

    for (addr = r->ar.start; addr < r->ar.end; addr += PAGE_SIZE) {
        struct folio *folio = damon_get_folio(PHYS_PFN(addr));
        if (!folio)
            continue;

        /* 이미 회수 불가능하면 스킵 */
        if (folio_test_unevictable(folio))
            goto next;

        /* 회수 리스트에 추가 */
        list_add(&folio->lru, &folio_list);
        applied += folio_nr_pages(folio);
    next:
        folio_put(folio);
    }

    /* 일괄 회수 수행 */
    reclaim_pages(&folio_list);
    return applied * PAGE_SIZE;
}
설명 DAMOS_PAGEOUT은 매칭된 리전의 모든 페이지를 순회하며 reclaim_pages()를 호출합니다. 이때 folio_test_unevictable()로 mlock된 페이지를 건너뛰고, anonymous 페이지는 스왑으로, file-backed 페이지는 디스크로 방출합니다. paddr Operations Set에서는 물리 주소를 직접 사용하므로 rmap 역추적이 필요하지만, vaddr에서는 VMA를 통해 직접 처리합니다.

DAMOS 필터

DAMOS 필터는 패턴 매칭을 통과한 리전 중에서 특정 조건의 페이지를 추가로 포함하거나 제외합니다. 최신 공식 문서 기준으로 필터는 core_filtersops_filters 두 계층으로 나뉘며, 공통 계층 필터가 먼저 평가되고 그 다음에 Operations Set별 필터가 평가됩니다.

필터 계층필터 타입설명예시 용도
core_filtersaddr주소 범위 기준 포함/제외힙, mmap 구간, 특정 PFN 범위만 타겟팅
core_filterstarget특정 모니터링 대상 인덱스만 포함/제외다중 프로세스 중 하나만 정책 적용
ops_filtersanon, active익명 페이지(Anonymous Page), active LRU 기준 포함/제외파일 캐시는 남기고 anonymous만 회수, active 페이지 보호
ops_filtersmemcg특정 memcg 경로의 페이지만 포함/제외특정 컨테이너(Container)의 메모리만 최적화
ops_filtersyoung, unmapped최근 접근 여부, 매핑 여부 기준 포함/제외아직 따뜻한 페이지와 매핑 끊긴 페이지를 분리
ops_filtershugepage_sizeHuge Page 크기 범위 기준 필터링2MB THP만 디모션하거나 1GB HugeTLB는 건너뛰기
/* include/linux/damon.h - 필터 구조체 (단순화) */
struct damos_filter {
    enum damos_filter_type type;
    bool matching;             /* 필터 조건이 일치해야 하는지 */
    bool allow;                /* true: 허용, false: 제외 */
    union {
        unsigned short memcg_id;
        struct damon_addr_range addr_range;
        int target_idx;
        struct {
            unsigned long min;
            unsigned long max;
        } hugepage_sz;
    };
    struct list_head list;
};
설명 matching은 "필터가 어떤 조건을 검사할지"를, allow는 "매칭 시 허용할지 제외할지"를 표현합니다. 평가 순서는 core_filtersops_filters이며, 각 그룹 안에서는 첫 번째 일치 필터가 결과를 결정합니다. 아무 필터에도 일치하지 않았을 때의 기본 동작은 마지막 필터의 allow 값에 따라 달라지므로, "항상 기본 포함"이라고 가정하면 안 됩니다.
# 최신 sysfs 방식: core_filters와 ops_filters를 분리해서 설정
echo 1 > .../schemes/0/core_filters/nr_filters
echo target > .../schemes/0/core_filters/0/type
echo Y > .../schemes/0/core_filters/0/matching
echo Y > .../schemes/0/core_filters/0/allow
echo 0 > .../schemes/0/core_filters/0/target_idx

echo 1 > .../schemes/0/ops_filters/nr_filters
echo memcg > .../schemes/0/ops_filters/0/type
echo Y > .../schemes/0/ops_filters/0/matching
echo N > .../schemes/0/ops_filters/0/allow
echo /kubepods.slice > .../schemes/0/ops_filters/0/memcg_path
DAMOS 필터 체인 평가 흐름 (Filter Chain Evaluation) 패턴 매칭 (Pattern Match) anon 불일치 memcg 불일치 addr 불일치 young 기본 동작 (마지막 allow 값) 일치 포함/제외 일치 포함/제외 예시 1: 파일 기반 페이지 → 제외됨 영역 R3 file-backed page anon 필터 일치! (non-anon) 제외됨 EXCLUDED 예시 2: 익명 페이지(Anonymous Page) + cgroup=web-app → 액션 적용 영역 R5 anon, web-app anon 필터 통과! memcg 필터 web-app 통과! 액션 적용 ACTION APPLIED ◆ 대표 예시 순서: core_filters → ops_filters | 각 그룹에서 첫 번째 일치 필터가 결과를 결정
DAMOS 필터 체인 평가: 최신 sysfs는 core_filters와 ops_filters를 분리하며, 무일치 시 기본 동작은 마지막 필터의 allow 값에 따라 달라집니다.
실무 권장: 통합 filters 디렉토리도 존재하지만, 최신 설계 문서는 core_filtersops_filters를 분리해 쓰는 편이 평가 순서를 분명히 한다고 설명합니다. 신규 정책은 가능하면 이 두 디렉토리로 작성하세요.

DAMOS 쿼터와 우선순위

DAMOS 쿼터는 스킴이 한 번의 집계 주기에서 소비할 수 있는 시간과 크기를 제한합니다. 쿼터가 초과되면 나머지 리전은 다음 주기로 연기됩니다. 이때 우선순위(prioritization)가 어떤 리전을 먼저 처리할지 결정합니다.

DAMOS 쿼터 기반 우선순위 처리 리전 우선순위 정렬 (pageout 스킴: 접근 빈도 낮을수록 높은 우선순위) R3: acc=0, 8MB 우선순위 1 (가장 콜드) R1: acc=1, 4MB 우선순위 2 R5: acc=2, 6MB 우선순위 3 R7: acc=3, 10MB 쿼터 초과 → 다음 주기 R9: acc=4, 2MB 쿼터 초과 → 다음 주기 쿼터 소비 (sz_limit = 16MB) R3: 8MB R1: 4MB R5: 4MB ← 16MB 도달! 쿼터 설정 파라미터 ms (시간 쿼터): 한 주기 최대 시간 sz (크기 쿼터): 한 주기 최대 바이트 reset_interval: 쿼터 리셋 주기 weight_*: 우선순위 가중치 우선순위 점수 계산: score = weight_sz * region_sz + weight_nr_accesses * acc + weight_age * age
쿼터가 16MB일 때, 우선순위 순으로 R3(8MB)+R1(4MB)+R5(부분 4MB)까지 처리하고 나머지는 다음 주기로 연기
/* include/linux/damon.h - 쿼터 구조체 */
struct damos_quota {
    unsigned long ms;           /* 시간 제한 (밀리초, 0=무제한) */
    unsigned long sz;           /* 크기 제한 (바이트, 0=무제한) */
    unsigned long reset_interval_ms; /* 쿼터 리셋 주기 */

    /* 우선순위 가중치 */
    unsigned int weight_sz;         /* 리전 크기 가중치 */
    unsigned int weight_nr_accesses; /* 접근 횟수 가중치 */
    unsigned int weight_age;        /* 나이 가중치 */

    /* 자동 튜닝 목표 */
    struct damos_quota_goal *goals;  /* v6.8+: 자동 쿼터 조절 */

    /* 내부 상태 */
    unsigned long charged_sz;
    unsigned long charged_from;
    unsigned long esz;              /* 유효 쿼터 크기 */
};
자동 쿼터 튜닝 (v6.8+): damos_quota_goal을 설정하면 DAMON이 목표 메트릭(예: PSI some 값 5% 이하)을 달성하도록 쿼터를 자동으로 조절합니다. 메모리 압박이 심하면 쿼터를 늘리고, 안정화되면 줄이는 피드백 루프입니다.
DAMOS 워터마크 상태 머신 비활성 free > high (DAMON 모니터링 중지) 일반 동작 low ≤ free ≤ high (일반 주기로 스킴 적용) 적극 동작 free < low (적극적 회수/스왑 실행) free ≤ mid free > high free < low free ≥ mid 워터마크 수준 (Free Memory %) free % 시간 high mid low ← 히스테리시스 구간 비활성 적극 일반 비활성 적극
DAMOS 워터마크 기반 상태 전이: high 이상이면 비활성, low 미만이면 적극 동작, mid 구간은 히스테리시스로 상태 진동 방지

sysfs 인터페이스

DAMON의 주요 인터페이스는 /sys/kernel/mm/damon/admin/ 디렉토리입니다. 커널 v5.18에서 도입되어 debugfs 인터페이스를 대체합니다.

/sys/kernel/mm/damon/admin/
├── kdamonds/
│   ├── nr_kdamonds          # kdamond 스레드 수 설정
│   └── 0/
│       ├── state            # on/off/commit/update_* 명령
│       ├── pid              # kdamond 스레드 PID (읽기 전용(Read-Only))
│       ├── refresh_ms       # 주기적 자동 갱신 주기
│       └── contexts/
│           ├── nr_contexts
│           └── 0/
│               ├── avail_operations # 현재 커널이 지원하는 ops 목록
│               ├── operations       # vaddr/fvaddr/paddr
│               ├── addr_unit        # paddr 계열 주소 단위
│               ├── monitoring_attrs/
│               │   ├── intervals/
│               │   │   ├── sample_us     # 샘플링 주기 (마이크로초)
│               │   │   ├── aggr_us       # 집계 주기
│               │   │   ├── update_us     # 갱신 주기
│               │   │   └── intervals_goal/
│               │   │       ├── access_bp
│               │   │       ├── aggrs
│               │   │       ├── min_sample_us
│               │   │       └── max_sample_us
│               │   └── nr_regions/
│               │       ├── min           # 최소 리전 수
│               │       └── max           # 최대 리전 수
│               ├── targets/
│               │   ├── nr_targets
│               │   └── 0/
│               │       ├── pid_target    # 대상 PID (vaddr)
│               │       ├── obsolete_target
│               │       └── regions/      # 초기 리전 (선택)
│               └── schemes/
│                   ├── nr_schemes
│                   └── 0/
│                       ├── action        # pageout/hugepage/...
│                       ├── apply_interval_us
│                       ├── target_nid
│                       ├── access_pattern/
│                       ├── quotas/        # goals/, effective_bytes 포함
│                       ├── watermarks/
│                       ├── core_filters/
│                       ├── ops_filters/
│                       ├── filters/
│                       ├── dests/
│                       ├── stats/        # nr_snapshots 포함
│                       └── tried_regions/

sysfs 설정 워크플로

# 1. kdamond 생성
echo 1 > /sys/kernel/mm/damon/admin/kdamonds/nr_kdamonds

# 2. context 생성 및 operations 설정
echo 1 > /sys/kernel/mm/damon/admin/kdamonds/0/contexts/nr_contexts
echo vaddr > /sys/kernel/mm/damon/admin/kdamonds/0/contexts/0/operations

# 3. 모니터링 파라미터 설정
echo 5000 > .../contexts/0/monitoring_attrs/intervals/sample_us   # 5ms
echo 100000 > .../contexts/0/monitoring_attrs/intervals/aggr_us   # 100ms
echo 60000000 > .../contexts/0/monitoring_attrs/intervals/update_us # 60s
echo 4 > .../contexts/0/monitoring_attrs/intervals/intervals_goal/access_bp
echo 20 > .../contexts/0/monitoring_attrs/intervals/intervals_goal/aggrs
echo 5000 > .../contexts/0/monitoring_attrs/intervals/intervals_goal/min_sample_us
echo 200000 > .../contexts/0/monitoring_attrs/intervals/intervals_goal/max_sample_us

# 4. 모니터링 대상 설정
echo 1 > .../contexts/0/targets/nr_targets
echo $(pidof my-app) > .../contexts/0/targets/0/pid_target

# 5. DAMOS 스킴 설정 (콜드 페이지 회수)
echo 1 > .../contexts/0/schemes/nr_schemes
echo pageout > .../contexts/0/schemes/0/action
echo 0 > .../contexts/0/schemes/0/access_pattern/nr_accesses/min
echo 0 > .../contexts/0/schemes/0/access_pattern/nr_accesses/max
echo 5 > .../contexts/0/schemes/0/access_pattern/age/min

# 6. 커밋 및 시작
echo commit > /sys/kernel/mm/damon/admin/kdamonds/0/state
echo on > /sys/kernel/mm/damon/admin/kdamonds/0/state
echo 1000 > /sys/kernel/mm/damon/admin/kdamonds/0/refresh_ms   # 1초마다 자동 갱신

# 7. 통계 확인
echo update_schemes_stats > /sys/kernel/mm/damon/admin/kdamonds/0/state
echo update_schemes_effective_quotas > /sys/kernel/mm/damon/admin/kdamonds/0/state
echo update_schemes_tried_regions > /sys/kernel/mm/damon/admin/kdamonds/0/state
cat .../contexts/0/schemes/0/stats/nr_applied
cat .../contexts/0/schemes/0/stats/sz_applied
cat .../contexts/0/schemes/0/quotas/effective_bytes
cat .../contexts/0/schemes/0/tried_regions/total_bytes
설명 sysfs 인터페이스는 DAMON의 전체 설정을 디렉토리 계층 구조로 노출합니다. state 파일에 commit을 쓰면 현재 sysfs 설정이 실제 DAMON 설정에 반영되고, on을 쓰면 kdamond 스레드(Thread)가 시작됩니다. update_schemes_stats, update_schemes_effective_quotas, update_schemes_tried_regions, update_tuned_intervals 같은 명령으로 최신 상태를 개별적으로 갱신할 수 있습니다.

최신 sysfs에서 놓치기 쉬운 확장점

경로의미운영 팁
kdamonds/0/refresh_ms통계, tuned interval, tried regions를 주기적으로 갱신합니다.관찰 전용 서버에서는 1000~5000ms 정도로 두면 폴링 스크립트를 단순화할 수 있습니다.
contexts/0/avail_operations현재 커널이 노출하는 Operations Set 목록입니다.배포판별로 fvaddr 지원 여부가 다를 수 있으므로 스크립트에서 먼저 확인하는 편이 안전합니다.
contexts/0/addr_unit주소를 페이지 단위로 쓸지 바이트 단위로 쓸지 표현합니다.paddr 자동화에서 단위를 잘못 가정하면 target/dests 계산이 어긋날 수 있습니다.
.../intervals/intervals_goal/*목표 접근 비율에 맞춰 sample/aggr 간격을 자동 조정합니다.워크로드가 들쭉날쭉한 서버에서는 고정 interval보다 이쪽이 더 안정적입니다.
.../schemes/0/core_filters, ops_filters필터를 공통 계층과 ops 계층으로 분리합니다.신규 구성에서는 통합 filters보다 이 두 디렉토리를 우선 사용하세요.
.../schemes/0/dests복수 마이그레이션 목적지를 가중치로 지정합니다.CXL, DRAM, PMEM이 섞인 환경에서 단일 target_nid보다 유연합니다.
.../schemes/0/stats/nr_snapshots스킴 통계 스냅샷 보존 개수를 확인합니다.장시간 실험에서는 max_nr_snapshots와 함께 봐야 오래된 통계가 잘리는 시점을 알 수 있습니다.
.../schemes/0/tried_regions최근 시도된 리전의 주소, 접근 횟수, 나이, 필터 통과 크기를 노출합니다.왜 어떤 리전이 실제 pageout 대상이 되었는지 역추적할 때 유용합니다.

debugfs 인터페이스 (레거시)

초기 DAMON은 /sys/kernel/debug/damon/ debugfs 인터페이스를 사용했습니다. 최신 공식 문서는 debugfs를 deprecated로 분류하며, 신규 스크립트와 운영 자동화는 sysfs 인터페이스로 작성할 것을 권고합니다.

# debugfs 인터페이스 (레거시 - 신규 사용 비권장)
/sys/kernel/debug/damon/
├── attrs           # "sample_us aggr_us update_us min_nr max_nr" 형식
├── target_ids      # 대상 PID 목록 (공백 구분)
├── schemes         # DAMOS 스킴 (한 줄에 하나씩)
└── monitor_on      # "on"/"off"

# 예시: debugfs로 모니터링 시작
echo "5000 100000 60000000 10 1000" > /sys/kernel/debug/damon/attrs
echo "$(pidof my-app)" > /sys/kernel/debug/damon/target_ids
echo "on" > /sys/kernel/debug/damon/monitor_on
마이그레이션 권장: debugfs 인터페이스는 CONFIG_DAMON_DBGFS로 활성화되며, 최신 커널에서는 기본 비활성화입니다. 새로운 배포에서는 반드시 sysfs 인터페이스(/sys/kernel/mm/damon/admin/)를 사용하세요.

debugfs에서 sysfs로 마이그레이션

기존 debugfs 기반 설정을 sysfs로 마이그레이션할 때 참고하는 대응표입니다. debugfs는 하나의 파일에 여러 값을 공백으로 구분하여 쓰는 반면, sysfs는 디렉토리 계층으로 각 값을 개별 파일에 저장합니다.

debugfs 경로/형식sysfs 경로비고
attrs (5개 값 한 줄)contexts/0/monitoring_attrs/intervals/ + nr_regions/sample_us, aggr_us, update_us, min, max 각각 분리
target_ids (PID 목록)contexts/0/targets/0/pid_targetsysfs는 타겟별 디렉토리 분리
schemes (한 줄 스킴)contexts/0/schemes/0/ 하위action, access_pattern, quotas, watermarks, filters 각각 분리
monitor_onkdamonds/0/stateon/off 대신 on/off/commit/update_schemes_stats
# [기존] debugfs 방식 - 단일 파일에 모든 파라미터
echo "5000 100000 60000000 10 1000" > /sys/kernel/debug/damon/attrs
echo "$(pidof my-app)" > /sys/kernel/debug/damon/target_ids
echo "on" > /sys/kernel/debug/damon/monitor_on

# [신규] sysfs 방식 - 계층적 디렉토리 구조
DAMON_BASE="/sys/kernel/mm/damon/admin/kdamonds/0"
CTX="${DAMON_BASE}/contexts/0"

# 모니터링 파라미터 (attrs의 5개 값을 개별 파일로)
echo 5000 > ${CTX}/monitoring_attrs/intervals/sample_us
echo 100000 > ${CTX}/monitoring_attrs/intervals/aggr_us
echo 60000000 > ${CTX}/monitoring_attrs/intervals/update_us
echo 10 > ${CTX}/monitoring_attrs/nr_regions/min
echo 1000 > ${CTX}/monitoring_attrs/nr_regions/max

# 타겟 PID 설정
echo 1 > ${CTX}/targets/nr_targets
echo $(pidof my-app) > ${CTX}/targets/0/pid_target

# 설정 반영 후 시작
echo commit > ${DAMON_BASE}/state
echo on > ${DAMON_BASE}/state
설명 debugfs의 attrs 파일은 "sample_us aggr_us update_us min_nr max_nr" 5개 값을 한 줄에 작성하는 방식이었습니다. sysfs에서는 이 값들이 monitoring_attrs/intervals/monitoring_attrs/nr_regions/ 하위에 각각 독립 파일로 분리되어 개별적으로 읽고 쓸 수 있습니다. monitor_on에 해당하는 state 파일은 commit(설정 반영), on(시작), off(중지), update_schemes_stats(통계 갱신) 등 다양한 명령을 지원합니다. sysfs 인터페이스는 debugfs보다 파일 수가 많지만, 원자적(atomic) 설정 변경과 통계 조회가 가능하다는 장점이 있습니다.
레거시 debugfs 사용 시 주의사항: (1) debugfs는 CONFIG_DAMON_DBGFS=y일 때만 사용 가능하며, 최신 문서에서도 deprecated 상태로 표시됩니다. (2) debugfs schemes 파일은 한 줄에 모든 스킴 파라미터를 공백으로 나열하므로 필터, 쿼터 목표 등 최신 기능을 설정할 수 없습니다. (3) debugfs와 sysfs를 동시에 사용하면 설정이 충돌할 수 있으므로, 반드시 하나의 인터페이스만 사용해야 합니다. (4) 기존 debugfs 기반 스크립트는 위의 대응표를 참고하여 sysfs 기반으로 순차적으로 전환하세요.

DAMON 기반 프로액티브 회수

DAMON_RECLAIM은 DAMON의 가장 대표적인 활용 사례로, 콜드 페이지를 메모리 압박 없이 사전에 회수합니다. 기존 kswapd가 워터마크 기반으로 사후 대응하는 것과 달리, DAMON_RECLAIM은 접근 패턴을 분석하여 실제로 사용되지 않는 페이지만 선별적으로 회수합니다.

DAMON_RECLAIM 동작 흐름 paddr ops 물리 주소 전체 모니터링 접근 패턴 수집 리전별 nr_accesses 집계 콜드 페이지 탐지 acc=0, age > threshold PAGEOUT 콜드 페이지 회수 모듈 파라미터 (/sys/module/damon_reclaim/parameters/) 모니터링 설정: sample_interval = 5000 # 5ms 샘플링 주기 aggr_interval = 100000 # 100ms 집계 주기 min_age = 200 # 200 집계주기(20초) 동안 미접근 시 콜드 쿼터 설정: quota_ms = 10 # 10ms/aggr_interval 최대 처리 시간 quota_sz = 128000000 # 128MB/aggr_interval 최대 회수량 워터마크 설정: wmarks_low = 300 # free < 3% → 적극 회수 wmarks_mid = 400 # free 3~4% → 일반 회수 wmarks_high = 500 # free > 5% → 회수 중지
DAMON_RECLAIM은 물리 주소 전체를 모니터링하여 콜드 페이지를 사전 회수합니다
# DAMON_RECLAIM 활성화
echo Y > /sys/module/damon_reclaim/parameters/enabled

# 기본 파라미터 확인
cat /sys/module/damon_reclaim/parameters/sample_interval    # 5000 (us)
cat /sys/module/damon_reclaim/parameters/aggr_interval     # 100000 (us)
cat /sys/module/damon_reclaim/parameters/min_age           # 200

# 서버 환경: 콜드 임계값을 낮추고 쿼터를 넉넉하게
echo 100 > /sys/module/damon_reclaim/parameters/min_age       # 10초 미접근 시 콜드
echo 20 > /sys/module/damon_reclaim/parameters/quota_ms       # 20ms/주기 처리
echo 256000000 > /sys/module/damon_reclaim/parameters/quota_sz # 256MB/주기

# 모니터링 통계 확인
cat /sys/module/damon_reclaim/parameters/nr_reclaimed     # 회수된 페이지 수
cat /sys/module/damon_reclaim/parameters/bytes_reclaimed  # 회수된 바이트 수
효과: Meta의 프로덕션 환경에서 DAMON_RECLAIM은 기존 kswapd 대비 10~20% 더 많은 메모리를 회수하면서도, 핫 페이지를 건드리지 않아 애플리케이션 성능 저하가 최소화됩니다. 특히 대규모 캐시를 사용하는 서버(memcached, Redis)에서 효과적입니다.
DAMON_RECLAIM vs kswapd 동작 타이밍 비교 kswapd (반응적) 시간 메모리 사용량 low watermark kswapd 휴면 (idle) 메모리 압박 구간 전체 페이지 스캔! 지연 스파이크! 회수 완료 → 다시 휴면 burst 스캔 → 높은 지연 cold/hot 구분 없이 전체 스캔 VS DAMON_RECLAIM (선제적) 시간 메모리 사용량 low watermark (도달 안 함) cold 감지+회수 cold 감지+회수 cold 감지+회수 cold 감지+회수 cold 감지+회수 cold 감지+회수 ← 균일한 저오버헤드 연속 동작 (지연 스파이크 없음) → cold 페이지만 선별 회수 접근 패턴 기반 → 낮은 오버헤드 kswapd burst 구간 DAMON 연속 모니터링 메모리 사용량
kswapd는 워터마크 도달 시 burst 스캔으로 지연(Latency)이 발생하지만, DAMON_RECLAIM은 지속적으로 콜드 페이지만 선별 회수하여 워터마크 도달을 예방

DAMON LRU Sort

DAMON_LRU_SORT(v6.0+)는 LRU 리스트의 페이지 순서를 DAMON의 접근 패턴 데이터 기반으로 재정렬합니다. 기존 LRU는 페이지 폴트(Page Fault)와 참조 시점에만 순서가 갱신되지만, DAMON_LRU_SORT는 실제 접근 빈도를 반영하여 보다 정확한 LRU 순서를 유지합니다.

동작조건LRU 효과
핫 페이지 프로모션nr_accesses > hot_thresholdLRU active 리스트 head로 이동
콜드 페이지 디모션nr_accesses < cold_threshold, age > min_ageLRU inactive 리스트 tail로 이동
# DAMON_LRU_SORT 활성화
echo Y > /sys/module/damon_lru_sort/parameters/enabled

# 핫/콜드 임계값 설정
echo 5 > /sys/module/damon_lru_sort/parameters/hot_thres_access_freq  # 접근 빈도 5 이상이면 핫
echo 200 > /sys/module/damon_lru_sort/parameters/cold_min_age          # 200 주기 이상 미접근이면 콜드

# 쿼터 설정 (LRU 재정렬 비용 제한)
echo 10 > /sys/module/damon_lru_sort/parameters/quota_ms

# 통계 확인
cat /sys/module/damon_lru_sort/parameters/nr_lru_sort_hot   # 핫 프로모션 횟수
cat /sys/module/damon_lru_sort/parameters/nr_lru_sort_cold  # 콜드 디모션 횟수
DAMON_RECLAIM + DAMON_LRU_SORT 조합: 두 모듈을 동시에 활성화하면 LRU_SORT가 콜드 페이지를 inactive tail로 밀어넣고, RECLAIM이 이를 회수하는 시너지 효과가 있습니다. 그러나 CPU 오버헤드가 2배가 되므로 대규모 시스템에서만 권장합니다.
DAMON LRU Sort 동작 원리 변경 전 LRU 리스트 Active Head Inactive Tail 페이지 A 페이지 B ··· 핫 페이지 H ··· 페이지 D 콜드 페이지 K 페이지 E 핫 판정: nr_accesses > hot_threshold → LRU_PRIO로 Active Head 승격 콜드 판정: nr_accesses=0, age > min_age → LRU_DEPRIO로 Inactive Tail 강등 승격 (Promote) 강등 (Demote) 변경 후 LRU 리스트 Active Head Inactive Tail 핫 페이지 H ★ 페이지 A 페이지 B ··· 페이지 D 페이지 E ··· 콜드 페이지 K ↓ 최근 접근 ← Active ─────────────────── Inactive → 회수 대상 승격됨 (LRU_PRIO) 강등됨 (LRU_DEPRIO) 일반 페이지
DAMON LRU Sort가 접근 빈도에 따라 핫 페이지를 Active Head로 승격하고, 콜드 페이지를 Inactive Tail로 강등하는 과정

damo 유저스페이스 도구

damo는 DAMON의 공식 유저스페이스 CLI 도구입니다. Python으로 작성되어 있으며, 모니터링 설정, 데이터 수집, 시각화, DAMOS 테스트를 간편하게 수행할 수 있습니다.

# 설치
pip3 install damo

# 프로세스 모니터링 (vaddr)
sudo damo start $(pidof my-app)

# 시스템 전체 모니터링 (paddr)
sudo damo start --ops paddr

# 접근 패턴 기록 (10초)
sudo damo record $(pidof my-app) --duration 10s -o access.json

# 히트맵 시각화
sudo damo report heats --input access.json

# 워킹셋 크기 분석
sudo damo report wss --input access.json
# 출력 예시:
# percentile  working_set_size
# 0           23.4MB
# 25          45.2MB
# 50          67.8MB
# 75          89.3MB
# 100         156.7MB

# 핫/콜드 분포 리포트
sudo damo report nr_regions --input access.json

# DAMOS 시뮬레이션 (실제 액션 없이 예상 결과만 확인)
sudo damo schemes --action stat \
    --access_rate 0 0 \
    --age 200 max \
    $(pidof my-app)

# DAMOS 적용
sudo damo schemes --action pageout \
    --access_rate 0 0 \
    --age 200 max \
    --quotas 10ms 128M \
    $(pidof my-app)
설명 damo record는 DAMON 모니터링을 시작하고 접근 패턴 데이터를 JSON 파일로 저장합니다. damo report heats는 주소 범위 × 시간 축의 히트맵을 터미널에 출력하여 핫/콜드 영역을 시각적으로 확인할 수 있습니다. damo report wss는 워킹셋(실제 사용 중인 메모리) 크기의 분포를 보여줍니다. damo schemes --action stat은 실제 회수 없이 매칭되는 리전의 크기만 확인하여 정책을 사전 검증할 수 있습니다.

실전 활용 사례

서버 환경: 대규모 메모리 최적화

# 시나리오: 256GB RAM 서버, memcached + MySQL 혼합 워크로드
# 목표: 사용되지 않는 memcached 캐시 페이지를 사전 회수

# DAMON_RECLAIM 설정 (물리 주소 전체 모니터링)
echo 5000 > /sys/module/damon_reclaim/parameters/sample_interval
echo 200000 > /sys/module/damon_reclaim/parameters/aggr_interval
echo 300 > /sys/module/damon_reclaim/parameters/min_age    # 60초 콜드 기준
echo 50 > /sys/module/damon_reclaim/parameters/quota_ms
echo 512000000 > /sys/module/damon_reclaim/parameters/quota_sz # 512MB/주기
echo Y > /sys/module/damon_reclaim/parameters/enabled

모바일/임베디드 환경

# 시나리오: 8GB RAM 스마트폰, 메모리 제약 환경
# 목표: 백그라운드 앱의 콜드 페이지 적극 회수

# 짧은 집계 주기 + 낮은 콜드 기준
echo 5000 > /sys/module/damon_reclaim/parameters/sample_interval
echo 50000 > /sys/module/damon_reclaim/parameters/aggr_interval  # 50ms
echo 100 > /sys/module/damon_reclaim/parameters/min_age           # 5초 콜드
echo 5 > /sys/module/damon_reclaim/parameters/quota_ms             # 낮은 쿼터
echo Y > /sys/module/damon_reclaim/parameters/enabled

컨테이너(Container) 환경: cgroup 필터

# 시나리오: Kubernetes Pod별 DAMOS 정책 분리
# sysfs 인터페이스로 memcg 필터 설정

# 특정 cgroup의 메모리만 회수 대상으로 지정
MEMCG_PATH="/sys/fs/cgroup/my-pod"

# DAMOS 스킴에 memcg 필터 추가
echo 1 > .../schemes/0/ops_filters/nr_filters
echo memcg > .../schemes/0/ops_filters/0/type
echo Y > .../schemes/0/ops_filters/0/matching
echo Y > .../schemes/0/ops_filters/0/allow
echo ${MEMCG_PATH} > .../schemes/0/ops_filters/0/memcg_path

Redis/Memcached 인메모리 캐시 최적화

Redis나 Memcached 같은 인메모리 캐시(In-memory Cache) 서버는 대량의 데이터를 메모리에 적재하지만, 실제로는 상당 부분이 콜드 상태입니다. 만료된 키(Expired Key), 거의 조회되지 않는 값, TTL이 남았지만 접근이 없는 항목 등이 RSS를 불필요하게 증가시킵니다. DAMON으로 캐시 적중률(Hit Rate)에 영향 없이 콜드 페이지를 사전 회수할 수 있습니다.

# 시나리오: 64GB Redis 인스턴스, RSS 48GB 중 실제 핫 데이터 ~30GB
# 목표: 콜드 anonymous 페이지만 선별적으로 pageout하여 RSS 절감

# ── 1단계: DAMON_RECLAIM 파라미터 설정 ──
echo 5000 > /sys/module/damon_reclaim/parameters/sample_interval    # 5ms
echo 200000 > /sys/module/damon_reclaim/parameters/aggr_interval    # 200ms
echo 600 > /sys/module/damon_reclaim/parameters/min_age              # 120초 콜드 기준
echo 30 > /sys/module/damon_reclaim/parameters/quota_ms              # 주기당 최대 30ms
echo 256000000 > /sys/module/damon_reclaim/parameters/quota_sz      # 주기당 256MB

# ── 2단계: anon 필터 (파일 캐시는 커널 페이지 캐시가 관리) ──
DAMON_CTX="/sys/kernel/mm/damon/admin/kdamonds/0/contexts/0"
echo 1 > ${DAMON_CTX}/schemes/0/ops_filters/nr_filters
echo anon > ${DAMON_CTX}/schemes/0/ops_filters/0/type
echo Y > ${DAMON_CTX}/schemes/0/ops_filters/0/matching
echo Y > ${DAMON_CTX}/schemes/0/ops_filters/0/allow  # anon만 포함

echo Y > /sys/module/damon_reclaim/parameters/enabled
캐시 워크로드 튜닝: Redis/Memcached는 접근 패턴이 Zipf 분포를 따라 상위 20% 키가 80% 트래픽을 처리합니다. min_age를 120초 이상으로 보수적으로 설정해도 상당량의 콜드 페이지를 회수할 수 있습니다. 일반적으로 RSS 20~40% 절감, 캐시 적중률 변화 1% 미만을 기대할 수 있습니다.
# 검증: 캐시 성능 + RSS 변화 모니터링
redis-cli info stats | grep "keyspace_hits\|keyspace_misses"
ps -o rss= -p $(pidof redis-server) | awk '{print $1/1024"MB"}'
cat /sys/module/damon_reclaim/parameters/nr_reclaimed

Java/JVM 힙 메모리 최적화

JVM(Java Virtual Machine) 힙의 올드 제너레이션(Old/Tenured Generation)에는 장기 생존하지만 거의 접근되지 않는 콜드 객체가 상당수 존재합니다. DAMON의 vaddr 오퍼레이션으로 특정 JVM 프로세스를 모니터링하면, GC가 관리하지 못하는 페이지 수준의 콜드 영역을 식별하고 회수할 수 있습니다.

GC와의 상호작용 주의: G1 GC나 ZGC의 컴팩션(Compaction) 사이클은 힙 전체를 순회하면서 모든 페이지가 일시적으로 핫 상태로 전환됩니다. min_age를 GC 주기의 2~3배 이상으로 충분히 길게 설정해야 합니다.
# 시나리오: -Xmx32g JVM, Old Gen 24GB 중 활성 ~15GB
JAVA_PID=$(pidof java)
CTX="/sys/kernel/mm/damon/admin/kdamonds/0/contexts/0"

echo vaddr > ${CTX}/operations
echo 1 > ${CTX}/targets/nr_targets
echo ${JAVA_PID} > ${CTX}/targets/0/pid_target

# 보수적 파라미터 (GC 주기 고려)
echo 10000 > ${CTX}/monitoring_attrs/intervals/sample_us    # 10ms
echo 500000 > ${CTX}/monitoring_attrs/intervals/aggr_us      # 500ms

# 콜드 판정: 250초 이상 미접근 (GC Full 주기 대비 충분히 길게)
echo 1 > ${CTX}/schemes/nr_schemes
echo pageout > ${CTX}/schemes/0/action
echo 0 > ${CTX}/schemes/0/access_pattern/nr_accesses/max
echo 500 > ${CTX}/schemes/0/access_pattern/age/min
echo 20 > ${CTX}/schemes/0/quotas/ms
echo 128000000 > ${CTX}/schemes/0/quotas/bytes
JVM별 권장 min_age: G1 GC → 500+(250초), ZGC → 800+(400초). jstat -gcutil로 GC 간격을 측정한 후 해당 간격의 2~3배로 설정하세요.

데이터베이스 버퍼(Buffer) 풀 최적화

MySQL(InnoDB)이나 PostgreSQL의 버퍼 풀(Buffer Pool)mmap()으로 매핑된 file-backed 페이지입니다. DAMON으로 콜드 버퍼 풀 페이지를 식별하여 다른 프로세스에 메모리를 환원할 수 있습니다.

더티 페이지(Dirty Page) 주의: 더티 페이지를 강제 회수하면 재접근 시 fsync() 비용이 발생합니다. 데이터베이스 체크포인트(Checkpoint) 주기와 조율하여 더티 페이지 비율을 낮게 유지하세요.
# MySQL InnoDB buffer pool 32GB, file-backed 콜드 페이지만 회수
echo 5000 > /sys/module/damon_reclaim/parameters/sample_interval
echo 200000 > /sys/module/damon_reclaim/parameters/aggr_interval
echo 900 > /sys/module/damon_reclaim/parameters/min_age           # 180초 콜드
echo 20 > /sys/module/damon_reclaim/parameters/quota_ms            # 낮은 쿼터

# anon 필터 allow=false → file-backed 페이지만 타겟
DAMON_CTX="/sys/kernel/mm/damon/admin/kdamonds/0/contexts/0"
echo 1 > ${DAMON_CTX}/schemes/0/ops_filters/nr_filters
echo anon > ${DAMON_CTX}/schemes/0/ops_filters/0/type
echo Y > ${DAMON_CTX}/schemes/0/ops_filters/0/matching
echo N > ${DAMON_CTX}/schemes/0/ops_filters/0/allow  # anon 제외=file만

echo Y > /sys/module/damon_reclaim/parameters/enabled

# 버퍼 풀 히트율 모니터링
mysql -e "SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read%';"
DB별 권장사항: MySQL은 innodb_buffer_pool_dump_pct로 핫 페이지 목록을 유지하여 DAMON 회수 후에도 빠른 워밍을 보장합니다. PostgreSQL은 shared_buffers가 OS 페이지 캐시(Page Cache)와 이중 캐싱되므로 file-backed 회수가 특히 효과적입니다. 초기에는 quota_ms를 10~20으로 보수적으로 시작하고, 히트율 99%+ 유지를 확인한 후 점진적으로 증가시키세요.

Meta TMO (Transparent Memory Offloading)

Meta(Facebook)의 TMO(Transparent Memory Offloading)는 DAMON을 프로덕션에 대규모로 적용한 대표적인 사례입니다. 수백만 대의 서버에서 운영되며, DAMON을 사용하여 콜드 메모리를 zswap으로 오프로딩(Offloading)합니다.

TMO 아키텍처

Meta TMO (Transparent Memory Offloading) 아키텍처 애플리케이션 (memcached, TAO, MySQL 등) DAMON (paddr operations) 콜드 페이지 탐지: nr_accesses=0, age > threshold DAMOS PAGEOUT 콜드 페이지 오프로딩 핫 페이지 유지 DRAM에 그대로 보존 zswap (압축 캐시) LZ4/zstd 압축, 메모리 60% 절약 PSI 피드백 루프 memory.pressure → quota 자동 조절
Meta TMO는 DAMON으로 콜드 페이지를 탐지하고 zswap으로 오프로딩하며, PSI 피드백으로 쿼터를 자동 조절
측정 항목TMO 없음TMO 적용개선
서버당 DRAM 사용100%70~80%20~30% 절약
워크로드 성능 (p99 지연(Latency))기준±2% 이내성능 유지
OOM 빈도기준50% 감소안정성 향상
CPU 오버헤드0%0.5~1%미미

TMO 스타일 DAMON sysfs 설정

Meta TMO와 유사한 구성을 DAMON sysfs 인터페이스를 통해 직접 설정하는 방법입니다. 물리 주소 모니터링(paddr)으로 콜드 페이지를 탐지하고 PAGEOUT 액션으로 zswap에 오프로딩합니다.

#!/bin/bash
# TMO 스타일 DAMON 설정: 콜드 페이지를 zswap으로 오프로딩

DAMON_BASE="/sys/kernel/mm/damon/admin/kdamonds/0"
CTX="${DAMON_BASE}/contexts/0"
SCHEME="${CTX}/schemes/0"

# 1. zswap 활성화 (zstd 압축, zsmalloc 할당자)
echo 1 > /sys/module/zswap/parameters/enabled
echo zstd > /sys/module/zswap/parameters/compressor
echo zsmalloc > /sys/module/zswap/parameters/zpool
echo 30 > /sys/module/zswap/parameters/max_pool_percent

# 2. paddr 오퍼레이션(물리 주소 전체 모니터링) 설정
echo 1 > ${DAMON_BASE}/../nr_kdamonds
echo 1 > ${DAMON_BASE}/contexts/nr_contexts
echo paddr > ${CTX}/operations

# 3. 모니터링 파라미터: TMO 권장값
echo 5000 > ${CTX}/monitoring_attrs/intervals/sample_us     # 5ms 샘플링
echo 100000 > ${CTX}/monitoring_attrs/intervals/aggr_us     # 100ms 집계
echo 1000000 > ${CTX}/monitoring_attrs/intervals/update_us  # 1초 리전 갱신
echo 10 > ${CTX}/monitoring_attrs/nr_regions/min
echo 1000 > ${CTX}/monitoring_attrs/nr_regions/max

# 4. DAMOS PAGEOUT 스킴: 콜드 페이지 오프로딩
echo 1 > ${CTX}/schemes/nr_schemes
echo pageout > ${SCHEME}/action

# 접근 패턴: nr_accesses=0 (미접근), age >= 200 집계주기(20초)
echo 0 > ${SCHEME}/access_pattern/sz/min
echo 0 > ${SCHEME}/access_pattern/sz/max          # 0=무제한
echo 0 > ${SCHEME}/access_pattern/nr_accesses/min
echo 0 > ${SCHEME}/access_pattern/nr_accesses/max  # 접근 없음
echo 200 > ${SCHEME}/access_pattern/age/min          # 최소 20초 미접근
echo 0 > ${SCHEME}/access_pattern/age/max            # 0=무제한

# 5. 쿼터 설정: I/O 폭주 방지
echo 10 > ${SCHEME}/quotas/ms                         # 집계 주기당 10ms
echo 128000000 > ${SCHEME}/quotas/bytes               # 주기당 128MB
echo 1000 > ${SCHEME}/quotas/reset_interval_ms        # 1초마다 리셋

# 6. 워터마크: 메모리 여유 시 비활성화
echo free_mem_rate > ${SCHEME}/watermarks/metric
echo 5000000 > ${SCHEME}/watermarks/interval_us       # 5초마다 확인
echo 500 > ${SCHEME}/watermarks/high                   # 50% 이상: 비활성
echo 400 > ${SCHEME}/watermarks/mid                    # 40% 이하: 활성
echo 200 > ${SCHEME}/watermarks/low                    # 20% 이하: 적극적

# 7. 설정 반영 및 시작
echo commit > ${DAMON_BASE}/state
echo on > ${DAMON_BASE}/state

echo "TMO 스타일 DAMON 설정 완료"
설명 TMO의 핵심은 paddr 오퍼레이션으로 시스템 전체 물리 메모리를 모니터링하고, PAGEOUT 액션으로 콜드 페이지를 스왑 아웃하는 것입니다. zswap이 활성화되어 있으면 스왑 아웃된 페이지가 먼저 압축 캐시에 저장되므로, 재접근 시 디스크 I/O 없이 메모리에서 직접 압축 해제됩니다. 쿼터(quotas/ms, quotas/bytes)는 한 번에 너무 많은 페이지를 회수하여 I/O 폭주가 발생하는 것을 방지합니다. 워터마크(watermarks/)는 메모리 여유가 충분할 때 불필요한 회수를 자동으로 비활성화합니다.

PSI 피드백 루프 모니터링

TMO에서 핵심적인 역할을 하는 PSI(Pressure Stall Information) 피드백 루프의 상태를 모니터링하는 방법입니다. DAMOS Quota Goal과 연동하여 메모리 압박에 따라 쿼터가 자동 조절되는 과정을 관찰할 수 있습니다.

#!/bin/bash
# PSI 피드백 루프 모니터링 스크립트

SCHEME="/sys/kernel/mm/damon/admin/kdamonds/0/contexts/0/schemes/0"

# PSI 기반 자동 쿼터 튜닝 설정 (v6.8+)
echo 1 > ${SCHEME}/quotas/goals/nr_goals
echo some_mem_psi_us > ${SCHEME}/quotas/goals/0/target_metric
echo 10000 > ${SCHEME}/quotas/goals/0/target_value  # PSI some 10ms 이내 목표

# 주기적 모니터링
while true; do
    # DAMOS 통계 갱신 요청
    echo update_schemes_stats > /sys/kernel/mm/damon/admin/kdamonds/0/state

    # 메모리 PSI 확인
    PSI_SOME=$(awk '/some/{print $2}' /proc/pressure/memory)

    # DAMOS 적용 통계
    TRIED=$(cat ${SCHEME}/stats/sz_tried)
    APPLIED=$(cat ${SCHEME}/stats/sz_applied)
    QUOTA_EXCEED=$(cat ${SCHEME}/stats/qt_exceeds)

    echo "[$(date +%H:%M:%S)] PSI_some=${PSI_SOME} tried=${TRIED} applied=${APPLIED} qt_exceeds=${QUOTA_EXCEED}"

    # zswap 상태 확인
    ZSWAP_STORED=$(cat /sys/kernel/debug/zswap/stored_pages)
    ZSWAP_POOL=$(cat /sys/kernel/debug/zswap/pool_total_size)
    echo "         zswap_pages=${ZSWAP_STORED} pool_size=$((ZSWAP_POOL/1024/1024))MB"

    sleep 5
done
설명 update_schemes_statsstate 파일에 쓰면 DAMOS 통계가 갱신됩니다. sz_tried는 스킴 조건에 매칭되어 시도된 총 바이트, sz_applied는 실제 적용(회수)된 바이트입니다. qt_exceeds는 쿼터 초과로 스킵된 횟수로, 이 값이 지속적으로 높다면 쿼터를 늘리거나 PSI 목표를 완화해야 합니다. PSI some 값이 목표(10ms)를 초과하면 DAMON이 쿼터를 자동으로 늘려 더 많은 콜드 페이지를 회수하고, 목표 이하로 떨어지면 쿼터를 줄여 불필요한 회수를 방지합니다.
Google TPP와의 비교: Google의 TPP(Transparent Page Placement)도 DAMON을 NUMA 티어링에 활용합니다. TPP는 핫 페이지를 DRAM으로 프로모션하는 데 초점을 맞추고, Meta의 TMO는 콜드 페이지를 zswap으로 오프로딩하는 데 초점을 맞춥니다. 두 접근 모두 DAMON의 접근 패턴 데이터를 활용하지만 최적화 방향이 다릅니다.

DAMON vs MGLRU

DAMON과 MGLRU(Multi-Gen LRU)는 모두 메모리 접근 패턴을 활용하지만, 접근 방식과 목적이 다릅니다. 두 메커니즘은 상호 보완적으로 동시에 사용할 수 있습니다.

DAMON vs MGLRU 아키텍처 비교 DAMON 접근 감지: 리전 기반 랜덤 샘플링 O(리전 수) / sample_interval 데이터 표현: nr_accesses (0~aggr/sample) age (불변 지속 주기) 액션: DAMOS (pageout, hugepage, lru_*) 사용자 정의 정책, 필터, 쿼터 오버헤드: CPU <1%, 메모리 O(리전 수) 독립 커널 스레드 (kdamond) 프로액티브 (항상 모니터링) MGLRU 접근 감지: 페이지 테이블 전체 스캔 O(페이지 수) / 회수 시점 데이터 표현: 세대(generation) 번호 4개 tier (hot/warm/cold/oldest) 액션: LRU 세대 에이징 + 회수 커널 내부 자동 (사용자 정책 제한적) 오버헤드: 회수 시에만 비용 발생 기존 kswapd/direct reclaim 통합 리액티브 (메모리 압박 시 동작)
DAMON은 프로액티브 모니터링+정책 실행, MGLRU는 리액티브 LRU 에이징 개선에 각각 특화
특성DAMONMGLRU
도입 버전v5.15v6.1
주요 목적데이터 접근 모니터링 + 자동 최적화LRU 알고리즘 근본 개선
동작 시점항상 (프로액티브)메모리 회수(Memory Reclaim) 시 (리액티브)
정밀도리전 단위 (통계적 추정)페이지 단위 (정확)
사용자 제어세밀한 정책 정의 가능제한적 (min_ttl_ms 등)
THP 최적화DAMOS_HUGEPAGE/NOHUGEPAGE내장 (folio 기반 에이징)
NUMA 지원MIGRATE_HOT/COLD (v6.9+)lru_gen 내장 NUMA 밸런싱
동시 사용가능 -- DAMON의 LRU_PRIO/DEPRIO가 MGLRU 세대 이동을 보완
상호 보완 전략: MGLRU가 기본 LRU 에이징을 담당하고, DAMON이 추가적으로 (1) 콜드 페이지를 사전 회수하여 MGLRU의 부담을 줄이거나, (2) 핫 페이지를 THP로 프로모션하거나, (3) NUMA 티어링을 수행하는 구성이 효과적입니다.

DAMON과 MGLRU 동시 활성화 설정

DAMON과 MGLRU는 독립적으로 동작하므로 동시에 활성화할 수 있습니다. MGLRU가 리액티브 회수를 담당하고, DAMON이 프로액티브 회수와 추가 최적화를 수행하는 구성입니다.

#!/bin/bash
# DAMON + MGLRU 동시 활성화 설정

# === MGLRU 활성화 (리액티브 LRU 에이징 개선) ===
# MGLRU 상태 확인
cat /sys/kernel/mm/lru_gen/enabled
# 0x0007 = 모든 기능 활성화 (y=세대 에이징, +page table 스캔, +블룸 필터)

# MGLRU 활성화 (아직 비활성이라면)
echo 7 > /sys/kernel/mm/lru_gen/enabled

# min_ttl_ms: 최소 생존 시간 (0=제한 없음, 1000=최소 1초 보장)
echo 1000 > /sys/kernel/mm/lru_gen/min_ttl_ms

# === DAMON_RECLAIM 활성화 (프로액티브 콜드 페이지 회수) ===
# MGLRU와 함께 사용 시 min_age를 다소 높게 설정하여
# MGLRU가 처리하지 못한 장기 미접근 페이지만 DAMON이 회수
echo 5000 > /sys/module/damon_reclaim/parameters/sample_interval  # 5ms
echo 100000 > /sys/module/damon_reclaim/parameters/aggr_interval  # 100ms
echo 300 > /sys/module/damon_reclaim/parameters/min_age            # 30초 미접근
echo 10 > /sys/module/damon_reclaim/parameters/quota_ms            # 10ms/주기
echo 128000000 > /sys/module/damon_reclaim/parameters/quota_sz    # 128MB/주기

# 워터마크: 메모리 여유 시 DAMON 비활성
echo 500 > /sys/module/damon_reclaim/parameters/wmarks_high
echo 400 > /sys/module/damon_reclaim/parameters/wmarks_mid
echo 200 > /sys/module/damon_reclaim/parameters/wmarks_low
echo Y > /sys/module/damon_reclaim/parameters/enabled

# === 상태 확인 ===
echo "--- MGLRU 상태 ---"
cat /sys/kernel/mm/lru_gen/enabled
cat /sys/kernel/debug/lru_gen  # 세대별 페이지 분포 (debugfs)

echo "--- DAMON_RECLAIM 상태 ---"
cat /sys/module/damon_reclaim/parameters/enabled
cat /sys/module/damon_reclaim/parameters/nr_reclaimed
cat /sys/module/damon_reclaim/parameters/bytes_reclaimed_regions
설명 MGLRU의 enabled 값 7(0x0007)은 세대 에이징(bit 0), 페이지 테이블 스캔(bit 1), 블룸 필터(bit 2)를 모두 활성화합니다. min_ttl_ms는 세대의 최소 생존 시간으로, 너무 빨리 에이징되는 것을 방지합니다. DAMON_RECLAIM의 min_age를 기본값(200)보다 높게(300) 설정하면, MGLRU가 이미 처리한 비교적 짧은 미접근 페이지는 건드리지 않고 장기 콜드 페이지만 DAMON이 사전 회수합니다.

sysfs/procfs 설정 비교

설정 항목DAMON (sysfs)MGLRU (sysfs/debugfs)
활성화/sys/module/damon_reclaim/parameters/enabled/sys/kernel/mm/lru_gen/enabled
최소 미접근 시간min_age (집계 주기 단위)min_ttl_ms (밀리초 단위)
회수 제한quota_ms, quota_sz해당 없음 (커널 자동 조절)
워터마크wmarks_high/mid/low (퍼밀)해당 없음 (kswapd 워터마크 사용)
모니터링 통계nr_reclaimed, schemes/0/stats//sys/kernel/debug/lru_gen
커널 CONFIGCONFIG_DAMON_RECLAIMCONFIG_LRU_GEN

워크로드별 선택 가이드

워크로드 유형권장 구성이유
범용 서버 (웹, API)MGLRU만리액티브 회수만으로 충분하며, 추가 오버헤드 불필요
메모리 집약 (DB, 캐시)MGLRU + DAMONDAMON이 장기 콜드 페이지를 사전 회수하여 OOM 예방
대규모 클라우드 (컨테이너)MGLRU + DAMON + memcg 필터cgroup별 차별화된 정책, 프로액티브 메모리 절약
NUMA 다계층 메모리MGLRU + DAMON MIGRATEMGLRU는 노드 내 에이징, DAMON은 노드 간 마이그레이션
임베디드/저전력DAMON만MGLRU의 페이지 테이블 전체 스캔이 부담되는 환경
THP 최적화 필요MGLRU + DAMON HUGEPAGEMGLRU는 folio 에이징, DAMON은 핫 리전 THP 프로모션

DAMON과 NUMA 티어링

커널 v6.9에서 도입된 DAMOS_MIGRATE_HOT/DAMOS_MIGRATE_COLD 액션은 DAMON의 접근 패턴 데이터를 NUMA 메모리 티어링에 활용합니다. CXL 메모리, HBM, PMEM 등 이기종 메모리 계층에서 데이터 배치를 최적화합니다.

DAMON 기반 NUMA 메모리 티어링 Node 0: DRAM (빠른 계층) HOT HOT cold warm Node 1: CXL (느린 계층) cold cold HOT! cold MIGRATE_COLD: 콜드 → 느린 계층 MIGRATE_HOT: 핫 → 빠른 계층 결과: 핫 데이터는 DRAM에, 콜드 데이터는 CXL에 자동 배치 접근 지연시간 최소화 + 메모리 용량 최대화
DAMON이 접근 패턴을 추적하여 핫 페이지는 빠른 NUMA 노드로, 콜드 페이지는 느린 노드로 자동 이동
# NUMA 티어링 예시: DRAM(Node 0) ↔ CXL(Node 1)

# 스킴 1: 콜드 페이지를 CXL로 디모션
echo migrate_cold > .../schemes/0/action
echo 0 > .../schemes/0/access_pattern/nr_accesses/min
echo 0 > .../schemes/0/access_pattern/nr_accesses/max
echo 100 > .../schemes/0/access_pattern/age/min
echo 1 > .../schemes/0/target_nid            # CXL node

# 스킴 2: 핫 페이지를 DRAM으로 프로모션
echo migrate_hot > .../schemes/1/action
echo 15 > .../schemes/1/access_pattern/nr_accesses/min
echo 20 > .../schemes/1/access_pattern/nr_accesses/max
echo 0 > .../schemes/1/target_nid             # DRAM node
CXL 메모리 시대: CXL(Compute Express Link) 메모리 확장 장치가 보급되면서 DAMON의 NUMA 티어링 역할이 점점 중요해지고 있습니다. Google의 TPP(Transparent Page Placement)와 Meta의 TMO(Transparent Memory Offloading)가 DAMON 기반 NUMA 티어링의 대표적인 프로덕션 사례입니다.

ftrace/tracepoint 디버깅(Debugging)

DAMON은 ftrace tracepoint를 통해 내부 동작을 디버깅할 수 있습니다.

# 사용 가능한 DAMON tracepoint 확인
ls /sys/kernel/debug/tracing/events/damon/
# damon_aggregated      -- 리전별 집계 결과

# tracepoint 활성화
echo 1 > /sys/kernel/debug/tracing/events/damon/damon_aggregated/enable

# 추적 시작
echo 1 > /sys/kernel/debug/tracing/tracing_on

# (DAMON 모니터링 실행 후)
cat /sys/kernel/debug/tracing/trace
# 출력 예시:
# kdamond.0-1234  [002] target_id=42 nr_regions=85
#   region: start=0x7f0000000 end=0x7f0100000
#           nr_accesses=18 age=0
#   region: start=0x7f0100000 end=0x7f0800000
#           nr_accesses=0  age=45

# 추적 중지
echo 0 > /sys/kernel/debug/tracing/tracing_on

# perf로 DAMON 이벤트 수집
perf record -e damon:damon_aggregated -a --duration 10

# BPF를 통한 DAMON 데이터 가공
bpftrace -e 'tracepoint:damon:damon_aggregated {
    printf("region %lx-%lx: acc=%u age=%u\n",
           args->start, args->end,
           args->nr_accesses, args->age);
}'
디버깅 체크리스트:
  • cat /sys/kernel/mm/damon/admin/kdamonds/0/pid가 유효한 PID를 반환하는지 확인 (kdamond 실행 중)
  • dmon_aggregated tracepoint에 리전 데이터가 출력되는지 확인 (모니터링 동작 중)
  • schemes/0/stats/nr_tried가 0이 아닌지 확인 (스킴 매칭이 발생하는지)
  • schemes/0/stats/nr_applied가 0이면 쿼터/워터마크/필터 조건 확인

파라미터 튜닝 가이드

DAMON의 효과는 파라미터 설정에 크게 좌우됩니다. 워크로드 특성에 맞는 최적 파라미터를 찾는 것이 중요합니다.

DAMON 파라미터 튜닝 트레이드오프 정밀도 (Precision) → 오버헤드 (Overhead) → 권장 영역 CPU <1%, 90%+ 정확도 보수적 sample=10ms max_regions=100 기본값 (권장) sample=5ms, max_regions=1000 공격적 sample=1ms max_regions=5000
sample_interval을 줄이고 max_nr_regions를 늘리면 정밀도가 높아지지만 CPU 오버헤드도 증가합니다
파라미터보수적 (저부하)기본값 (권장)공격적 (고정밀)튜닝 지침
sample_interval10ms5ms1ms짧을수록 정밀하나 CPU 사용 증가
aggr_interval200ms100ms50ms짧을수록 DAMOS 반응 빠름
update_interval120s60s10sVMA 변경이 잦으면 짧게
min_nr_regions101010보통 기본값 유지
max_nr_regions10010005000RSS 크기에 비례하여 조절
min_age (RECLAIM)50020050워크로드의 재접근 주기 고려
quota_ms51050CPU 여유에 맞게

체계적 튜닝 방법론

# Step 1: 기본값으로 워크로드 프로파일링
sudo damo record $(pidof my-app) --duration 60s -o baseline.json

# Step 2: 워킹셋 분포 확인
sudo damo report wss --input baseline.json
# → 워킹셋 대비 RSS가 2배 이상이면 DAMON_RECLAIM 효과적

# Step 3: DAMOS 시뮬레이션으로 회수 가능량 확인
sudo damo schemes --action stat \
    --access_rate 0 0 \
    --age 200 max \
    $(pidof my-app)
# → stat 결과가 RSS의 20% 이상이면 회수 효과 기대

# Step 4: 보수적으로 시작하여 점진적 강화
echo 500 > /sys/module/damon_reclaim/parameters/min_age
echo 5 > /sys/module/damon_reclaim/parameters/quota_ms
echo Y > /sys/module/damon_reclaim/parameters/enabled

# Step 5: 모니터링하며 min_age, quota_ms 조절
watch -n 5 "cat /sys/module/damon_reclaim/parameters/nr_reclaimed; \
             cat /proc/vmstat | grep -E 'pgscan|pgsteal'"

커널 빌드 옵션

# DAMON 관련 커널 설정 (make menuconfig)
# Memory Management options → Data Access Monitoring

CONFIG_DAMON=y                  # DAMON 코어 프레임워크
CONFIG_DAMON_VADDR=y            # vaddr Operations Set
CONFIG_DAMON_PADDR=y            # paddr Operations Set
CONFIG_DAMON_SYSFS=y            # sysfs 인터페이스 (/sys/kernel/mm/damon/)
CONFIG_DAMON_DBGFS=n            # debugfs 인터페이스 (레거시, 비권장)
CONFIG_DAMON_RECLAIM=y          # DAMON 기반 프로액티브 회수
CONFIG_DAMON_LRU_SORT=y         # DAMON 기반 LRU 정렬

# 의존성
CONFIG_MMU=y                    # 필수: MMU 지원
CONFIG_PAGE_IDLE_FLAG=y         # paddr ops에 필요

# 선택적 (디버깅)
CONFIG_DAMON_KUNIT_TEST=n       # DAMON 커널 유닛 테스트
CONFIG 옵션설명기본값프로덕션 권장
CONFIG_DAMON코어 프레임워크ny
CONFIG_DAMON_VADDR프로세스별 모니터링ny
CONFIG_DAMON_PADDR시스템 전체 모니터링ny
CONFIG_DAMON_SYSFSsysfs 인터페이스ny
CONFIG_DAMON_RECLAIM프로액티브 회수ny
CONFIG_DAMON_LRU_SORTLRU 재정렬n선택적
CONFIG_DAMON_DBGFSdebugfs (레거시)nn

내부 자료 구조

DAMON의 핵심 동작을 이해하려면 kdamond 메인 루프의 실행 흐름을 추적해야 합니다.

kdamond 메인 루프 (damon_do_kdamond()) kdamond 시작 ops.init() -- 리전 초기화 while (!kthread_should_stop()) ops.prepare_access_checks() sleep(sample_interval) ops.check_accesses() -- nr_accesses++ aggr 도달? No Yes merge_regions() -- 리전 병합 apply_schemes() -- DAMOS 적용 callback.after_aggregation() reset_aggregated() + split_regions() update 도달? Yes ops.update() No/Yes(후) * 전체 루프는 sample_interval 단위로 반복, aggr_interval/update_interval에서 추가 작업 수행
kdamond의 메인 루프: sample_interval마다 PTE 확인, aggr_interval마다 병합/DAMOS, update_interval마다 리전 갱신
/* mm/damon/core.c - kdamond 메인 루프 (대폭 단순화) */
static int kdamond_fn(void *data)
{
    struct damon_ctx *ctx = data;

    /* 리전 초기화 */
    ctx->ops.init(ctx);

    while (!kthread_should_stop() && ctx->kdamond) {
        /* 워터마크 확인 -- 조건 불충족 시 슬립 */
        if (kdamond_wait_activation(ctx))
            continue;

        /* Access Bit 클리어 (다음 체크 준비) */
        ctx->ops.prepare_access_checks(ctx);

        /* sample_interval 대기 */
        kdamond_usleep(ctx->attrs.sample_interval);

        /* Access Bit 확인 → nr_accesses 갱신 */
        ctx->ops.check_accesses(ctx);

        /* aggr_interval 도달 시 */
        if (kdamond_aggregate_interval(ctx)) {
            damon_merge_regions_of(ctx);
            damon_do_apply_schemes(ctx);     /* DAMOS 적용 */
            kdamond_call_after_aggregation(ctx);
            damon_reset_aggregated(ctx);
            damon_split_regions_of(ctx);
        }

        /* update_interval 도달 시 */
        if (kdamond_update_interval(ctx))
            ctx->ops.update(ctx);
    }

    ctx->callback.before_terminate(ctx);
    return 0;
}
설명 kdamond_fn은 kdamond 커널 스레드의 메인 함수입니다. 매 sample_interval마다 prepare_access_checks()로 Access Bit를 클리어하고, 다음 주기에 check_accesses()로 확인합니다. aggr_interval에 도달하면 리전 병합, DAMOS 스킴 적용, 콜백 호출, 리전 분할을 순서대로 수행합니다. update_interval에 도달하면 VMA 변경을 반영하여 리전을 재초기화합니다. kdamond_wait_activation()은 워터마크 조건을 확인하여, 메모리가 충분하면 모니터링을 일시 중단합니다.
/* mm/damon/core.c - damon_split_regions_of() (단순화) */
static void damon_split_regions_of(
    struct damon_ctx *ctx,
    struct damon_target *t)
{
    struct damon_region *r, *next;
    unsigned int nr_new_regs = 0;

    damon_for_each_region_safe(r, next, t) {
        if (t->nr_regions >= ctx->attrs.max_nr_regions)
            break;
        /* 리전 크기가 2 * min_region_sz 이상이면 분할 */
        if (damon_sz_region(r) > 2 * min_region_sz) {
            struct damon_region *new;
            unsigned long mid = r->ar.start + damon_sz_region(r) / 2;
            new = damon_new_region(mid, r->ar.end);
            new->nr_accesses = r->nr_accesses;
            new->age = r->age;
            r->ar.end = mid;
            damon_insert_region(new, r, next, t);
            nr_new_regs++;
        }
    }
}
설명

damon_split_regions_of()는 집계 주기(aggr_interval)마다 호출되어, 크기가 큰 리전을 절반으로 분할합니다. 분할 조건은 리전 크기가 2 * min_region_sz 이상이고, 전체 리전 수가 max_nr_regions 미만인 경우입니다.

분할 시 새 리전은 원본의 nr_accessesage 값을 상속받습니다. 이는 분할 직후에도 접근 패턴 정보가 유지되어 DAMOS 스킴 매칭이 올바르게 동작하기 위함입니다. 병합(merge)이 동질적인 리전을 합쳐 오버헤드를 줄이는 역할이라면, 분할(split)은 접근 패턴이 다른 영역을 세분화하여 정밀도를 높이는 역할을 합니다.

/* mm/damon/core.c - damon_do_apply_schemes() (단순화) */
static void damon_do_apply_schemes(
    struct damon_ctx *ctx)
{
    struct damos *s;

    damon_for_each_scheme(s, ctx) {
        struct damon_target *t;
        /* 워터마크 확인 */
        if (!damos_valid_wmarks(s))
            continue;
        /* 쿼터 리셋 확인 */
        damos_check_quota_reset(s);

        damon_for_each_target(t, ctx) {
            struct damon_region *r;
            damon_for_each_region(r, t) {
                /* 패턴 매칭 */
                if (!damos_access_pattern_match(s, r))
                    continue;
                /* 필터 확인 */
                if (damos_filter_out(s, t, r))
                    continue;
                /* 쿼터 확인 */
                if (damos_quota_exceeded(s))
                    break;
                /* 액션 적용 */
                sz = ctx->ops.apply_scheme(ctx, t, r, s);
                s->stat.nr_applied++;
                s->stat.sz_applied += sz;
            }
        }
    }
}
설명

damon_do_apply_schemes()는 DAMOS의 핵심 실행 함수로, 등록된 모든 스킴을 순회하며 조건에 맞는 리전에 액션을 적용합니다. 실행 흐름은 4단계 필터링을 거칩니다:

  1. 워터마크 확인: damos_valid_wmarks()가 현재 메모리 상태(빈 메모리 비율)를 워터마크와 비교합니다. 빈 메모리가 high 이상이면 스킴을 건너뛰고, low 미만이면 적극 적용합니다.
  2. 패턴 매칭: damos_access_pattern_match()가 리전의 nr_accesses, age, 크기를 스킴의 min/max 범위와 비교합니다.
  3. 필터 확인: damos_filter_out()이 anon/file, memcg, 주소 범위 등의 필터 조건을 평가하여 불필요한 페이지를 제외합니다.
  4. 쿼터 확인: damos_quota_exceeded()가 시간/크기 쿼터 초과 여부를 확인하여 과도한 자원 소비를 방지합니다.

ctx->ops.apply_scheme()은 Operations Set에 등록된 구현체를 호출하며, paddr의 경우 damon_pa_apply_scheme()이 pageout, lru_prio, stat 등의 액션을 수행합니다. 통계(nr_applied, sz_applied)는 sysfs의 stats/ 디렉토리를 통해 사용자 공간(User Space)에서 확인할 수 있습니다.

damon_attrs 구조체(Struct)

/* include/linux/damon.h */
struct damon_attrs {
    unsigned long sample_interval;     /* 마이크로초 단위 */
    unsigned long aggr_interval;
    unsigned long ops_update_interval;
    unsigned long min_nr_regions;
    unsigned long max_nr_regions;
};

damos_watermarks 구조체

/* include/linux/damon.h - 워터마크 */
struct damos_watermarks {
    enum damos_wmark_metric metric;  /* DAMOS_WMARK_FREE_MEM_RATE */
    unsigned long interval;           /* 확인 주기 (마이크로초) */
    unsigned long high;               /* 높은 워터마크 (퍼밀, 1/1000) */
    unsigned long mid;                /* 중간 워터마크 */
    unsigned long low;                /* 낮은 워터마크 */
};
설명 워터마크는 퍼밀(permil, 1/1000) 단위로 설정합니다. high=500이면 빈 메모리가 전체의 50% 이상일 때 DAMOS 스킴을 비활성화합니다. low=200이면 빈 메모리가 20% 미만일 때 적극적으로 스킴을 적용합니다. mid는 현재 상태를 유지하는 구간입니다 (히스테리시스).

성능 영향 분석

DAMON 성능 오버헤드 (다양한 설정) 0% 1% 2% 3% 4% 5% CPU 오버헤드 베이스라인 (DAMON 없음) 0.3% 보수적 10ms/100r 0.7% 기본값 5ms/1000r 2.0% 공격적 1ms/5000r 1.0% 기본+RECLAIM 5ms/1000r 4.0%+ 전체 페이지 스캔 비교군
DAMON의 기본 설정에서 CPU 오버헤드는 1% 미만이며, 전체 페이지 스캔 대비 5~6배 효율적
측정 항목DAMON 비활성DAMON 기본값DAMON + RECLAIM비고
CPU 오버헤드0%0.5~0.8%0.8~1.2%워크로드/RSS 크기에 따라 변동
메모리 사용0~200KB~300KB리전 메타데이터 + 스킴 구조체
TLB miss 증가0%<0.1%<0.5%Access Bit 클리어에 의한 추가 TLB miss
메모리 절약-모니터링만10~30% RSS 감소콜드 페이지 회수 효과
주의사항: DAMON의 Access Bit 클리어는 소프트 TLB miss를 유발할 수 있습니다. sample_interval이 매우 짧으면(1ms 미만) TLB thrashing이 발생하여 오히려 성능이 저하될 수 있습니다. 프로덕션에서는 반드시 벤치마크를 통해 최적 값을 확인하세요.

perf를 이용한 DAMON 오버헤드 측정

perf 도구를 사용하여 kdamond 커널 스레드의 CPU 사용률과 TLB miss 증가량을 정량적으로 측정할 수 있습니다.

# kdamond 스레드 PID 확인
KDAMOND_PID=$(pgrep -x kdamond)
echo "kdamond PID: ${KDAMOND_PID}"

# 1. kdamond의 CPU 사용률 프로파일링 (30초간)
perf stat -p ${KDAMOND_PID} -e task-clock,context-switches,page-faults -- sleep 30

# 2. kdamond 함수별 CPU 시간 분석
perf record -p ${KDAMOND_PID} -g -- sleep 10
perf report --sort comm,dso,symbol

# 3. DAMON 활성화 전후 TLB miss 비교
# (먼저 DAMON 비활성 상태에서 베이스라인 측정)
perf stat -e dTLB-load-misses,dTLB-store-misses,iTLB-load-misses \
    -a -- sleep 30

# (DAMON 활성화 후 동일 측정)
echo Y > /sys/module/damon_reclaim/parameters/enabled
perf stat -e dTLB-load-misses,dTLB-store-misses,iTLB-load-misses \
    -a -- sleep 30

# 4. DAMON 관련 커널 함수 호출 빈도 측정
perf stat -e probe:damon_do_apply_schemes,probe:kdamond_fn \
    -a -- sleep 10 2>&1 || \
echo "프로브 미설정 시: perf probe -a damon_do_apply_schemes 실행 필요"
설명 perf stat -p ${KDAMOND_PID}는 kdamond 스레드의 CPU 시간을 직접 측정합니다. task-clock 이벤트는 해당 스레드가 실제로 사용한 CPU 시간(밀리초)을 보여줍니다. perf record -g는 콜 그래프를 포함한 상세 프로파일을 수집하여, damon_do_apply_schemes(), damon_pa_check_accesses() 등 어떤 DAMON 함수가 가장 많은 시간을 소비하는지 확인할 수 있습니다. TLB miss 비교는 DAMON의 Access Bit 클리어가 실제로 얼마나 TLB 성능에 영향을 미치는지 정량적으로 보여줍니다.

bpftrace로 DAMON 이벤트 추적

bpftrace를 사용하면 DAMON의 내부 이벤트를 실시간으로 추적할 수 있습니다. 리전 분할/병합 빈도, DAMOS 액션 실행 횟수, 쿼터 초과 등을 모니터링합니다.

# 1. DAMON 트레이스포인트 확인
cat /sys/kernel/debug/tracing/available_events | grep damon

# 2. bpftrace: DAMOS 액션 실행 추적
bpftrace -e '
tracepoint:damon:damos_before_apply {
    @actions[str(args->action)] = count();
    @sz_sum = sum(args->sz);
}

interval:s:5 {
    printf("--- DAMOS actions (5s window) ---\n");
    print(@actions); clear(@actions);
    printf("Total bytes tried: %lld\n", @sz_sum);
    @sz_sum = 0;
}'

# 3. bpftrace: kdamond 실행 주기 및 지연 측정
bpftrace -e '
kprobe:kdamond_fn {
    @start[tid] = nsecs;
}
kretprobe:kdamond_fn /@start[tid]/ {
    @latency_us = hist((nsecs - @start[tid]) / 1000);
    delete(@start[tid]);
}'

# 4. bpftrace: 리전 분할/병합 빈도 추적
bpftrace -e '
kprobe:damon_split_region_at {
    @splits = count();
}
kprobe:damon_merge_two {
    @merges = count();
}
interval:s:10 {
    printf("10s: splits=%lld merges=%lld\n", @splits, @merges);
    @splits = 0; @merges = 0;
}'
설명 tracepoint:damon:damos_before_apply는 DAMOS 스킴이 리전에 적용되기 직전에 발생하는 트레이스포인트입니다. args->action은 적용된 액션(pageout, hugepage 등), args->sz는 대상 리전의 크기를 나타냅니다. kdamond_fn은 kdamond 커널 스레드의 메인 루프 함수로, 실행 지연을 측정하면 모니터링 주기가 정상적으로 유지되는지 확인할 수 있습니다. 리전 분할/병합 빈도가 과도하게 높다면 min_nr_regions/max_nr_regions 범위를 조정하거나 aggr_interval을 늘려야 합니다.

벤치마크 실행 및 결과 해석

DAMON의 성능 영향을 정확히 파악하려면 체계적인 벤치마크가 필요합니다. 다음은 DAMON 활성화 전후를 비교하는 벤치마크 절차입니다.

#!/bin/bash
# DAMON 성능 벤치마크 스크립트

RESULTS_DIR="/tmp/damon-bench"
mkdir -p ${RESULTS_DIR}

run_benchmark() {
    local label=$1
    echo "=== ${label} 벤치마크 시작 ==="

    # 캐시 드롭 후 측정 (공정한 비교)
    sync; echo 3 > /proc/sys/vm/drop_caches

    # 1. 메모리 집약 워크로드: stress-ng
    perf stat -o ${RESULTS_DIR}/${label}-stress.txt \
        -e task-clock,dTLB-load-misses,page-faults \
        -- stress-ng --vm 2 --vm-bytes 1G --timeout 60s

    # 2. 실제 워크로드 시뮬레이션: redis-benchmark
    redis-benchmark -t set,get -n 1000000 -d 256 \
        > ${RESULTS_DIR}/${label}-redis.txt 2>&1

    # 3. 메모리 사용량 스냅샷
    cat /proc/meminfo | grep -E "MemFree|MemAvailable|SwapCached|AnonPages|Mapped" \
        > ${RESULTS_DIR}/${label}-meminfo.txt

    # 4. vmstat 스냅샷 (페이지 폴트, 스왑 활동)
    vmstat 1 10 > ${RESULTS_DIR}/${label}-vmstat.txt
}

# A. DAMON 비활성 베이스라인
echo N > /sys/module/damon_reclaim/parameters/enabled 2>/dev/null
sleep 5
run_benchmark "baseline"

# B. DAMON 기본값 활성화
echo 5000 > /sys/module/damon_reclaim/parameters/sample_interval
echo 100000 > /sys/module/damon_reclaim/parameters/aggr_interval
echo 200 > /sys/module/damon_reclaim/parameters/min_age
echo 10 > /sys/module/damon_reclaim/parameters/quota_ms
echo Y > /sys/module/damon_reclaim/parameters/enabled
sleep 5
run_benchmark "damon-default"

# C. 결과 비교
echo "=== 결과 비교 ==="
echo "--- TLB miss 비교 ---"
grep "dTLB-load-misses" ${RESULTS_DIR}/*-stress.txt
echo "--- 메모리 절약 ---"
diff ${RESULTS_DIR}/baseline-meminfo.txt ${RESULTS_DIR}/damon-default-meminfo.txt
echo "--- DAMON 회수 통계 ---"
cat /sys/module/damon_reclaim/parameters/nr_reclaimed
설명 벤치마크는 캐시를 드롭한 후 실행하여 공정한 비교를 보장합니다. stress-ng --vm은 메모리를 집중적으로 할당/해제하는 워크로드로, DAMON의 TLB miss 영향을 가장 잘 보여줍니다. redis-benchmark는 실제 서비스와 유사한 메모리 접근 패턴을 생성하여 DAMON의 콜드 페이지 탐지 정확도를 검증합니다. 결과 해석 시 핵심 지표는 (1) dTLB-load-misses 증가율이 1% 미만인지, (2) MemAvailable이 증가했는지 (콜드 페이지 회수 효과), (3) page-faults가 과도하게 증가하지 않았는지입니다.

커널 내부 DAMON API

커널 모듈(Kernel Module)에서 DAMON을 프로그래밍적으로 사용하는 주요 API입니다.

/* mm/damon/core.c - 주요 API */

/* DAMON context 생성/해제 */
struct damon_ctx *damon_new_ctx(void);
void damon_destroy_ctx(struct damon_ctx *ctx);

/* Operations Set 등록 */
int damon_select_ops(struct damon_ctx *ctx,
                     enum damon_ops_id id);

/* 모니터링 대상 추가 */
struct damon_target *damon_new_target(void);
void damon_add_target(struct damon_ctx *ctx,
                      struct damon_target *t);

/* 리전 추가 */
struct damon_region *damon_new_region(
    unsigned long start, unsigned long end);
void damon_add_region(struct damon_region *r,
                      struct damon_target *t);

/* DAMOS 스킴 추가 */
struct damos *damon_new_scheme(
    struct damos_access_pattern *pattern,
    enum damos_action action,
    unsigned long apply_interval_us,
    struct damos_quota *quota,
    struct damos_watermarks *wmarks);
void damon_set_schemes(struct damon_ctx *ctx,
                       struct damos **schemes,
                       ssize_t nr_schemes);

/* 모니터링 시작/중지 */
int damon_start(struct damon_ctx **ctxs,
               int nr_ctxs, bool exclusive);
int damon_stop(struct damon_ctx **ctxs, int nr_ctxs);
설명 커널 모듈에서 DAMON을 사용하려면 damon_new_ctx()로 컨텍스트를 생성하고, damon_select_ops()로 Operations Set을 선택한 뒤, damon_add_target()으로 모니터링 대상을 추가합니다. DAMOS 스킴을 설정하려면 damon_new_scheme()으로 스킴을 생성하여 damon_set_schemes()로 등록합니다. damon_start()를 호출하면 kdamond 커널 스레드가 생성되어 모니터링을 시작합니다. DAMON_RECLAIM과 DAMON_LRU_SORT가 이 API의 대표적인 사용 사례입니다.

안티패턴과 주의사항

안티패턴 1: 과도한 샘플링

# 잘못된 설정: sample_interval이 너무 짧음
echo 100 > .../monitoring_attrs/intervals/sample_us   # 0.1ms!
echo 5000 > .../nr_regions/max                        # 5000 리전!
# → CPU 오버헤드 5%+, TLB thrashing 발생

# 올바른 설정: 기본값 또는 보수적 설정
echo 5000 > .../monitoring_attrs/intervals/sample_us  # 5ms (기본값)
echo 1000 > .../nr_regions/max                        # 1000 리전 (기본값)

안티패턴 2: 쿼터 없는 DAMOS

# 잘못된 설정: 쿼터 없이 pageout 스킴 활성화
echo pageout > .../schemes/0/action
echo 0 > .../schemes/0/quotas/ms     # 무제한 시간!
echo 0 > .../schemes/0/quotas/bytes  # 무제한 크기!
# → 한 번에 수 GB를 회수하여 I/O 폭주

# 올바른 설정: 항상 쿼터 설정
echo 10 > .../schemes/0/quotas/ms          # 10ms/주기
echo 128000000 > .../schemes/0/quotas/bytes # 128MB/주기

안티패턴 3: min_age가 너무 낮은 RECLAIM

# 잘못된 설정: 1초만 미접근이면 회수
echo 10 > /sys/module/damon_reclaim/parameters/min_age
# → 버스트 워크로드에서 곧 재접근될 페이지까지 회수
# → page fault 증가 → 성능 저하

# 올바른 설정: 워크로드의 재접근 패턴 고려
echo 200 > /sys/module/damon_reclaim/parameters/min_age  # 20초 (기본값)

DAMON vs 기존 메커니즘 종합 비교

특성DAMONidle page trackingperf mem/proc/PID/pagemap
커널 내장v5.15+v4.3+v2.6.31+v2.6.25+
자동 액션DAMOS없음없음없음
오버헤드<1% CPU~5% (풀스캔)1~3% (PMU 샘플링)높음 (PT 순회)
정밀도리전 단위페이지 단위주소 단위 (PMU)페이지 단위
하드웨어 의존PTE Access BitPTE Idle BitPMU (IBS/PEBS)PTE
실시간 대응가능 (DAMOS)불가 (폴링)불가 (오프라인)불가 (폴링)
NUMA 최적화v6.9+불가가능 (분석)불가

시나리오별 메커니즘 선택 가이드

사용 시나리오권장 메커니즘이유
프로덕션 메모리 최적화DAMON + DAMOS자동 액션(회수/프로모션)과 쿼터로 안정적 운영 가능
원샷 메모리 프로파일링idle page tracking정확한 페이지 단위 접근 여부 확인, 일회성 분석에 적합
NUMA 접근 패턴 분석perf memPMU 기반 로컬/리모트 접근 비율 측정, numastat 보완
특정 프로세스 메모리 맵(Memory Map)핑/proc/PID/pagemap가상→물리 매핑, RSS/WSS 정밀 측정
콜드 페이지 자동 회수DAMON_RECLAIM유일하게 자동 PAGEOUT을 지원하는 저오버헤드 메커니즘
개발/디버깅 단계perf mem + damo시각적 히트맵으로 접근 패턴 파악 후 DAMON 정책 설계

idle page tracking vs DAMON 코드 비교

idle page tracking은 /sys/kernel/mm/page_idle/bitmap을 통해 페이지별 idle 비트를 설정/확인하는 방식입니다. DAMON과의 접근 방식 차이를 코드로 비교합니다.

# === idle page tracking 방식 ===
# 1단계: 대상 프로세스의 모든 PFN 수집
TARGET_PID=1234
python3 -c "
import struct, os

pagemap = open(f'/proc/{os.environ[\"PID\"]}/pagemap', 'rb')
maps = open(f'/proc/{os.environ[\"PID\"]}/maps', 'r')

pfns = []
for line in maps:
    parts = line.split()
    start, end = [int(x, 16) for x in parts[0].split('-')]
    for vaddr in range(start, end, 4096):
        pagemap.seek(vaddr // 4096 * 8)
        entry = struct.unpack('Q', pagemap.read(8))[0]
        if entry & (1 << 63):  # present
            pfns.append(entry & ((1 << 55) - 1))

# 2단계: idle 비트 설정 (전체 PFN 순회)
idle_bitmap = open('/sys/kernel/mm/page_idle/bitmap', 'r+b')
for pfn in pfns:
    idle_bitmap.seek(pfn // 64 * 8)
    idle_bitmap.write(struct.pack('Q', 1 << (pfn % 64)))

print(f'Set idle bit for {len(pfns)} pages')
" PID=${TARGET_PID}

# 3단계: 일정 시간 대기 후 idle 비트 확인
sleep 30

# 4단계: 여전히 idle인 페이지 = 콜드 페이지
# (동일 PFN 목록을 다시 순회하여 idle 비트 확인)

# === DAMON 방식 ===
# 동일한 목적을 달성하지만 코드가 훨씬 간단
DAMON_BASE="/sys/kernel/mm/damon/admin/kdamonds/0"
CTX="${DAMON_BASE}/contexts/0"

# 리전 기반 샘플링으로 자동 모니터링 (전체 PFN 순회 불필요)
echo vaddr > ${CTX}/operations
echo 1 > ${CTX}/targets/nr_targets
echo ${TARGET_PID} > ${CTX}/targets/0/pid_target
echo 5000 > ${CTX}/monitoring_attrs/intervals/sample_us
echo 100000 > ${CTX}/monitoring_attrs/intervals/aggr_us
echo commit > ${DAMON_BASE}/state
echo on > ${DAMON_BASE}/state

# 30초 후 결과 확인
sleep 30
echo update_schemes_stats > ${DAMON_BASE}/state
# damo를 사용하면 리전별 접근 빈도를 시각적으로 확인 가능
damo report access --input /sys/kernel/mm/damon/admin
설명 idle page tracking은 모든 페이지의 PFN을 수집하고, idle 비트를 하나씩 설정하고, 대기 후 다시 확인하는 3단계 과정이 필요합니다. 대상 프로세스의 RSS가 클수록 순회해야 할 PFN 수가 선형으로 증가하여 오버헤드가 급증합니다(O(페이지 수)). 반면 DAMON은 주소 공간을 리전으로 묶어 리전당 하나의 랜덤 페이지만 샘플링하므로 O(리전 수)의 일정한 오버헤드를 유지합니다. 다만 idle page tracking은 페이지 단위의 정확한 결과를 제공하고, DAMON은 리전 단위의 통계적 추정 결과를 제공한다는 정밀도 차이가 있습니다.

자동 쿼터 튜닝 (DAMOS Quota Goal)

최신 공식 문서 기준의 DAMOS Quota Goal은 사용자가 명시적 쿼터 값을 고정하는 대신, 목표 메트릭을 지정하면 DAMON이 effective_bytes와 유효 시간 쿼터를 자동으로 조절하는 피드백 루프입니다. 이제 목표는 PSI 하나에만 머무르지 않고, NUMA 노드 메모리 사용률과 memcg 경로별 사용률까지 지정할 수 있습니다.

/* include/linux/damon.h - 쿼터 목표 구조체 */
struct damos_quota_goal {
    enum damos_quota_goal_metric metric;
    /* DAMOS_QUOTA_USER_INPUT: 사용자 직접 입력 */
    /* DAMOS_QUOTA_SOME_MEM_PSI_US: PSI some 값 */
    /* DAMOS_QUOTA_NODE_MEM_USED_BP / _FREE_BP */
    /* DAMOS_QUOTA_NODE_MEMCG_USED_BP / _FREE_BP */
    /* DAMOS_QUOTA_ACTIVE_MEM_BP / _INACTIVE_MEM_BP */
    unsigned long target_value;      /* 목표 값 */
    unsigned long current_value;     /* 현재 값 (커널이 갱신) */
    int nid;                        /* NUMA 노드 기반 목표일 때 사용 */
    char *path;                     /* memcg 경로 기반 목표일 때 사용 */
    struct list_head list;
};
설명 DAMOS_QUOTA_SOME_MEM_PSI_US는 메모리 PSI(Pressure Stall Information)의 some 값(마이크로초)을 목표로 합니다. 예를 들어 target_value=10000이면 DAMON은 PSI some이 10ms를 넘지 않도록 쿼터를 조절합니다. 최신 문서는 여기에 더해 특정 NUMA 노드의 사용률, 특정 memcg 경로의 사용률, active/inactive 메모리 비율도 목표로 둘 수 있다고 설명합니다. 여러 goal을 동시에 두면 DAMON은 각 goal의 현재 값을 갱신한 뒤 가장 적절한 값으로 유효 쿼터를 계산합니다.
target_metric의미추가 입력
user_input사용자 공간이 current_value를 직접 넣는 방식입니다.주기적으로 값을 밀어 넣는 외부 제어 루프가 필요합니다.
some_mem_psi_us메모리 PSI some 지연시간을 목표로 합니다.추가 입력 없음
node_mem_used_bp, node_mem_free_bp특정 NUMA 노드의 사용/유휴 비율을 목표로 합니다.nid
node_memcg_used_bp, node_memcg_free_bp특정 memcg가 노드별로 소비하는 비율을 목표로 합니다.nid, path
active_mem_bp, inactive_mem_bpactive/inactive LRU 비율을 목표로 합니다.추가 입력 없음

자동 튜닝 알고리즘

DAMON의 자동 쿼터 튜닝은 비례 제어(proportional control) 기반으로 동작합니다:

/* mm/damon/core.c - 쿼터 자동 조절 (단순화) */
static void damos_adjust_quota(
    struct damos *s)
{
    struct damos_quota *q = &s->quota;
    struct damos_quota_goal *g;
    unsigned long score;

    list_for_each_entry(g, &q->goals, list) {
        /* 현재 메트릭 수집 */
        damos_quota_goal_update(g);

        /* 목표 대비 비율 계산 */
        if (g->current_value < g->target_value) {
            /* 여유 있음 → 쿼터 축소 */
            score = g->current_value * 10000 / g->target_value;
        } else {
            /* 압박 상태 → 쿼터 확대 */
            score = g->current_value * 10000 / g->target_value;
        }
    }

    /* 유효 쿼터 조절 (최소/최대 제한 적용) */
    q->esz = q->esz * score / 10000;
    q->esz = clamp(q->esz, DAMOS_QUOTA_MIN, q->sz);
}
# sysfs에서 자동 쿼터 튜닝 설정
# PSI some 5ms 이하를 목표로 자동 조절
echo 1 > .../schemes/0/quotas/goals/nr_goals
echo some_mem_psi_us > .../schemes/0/quotas/goals/0/target_metric
echo 5000 > .../schemes/0/quotas/goals/0/target_value

# 초기 쿼터는 보수적으로 설정 (자동 튜닝이 조절)
echo 5 > .../schemes/0/quotas/ms
echo 64000000 > .../schemes/0/quotas/bytes
echo commit_schemes_quota_goals > .../kdamonds/0/state
echo update_schemes_effective_quotas > .../kdamonds/0/state
cat .../schemes/0/quotas/effective_bytes
# memcg + NUMA 기준 목표 예시
echo 1 > .../schemes/0/quotas/goals/nr_goals
echo node_memcg_used_bp > .../schemes/0/quotas/goals/0/target_metric
echo 650 > .../schemes/0/quotas/goals/0/target_value
echo 1 > .../schemes/0/quotas/goals/0/nid
echo /kubepods.slice/pod123 > .../schemes/0/quotas/goals/0/path
echo commit_schemes_quota_goals > .../kdamonds/0/state
프로덕션 권장: 자동 쿼터 튜닝은 워크로드 변동이 큰 환경(CI/CD 파이프라인, 웹 서버, 다중 테넌트 memcg)에서 특히 유용합니다. 고정 쿼터는 피크 시에 부족하고 유휴 시에 과잉되지만, quota goal은 현재 PSI 또는 노드별 사용률을 보고 실시간으로 적응합니다.

DAMON_STAT 경량 모니터링 모듈

최신 관리자 문서는 DAMON_STAT을 "시스템 전체 물리 메모리 접근 패턴을 위한 정적이고 단순한 모듈"로 설명합니다. 이 모듈은 DAMOS 액션을 수행하지 않고, 추정 메모리 대역폭(Bandwidth)메모리 유휴 시간 분위수를 바로 읽을 수 있게 해 줍니다. 운영자가 "정책 적용" 전에 시스템 상태를 낮은 비용으로 관찰할 때 유용합니다.

항목설명운영 의미
estimated_memory_bandwidth추정 메모리 대역폭입니다.메모리 집약 구간과 유휴 구간을 빠르게 구분할 수 있습니다.
memory_idle_ms_percentiles메모리 유휴 시간의 분위수입니다.콜드 데이터가 얼마나 오래 방치되는지 분포로 볼 수 있습니다.
자동 간격 튜닝기본적으로 관찰된 접근 이벤트 비율을 약 4% 수준으로 맞추도록 interval을 조절합니다.정확도와 오버헤드 사이 균형을 자동으로 유지합니다.
오버헤드 목표관리자 문서는 몇몇 프로덕션 서버에서 단일 CPU의 0.x% 수준 시간만 사용한다고 설명합니다.상시 켜 두는 관찰용 모듈로 쓰기 좋습니다.
# DAMON_STAT 활성화와 결과 확인
cat /sys/module/damon_stat/parameters/enabled
echo Y > /sys/module/damon_stat/parameters/enabled

cat /sys/module/damon_stat/parameters/aggr_interval_us
cat /sys/module/damon_stat/parameters/min_sample_us
cat /sys/module/damon_stat/parameters/max_sample_us
cat /sys/module/damon_stat/parameters/estimated_memory_bandwidth
cat /sys/module/damon_stat/parameters/memory_idle_ms_percentiles
언제 유용한가: DAMON_RECLAIM이나 LRU_SORT를 바로 켜기 전에, 먼저 DAMON_STAT으로 "이 서버에 실제로 긴 유휴 꼬리가 있는가"를 확인하면 불필요한 정책 실험을 줄일 수 있습니다.

접근 패턴 분석 기법

DAMON의 모니터링 데이터를 효과적으로 분석하면 워크로드의 메모리 사용 특성을 정밀하게 파악할 수 있습니다.

DAMON 접근 패턴 히트맵 예시 주소 공간 0x7f000 0x7f100 0x7f200 0x7f300 0x7f400 0x7f500 0x7f600 0x7f700 ── Heap ── ──── mmap 영역 ──── ── Stack ── 시간 t0 t1 t2 t3 t4 t5 핫 (Hot) 따뜻 (Warm) 시원 (Cool) 콜드 (Cold) ↑ mmap: 시간 경과 시 냉각
DAMON이 관찰한 접근 패턴 히트맵: Heap/Stack은 지속적으로 핫, mmap 영역은 시간이 지나면서 점차 냉각되어 DAMOS 회수 대상이 됨

워킹셋 크기 분석

워킹셋(Working Set Size)은 특정 시간 동안 실제로 접근된 메모리 양입니다. DAMON의 nr_accesses > 0인 리전의 크기 합이 워킹셋의 근사치입니다.

# damo로 워킹셋 분석
sudo damo record $(pidof redis-server) --duration 120s -o redis.json

# 시간대별 워킹셋 변화 확인
sudo damo report wss --input redis.json --sortby time

# 워킹셋 분포 히스토그램
sudo damo report wss --input redis.json --percentiles 10 25 50 75 90 95 99
# 출력 예시:
# percentile  wss
# 10          128MB    (최소 활성)
# 25          256MB    (1사분위)
# 50          512MB    (중앙값)
# 75          1.2GB    (3사분위)
# 90          1.8GB    (p90)
# 95          2.1GB    (p95)
# 99          2.4GB    (p99)
# → RSS 4GB 중 약 50%가 일상적으로 사용되지 않음
# → DAMON_RECLAIM으로 ~2GB 회수 가능

핫/콜드 메모리 분류

분류nr_accesses 범위비율 (일반적)최적 처리
핫 (Hot)aggr/sample의 80%+10~30%THP 프로모션, DRAM 고정
웜 (Warm)aggr/sample의 20~80%20~40%LRU active 유지
쿨 (Cool)aggr/sample의 1~20%10~20%LRU inactive 이동
콜드 (Cold)0 (age > threshold)20~50%프로액티브 회수, CXL 디모션
# 핫/콜드 분포를 bpftrace로 실시간 확인
bpftrace -e '
tracepoint:damon:damon_aggregated {
    @hot   = count(args->nr_accesses >= 15);
    @warm  = count(args->nr_accesses >= 5 && args->nr_accesses < 15);
    @cool  = count(args->nr_accesses >= 1 && args->nr_accesses < 5);
    @cold  = count(args->nr_accesses == 0);
    @total_cold_bytes = sum(args->nr_accesses == 0 ?
        (args->end - args->start) : 0);
}
interval:s:10 {
    printf("hot=%d warm=%d cool=%d cold=%d cold_bytes=%lld\n",
           @hot, @warm, @cool, @cold, @total_cold_bytes);
    clear(@hot); clear(@warm); clear(@cool); clear(@cold);
    clear(@total_cold_bytes);
}'

접근 빈도 히스토그램

# DAMON 리전 데이터를 사용한 접근 빈도 히스토그램 생성
bpftrace -e '
tracepoint:damon:damon_aggregated {
    @accesses = lhist(args->nr_accesses, 0, 20, 1);
    @sizes[args->nr_accesses] =
        sum(args->end - args->start);
}
END {
    printf("\n--- 접근 빈도별 메모리 크기 분포 ---\n");
    print(@sizes);
}'

프로덕션 운영 플레이북

단계 1: 프로파일링 (관측만)

# 1주일간 워크로드 프로파일링
# stat 액션으로 실제 회수 없이 데이터만 수집

# sysfs 설정
echo 1 > /sys/kernel/mm/damon/admin/kdamonds/nr_kdamonds
echo 1 > .../kdamonds/0/contexts/nr_contexts
echo paddr > .../kdamonds/0/contexts/0/operations

# 모니터링 파라미터
echo 5000 > .../contexts/0/monitoring_attrs/intervals/sample_us
echo 100000 > .../contexts/0/monitoring_attrs/intervals/aggr_us
echo 60000000 > .../contexts/0/monitoring_attrs/intervals/update_us

# stat 스킴 (콜드 페이지 크기만 측정)
echo 1 > .../contexts/0/schemes/nr_schemes
echo stat > .../contexts/0/schemes/0/action
echo 0 > .../contexts/0/schemes/0/access_pattern/nr_accesses/min
echo 0 > .../contexts/0/schemes/0/access_pattern/nr_accesses/max
echo 200 > .../contexts/0/schemes/0/access_pattern/age/min

# 시작
echo commit > .../kdamonds/0/state
echo on > .../kdamonds/0/state

# 매일 통계 수집 (cron에 등록)
echo update_schemes_stats > .../kdamonds/0/state
DATE=$(date +%Y%m%d)
echo "$DATE nr_tried=$(cat .../schemes/0/stats/nr_tried) \
sz_tried=$(cat .../schemes/0/stats/sz_tried)" >> /var/log/damon-stats.log

단계 2: 스테이징 환경 테스트

# 프로파일링 결과 기반으로 보수적 DAMOS 적용

# DAMON_RECLAIM으로 간편 시작
echo 300 > /sys/module/damon_reclaim/parameters/min_age       # 30초 콜드
echo 5 > /sys/module/damon_reclaim/parameters/quota_ms         # 5ms (보수적)
echo 64000000 > /sys/module/damon_reclaim/parameters/quota_sz  # 64MB
echo 500 > /sys/module/damon_reclaim/parameters/wmarks_high    # 50%
echo 400 > /sys/module/damon_reclaim/parameters/wmarks_mid     # 40%
echo 200 > /sys/module/damon_reclaim/parameters/wmarks_low     # 20%
echo Y > /sys/module/damon_reclaim/parameters/enabled

# 성능 지표 모니터링 (A/B 비교)
while true; do
    echo "$(date) \
reclaimed=$(cat /sys/module/damon_reclaim/parameters/nr_reclaimed) \
pgscan=$(grep pgscan_direct /proc/vmstat | awk '{print $2}') \
pgfault=$(grep pgfault /proc/vmstat | awk '{print $2}') \
psi_mem=$(cat /proc/pressure/memory | head -1)"
    sleep 60
done >> /var/log/damon-perf.log

단계 3: 프로덕션 점진적 롤아웃

# 카나리 배포: 전체 호스트의 5%에 먼저 적용
# 1주일 모니터링 후 문제없으면 25% → 50% → 100%

# 프로덕션 최종 설정 (예시)
echo 200 > /sys/module/damon_reclaim/parameters/min_age
echo 10 > /sys/module/damon_reclaim/parameters/quota_ms
echo 128000000 > /sys/module/damon_reclaim/parameters/quota_sz

# 자동 쿼터 튜닝 활성화 (v6.8+)
# → PSI 기반으로 자동 조절하므로 수동 튜닝 부담 감소

# 롤백 절차
echo N > /sys/module/damon_reclaim/parameters/enabled
# → 즉시 회수 중단, 기존 페이지에 영향 없음

모니터링 알림 설정

# Prometheus + Grafana 연동 (node_exporter custom collector)
# /var/lib/node_exporter/textfile/damon.prom

cat <<'EOF' > /usr/local/bin/damon-metrics.sh
#!/bin/bash
METRICS=/var/lib/node_exporter/textfile/damon.prom
{
  echo "# HELP damon_reclaim_nr_reclaimed Total pages reclaimed by DAMON"
  echo "# TYPE damon_reclaim_nr_reclaimed counter"
  echo "damon_reclaim_nr_reclaimed $(cat /sys/module/damon_reclaim/parameters/nr_reclaimed 2>/dev/null || echo 0)"

  echo "# HELP damon_reclaim_bytes_reclaimed Total bytes reclaimed"
  echo "# TYPE damon_reclaim_bytes_reclaimed counter"
  echo "damon_reclaim_bytes_reclaimed $(cat /sys/module/damon_reclaim/parameters/bytes_reclaimed 2>/dev/null || echo 0)"
} > ${METRICS}.tmp
mv ${METRICS}.tmp ${METRICS}
EOF
chmod +x /usr/local/bin/damon-metrics.sh

# cron: 1분마다 메트릭 수집
echo "* * * * * root /usr/local/bin/damon-metrics.sh" > /etc/cron.d/damon-metrics
프로덕션 체크리스트:
  • DAMON 활성화 전후 애플리케이션 지연(p50/p99) 비교
  • page fault 비율(/proc/vmstat pgfault, pgmajfault) 증가 여부 확인
  • PSI 메모리(/proc/pressure/memory) 악화 여부 모니터링
  • 스왑 사용량 급증 여부 확인 (DAMOS pageout → 스왑 I/O)
  • 워터마크 설정이 환경에 적합한지 (충분한 히스테리시스)
  • 롤백(Rollback) 자동화 스크립트 준비 (알림 → 자동 비활성화)

Android/ChromeOS에서의 DAMON

DAMON은 모바일/ChromeOS 환경에서 특히 효과적입니다. 제한된 메모리에서 멀티태스킹 성능을 최적화하기 위해 다음과 같이 활용됩니다.

Android LMKD 대체/보완

특성Android LMKDDAMON + DAMOS
메모리 회수 방식프로세스 킬 (전체 메모리 반환)콜드 페이지만 선택적 회수
사용자 경험앱 재시작(Reboot) 필요앱 유지, 백그라운드 메모리만 회수
접근 패턴 활용없음 (RSS/oom_score만)실제 접근 빈도 기반
오버헤드킬 시 순간 비용상시 ~0.5% CPU
적합한 상황심각한 메모리 부족일상적 메모리 최적화
# Android 환경 DAMON 설정 예시
# 백그라운드 앱의 콜드 페이지를 zram으로 스왑

# 짧은 주기, 공격적 콜드 기준
echo 5000 > /sys/module/damon_reclaim/parameters/sample_interval
echo 50000 > /sys/module/damon_reclaim/parameters/aggr_interval   # 50ms
echo 60 > /sys/module/damon_reclaim/parameters/min_age              # 3초 콜드
echo 3 > /sys/module/damon_reclaim/parameters/quota_ms               # 낮은 CPU 쿼터
echo 32000000 > /sys/module/damon_reclaim/parameters/quota_sz       # 32MB/주기

# 프리 메모리 15% 이하에서만 동작
echo 200 > /sys/module/damon_reclaim/parameters/wmarks_high          # 20%
echo 150 > /sys/module/damon_reclaim/parameters/wmarks_mid           # 15%
echo 100 > /sys/module/damon_reclaim/parameters/wmarks_low           # 10%

echo Y > /sys/module/damon_reclaim/parameters/enabled

ChromeOS 메모리 관리

Google의 ChromeOS는 DAMON을 탭 관리에 활용합니다. 백그라운드 탭의 렌더러 프로세스에 대해 DAMON으로 접근 패턴을 모니터링하고, 완전히 콜드한 탭의 메모리를 사전 회수하여 활성 탭의 성능을 보장합니다.

측정 결과 (Google 보고): ChromeOS에서 DAMON 기반 프로액티브 회수를 적용한 결과, 타 탭 전환 시 메모리 가용량이 15~25% 향상되었고, 탭 디스카드(Tab Discard) 빈도가 30% 감소했습니다.

DAMON vs Idle Page Tracking 상세 비교

idle page tracking(/sys/kernel/mm/page_idle/bitmap)은 커널 v4.3에서 도입된 페이지 단위 접근 추적 메커니즘입니다. DAMON과 유사한 목적이지만 구현 방식과 성능 특성이 크게 다릅니다.

# idle page tracking 사용법 (비교용)

# 1. 모든 페이지를 idle로 마킹
echo 1 > /sys/kernel/mm/page_idle/bitmap  # 전체 페이지 idle 설정

# 2. 일정 시간 대기 (워크로드 실행)
sleep 60

# 3. 여전히 idle인 페이지 확인
python3 -c "
import struct, os
with open('/sys/kernel/mm/page_idle/bitmap', 'rb') as f:
    idle_count = 0
    total_count = 0
    while True:
        data = f.read(8)
        if not data: break
        val = struct.unpack('Q', data)[0]
        for i in range(64):
            total_count += 1
            if val & (1 << i):
                idle_count += 1
print(f'Idle pages: {idle_count}/{total_count} '
      f'({idle_count*4/1024:.0f}MB / {total_count*4/1024:.0f}MB)')
"
비교 항목DAMONidle page tracking
샘플링 단위리전 (랜덤 1 페이지)모든 페이지 (비트맵(Bitmap))
자동화커널 내부 자동 루프유저스페이스 폴링 필요
오버헤드 (1GB RSS)~100 PTE 확인/주기~256K PTE 확인/주기
접근 빈도 정보nr_accesses (다단계)idle/non-idle (이진)
자동 액션DAMOS (pageout, hugepage 등)없음 (외부 도구 필요)
필터링addr/target + anon/active/memcg/young/unmapped/hugepage_size없음
NUMA 티어링MIGRATE_HOT/COLD없음

BPF와 DAMON 통합

BPF(Berkeley Packet Filter)를 활용하면 DAMON의 tracepoint 데이터를 실시간으로 가공하거나, 커스텀 정책 로직을 구현할 수 있습니다.

/* BPF 프로그램: DAMON 데이터 기반 커스텀 히트맵 */
/* damon_heatmap.bpf.c */

#include <vmlinux.h>
#include <bpf/bpf_helpers.h>

struct {
    __uint(type, BPF_MAP_TYPE_HASH);
    __uint(max_entries, 10000);
    __type(key, __u64);        /* 리전 시작 주소 (4KB 정렬) */
    __type(value, __u32);      /* 누적 접근 횟수 */
} access_map SEC(".maps");

SEC("tracepoint/damon/damon_aggregated")
int handle_aggregated(struct trace_event_raw_damon_aggregated *ctx)
{
    __u64 start = ctx->start;
    __u32 accesses = ctx->nr_accesses;
    __u32 *val;

    /* 4KB 정렬 키로 변환 */
    start &= ~(0xFFFULL);

    val = bpf_map_lookup_elem(&access_map, &start);
    if (val) {
        *val += accesses;
    } else {
        bpf_map_update_elem(&access_map, &start,
                            &accesses, BPF_ANY);
    }

    return 0;
}
설명 이 BPF 프로그램은 damon_aggregated tracepoint에 attach되어, 각 리전의 접근 횟수를 BPF 해시(Hash)맵에 누적합니다. 유저스페이스 도구가 이 맵을 주기적으로 읽어 히트맵을 생성하거나, 특정 임계값 초과 시 알림을 발생시킬 수 있습니다. 현재 공식 문서 기준으로 BPF는 주로 tracepoint 기반 관찰에 활용되며, 실제 메모리 조작은 기본 DAMOS 액션(pageout, hugepage, migrate_hot 등)이 담당합니다.
# BPF 프로그램 로드 및 히트맵 출력
sudo bpftool prog load damon_heatmap.bpf.o /sys/fs/bpf/damon_heatmap
sudo bpftool prog attach pinned /sys/fs/bpf/damon_heatmap tracepoint damon damon_aggregated

# 10초 후 맵 덤프
sleep 10
sudo bpftool map dump pinned /sys/fs/bpf/access_map | \
    sort -t: -k2 -n -r | head -20
# → 가장 핫한 주소 영역 Top 20

트러블슈팅 가이드

DAMON이 동작하지 않는 경우

# 1. 커널 설정 확인
zcat /proc/config.gz | grep DAMON
# CONFIG_DAMON=y 확인, 없으면 커널 재빌드 필요

# 2. sysfs 존재 확인
ls /sys/kernel/mm/damon/admin/
# 없으면 CONFIG_DAMON_SYSFS=y 필요

# 3. kdamond 상태 확인
cat /sys/kernel/mm/damon/admin/kdamonds/0/state
# "on"이 아니면 시작되지 않음
cat /sys/kernel/mm/damon/admin/kdamonds/0/pid
# PID가 없으면 kdamond가 실행 중이 아님

# 4. commit 누락 확인 (가장 흔한 실수)
echo commit > /sys/kernel/mm/damon/admin/kdamonds/0/state
# → sysfs 설정 변경 후 반드시 commit 필요!

# 5. 대상 PID 유효성 확인
cat .../contexts/0/targets/0/pid_target
ls /proc/$(cat .../contexts/0/targets/0/pid_target)
# 프로세스가 이미 종료되었으면 모니터링 불가

DAMOS가 회수하지 않는 경우

# 1. 스킴 통계 확인
echo update_schemes_stats > .../kdamonds/0/state
echo "nr_tried=$(cat .../schemes/0/stats/nr_tried)"
echo "sz_tried=$(cat .../schemes/0/stats/sz_tried)"
echo "nr_applied=$(cat .../schemes/0/stats/nr_applied)"
echo "sz_applied=$(cat .../schemes/0/stats/sz_applied)"
echo "qt_exceeds=$(cat .../schemes/0/stats/qt_exceeds)"

# nr_tried=0: 패턴 매칭 실패 → access_pattern 조건 완화
# nr_tried>0, nr_applied=0: 필터/쿼터/워터마크 차단
# qt_exceeds>0: 쿼터 초과 → quota_ms/quota_sz 증가

# 2. 워터마크 확인 (free memory)
free -m
# free가 wmarks_high 이상이면 스킴 비활성화 상태

# 3. min_age 확인
# min_age=200, aggr_interval=100ms → 20초 이상 미접근 필요
# 워크로드가 20초 내에 모든 메모리를 재접근하면 콜드 리전 없음

# 4. 필터 확인
cat .../schemes/0/core_filters/0/type
cat .../schemes/0/ops_filters/0/type
cat .../schemes/0/ops_filters/0/allow
# ops memcg/anon 필터가 allow=N이면 해당 페이지는 제외

오버헤드가 높은 경우

# kdamond CPU 사용률 확인
top -p $(cat /sys/kernel/mm/damon/admin/kdamonds/0/pid)

# CPU 1% 이상이면 파라미터 완화
echo 10000 > .../monitoring_attrs/intervals/sample_us   # 5ms → 10ms
echo 500 > .../monitoring_attrs/nr_regions/max            # 1000 → 500
echo commit > .../kdamonds/0/state

# TLB miss 증가 확인
perf stat -e dTLB-load-misses,dTLB-store-misses -a sleep 10
# DAMON 활성화 전후 비교

systemd 서비스 연동

DAMON_RECLAIM을 시스템 부팅 시 자동으로 활성화하려면 systemd 서비스 유닛을 작성합니다.

# /etc/systemd/system/damon-reclaim.service
[Unit]
Description=DAMON Proactive Memory Reclaim
After=multi-user.target

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/bash -c '\
  echo 5000 > /sys/module/damon_reclaim/parameters/sample_interval; \
  echo 100000 > /sys/module/damon_reclaim/parameters/aggr_interval; \
  echo 200 > /sys/module/damon_reclaim/parameters/min_age; \
  echo 10 > /sys/module/damon_reclaim/parameters/quota_ms; \
  echo 128000000 > /sys/module/damon_reclaim/parameters/quota_sz; \
  echo 500 > /sys/module/damon_reclaim/parameters/wmarks_high; \
  echo 400 > /sys/module/damon_reclaim/parameters/wmarks_mid; \
  echo 200 > /sys/module/damon_reclaim/parameters/wmarks_low; \
  echo Y > /sys/module/damon_reclaim/parameters/enabled'
ExecStop=/bin/bash -c '\
  echo N > /sys/module/damon_reclaim/parameters/enabled'

[Install]
WantedBy=multi-user.target
# 서비스 등록 및 시작
sudo systemctl daemon-reload
sudo systemctl enable damon-reclaim.service
sudo systemctl start damon-reclaim.service

# 상태 확인
sudo systemctl status damon-reclaim.service
cat /sys/module/damon_reclaim/parameters/enabled   # Y
cat /sys/module/damon_reclaim/parameters/nr_reclaimed
커널 부트 파라미터: CONFIG_DAMON_RECLAIM이 빌트인(y)인 경우, 커널 부트 파라미터로도 설정할 수 있습니다: damon_reclaim.enabled=Y damon_reclaim.min_age=200 damon_reclaim.quota_ms=10

버전별 주요 변경사항

커널 버전변경사항관련 CONFIG관련 git hash
v5.15DAMON 코어 프레임워크 최초 머지, region-based sampling, vaddr/paddr, debugfsCONFIG_DAMONcore 2224d8485492
v5.16DAMOS 도입, DAMON_RECLAIM, 워터마크 기반 프로액티브 회수CONFIG_DAMON
CONFIG_DAMON_RECLAIM
core 1f366e421c8f
vaddr 6dea8add4d28
dbgfs af122dd8f3c0
reclaim 43b0536cb471
wmarks-core ee801b7dd782
wmarks-dbgfs ae666a6dddfd
v5.17DAMON_RECLAIM 회수 통계 추가CONFIG_DAMON_RECLAIMstat 60e52e7c46a1
v5.18sysfs 인터페이스(/sys/kernel/mm/damon/admin/) 도입, virtual/physical monitoring, DAMOS 제어CONFIG_DAMON_SYSFSstub c951cd3b8901
vaddr a61ea561c871
paddr 2031b14ea757
DAMOS 7e84b1f8212a
quotas 9bbb820a5bd5
wmarks 1b32234ab087
stats 0ac32b8affb5
v5.19고정 가상 주소 범위(fvaddr) 모니터링CONFIG_DAMON_SYSFSvaddr de6d01542a5c
sysfs b82434471cd2
v6.0DAMON_LRU_SORT, LRU_PRIO/LRU_DEPRIO 액션CONFIG_DAMON_LRU_SORTmodule 40e983cca927
LRU_PRIO 8cdcc532268d
LRU_DEPRIO 99cdc2cd180a
v6.2reclaim/lru_sort enable/disable 동기화, 워터마크 기반 제어 정리CONFIG_DAMON_RECLAIM
CONFIG_DAMON_LRU_SORT
reclaim 04e98764befa
lru_sort 7a034fbba336
v6.3DAMOS 필터 프레임워크 (anon, memcg, addr) 및 sysfs 필터 디렉터리-core 98def236f63c
paddr 18250e78f9c7
filters-dir ac35264b9e88
filter-dir 7ee161f18b5d
connect 472e2b70eda6
scheme-filters 29cbb9a13f05
v6.6target type DAMOS filter 추가-core 17e7c724d3c2
v6.7DAMOS apply interval 설정-sysfs a2a9f68e358f
v6.8목표 기반 피드백 쿼터 자동 튜닝-core 9294a037c015
v6.9메모리 PSI 기반 쿼터 self-tuning (DAMON_RECLAIM)CONFIG_DAMON_RECLAIMreclaim 7ce55f8ffded
v6.11MIGRATE_HOT/MIGRATE_COLD 액션, NUMA 티어링-MIGRATE_HOT b696722d784f
MIGRATE_COLD b51820ebea65
v6.15monitoring intervals auto-tuning, core_filters/ops_filters-struct 1eb3471bf574
core f04b0fedbe71
dirs db2e76ceb40b
commit 968cbea1bb0e
ops-field ab82e57981d0
paddr ac7b094bf4d6
v6.17refresh_ms, dests, DAMON_STATCONFIG_DAMON_STATrefresh_ms b907494768e5
refresh_ms-core d809a7c64ba8
dests-field aabc85ee33c8
dests-dir 2cd0bf85a203
dests-commit cbc4eea4ffb5
DAMON_STAT 369c415e6073
v7.0-rc7young page filters, active/inactive 비율 quota goal-young-filter 303dbb1f08cf
quota-goal 4835e2871321
sysfs-goal fbec8a1e4fa4
lru_sort-goal 40d98d31cd70
git hash 기준: 위 표의 해시는 Torvalds tree 기준으로 해당 기능이 최초로 사용자/운영 인터페이스에 드러난 주요 커밋입니다. 하나의 기능이 core, vaddr/paddr, sysfs, dbgfs로 나뉘어 머지된 경우에는 관련 해시를 함께 적었습니다.

v5.15: DAMON 최초 머지

커널 v5.15(2021년 10월)에서 SeongJae Park이 개발한 DAMON이 Andrew Morton의 mm 트리를 통해 최초로 머지되었습니다. 이 버전에서는 코어 프레임워크(mm/damon/core.c), 가상/물리 주소 오퍼레이션(vaddr.c, paddr.c), debugfs 인터페이스가 포함되었습니다. 리전 기반 적응적 샘플링 알고리즘으로 기존 idle page tracking 대비 5~10배 낮은 오버헤드를 달성했습니다. 최초 머지 커밋은 2224d8485492입니다.

v5.16: DAMOS와 DAMON_RECLAIM

v5.16에서 DAMON은 "관찰"만 하는 프레임워크를 넘어 실제 메모리 정책(Memory Policy)을 수행하는 단계로 확장되었습니다. DAMOS 코어는 1f366e421c8f로 들어왔고, vaddr/dbgfs 지원은 6dea8add4d28, af122dd8f3c0로 이어졌습니다. 같은 릴리스에서 DAMON_RECLAIM43b0536cb471로 도입되었고, 워터마크 기반 활성화는 ee801b7dd782, ae666a6dddfd에서 정리되었습니다.

v5.18: sysfs 인터페이스 도입

v5.18(2022년 5월)에서 sysfs 인터페이스가 도입되면서 DAMON의 사용성이 크게 개선되었습니다. debugfs는 단일 파일에 여러 파라미터를 공백으로 나열하는 방식이었지만, sysfs는 /sys/kernel/mm/damon/admin/ 아래 계층적 디렉토리 구조로 각 설정을 개별 파일에 저장합니다. 이를 통해 원자적 설정 변경, 실시간 통계 조회, 다중 kdamond/컨텍스트 관리가 가능해졌습니다. 최소 뼈대는 c951cd3b8901이며, virtual/paddr/DAMOS 연결은 a61ea561c871, 2031b14ea757, 7e84b1f8212a에서 순차적으로 붙었습니다.

v6.0: DAMON_LRU_SORT

v6.0(2022년 10월)에서 DAMON_LRU_SORT 모듈이 추가되었습니다. 기존 DAMON_RECLAIM이 콜드 페이지를 회수(PAGEOUT)하는 데 초점을 맞춘 반면, DAMON_LRU_SORT는 핫 페이지의 LRU 우선순위를 올리고(LRU_PRIO) 콜드 페이지의 우선순위를 내려(LRU_DEPRIO) LRU 리스트의 정확도를 개선합니다. 이는 MGLRU와 상호 보완적으로 동작합니다. 대표 해시는 모듈 도입 40e983cca927, 액션 추가 8cdcc532268d, 99cdc2cd180a입니다.

v6.3+: DAMOS 필터 프레임워크

v6.3(2023년 4월)부터 DAMOS 필터가 도입되어 스킴 적용 대상을 세밀하게 제어할 수 있게 되었습니다. 최초 코어/물리 주소 지원은 98def236f63c, 18250e78f9c7이며, sysfs 디렉터리 구조는 ac35264b9e88부터 이어졌습니다. 이 시점의 기본 필터는 anon, memcg, addr였고, target 필터는 v6.6, young 페이지 필터는 mainline v7.0-rc7에서 추가되었습니다.

v6.15: auto-tuning과 filter 레이어 분리

v6.15에서는 모니터링 간격 자체를 workload 특성에 맞게 조절하는 intervals auto-tuning1eb3471bf574, f04b0fedbe71로 들어왔습니다. 동시에 core_filters/ops_filters 디렉터리와 커밋 경로가 db2e76ceb40b, 968cbea1bb0e로 정리되어, 공통 필터와 ops 전용 필터를 명시적으로 분리할 수 있게 되었습니다.

v6.17: 운영 제어면 고도화

v6.17은 최근 문서에서 눈에 띄는 운영 기능이 대거 정리된 릴리스입니다. refresh_msb907494768e5, d809a7c64ba8로 들어왔고, 다중 마이그레이션 목적지인 destsaabc85ee33c8, 2cd0bf85a203, cbc4eea4ffb5로 정리되었습니다. 시스템 전체 유휴 시간 분포를 저비용으로 보는 DAMON_STAT369c415e6073에서 처음 도입되었습니다.

debugfs에서 sysfs 마이그레이션 타임라인

현재 공식 문서는 debugfs 인터페이스를 deprecated로 명시하고 있으며, 신규 배포판 스크립트와 운영 자동화는 sysfs 기준으로 작성할 것을 권고합니다. 특히 quota goal, tried regions, filter layer 분리 같은 최신 기능은 sysfs에서 훨씬 자연스럽게 표현됩니다.

실무 정리: 기존 debugfs 스크립트가 남아 있어도 "동작하니 유지"보다는 "읽기 전용(Read-Only) 호환 계층"으로 보고, /sys/kernel/mm/damon/admin/ 경로로 순차 전환하는 편이 안전합니다.

현재 상태

최신 DAMON 문서를 기준으로 보면, 요즘의 핵심 변화는 "새 액션이 생길 가능성"보다 운영 제어면이 더 정교해졌다는 점입니다. 같은 pageout 정책이라도 이제는 tuned interval, quota goal, tried regions, weighted destination, DAMON_STAT를 조합해 훨씬 세밀하게 운영할 수 있습니다.

현재 확인되는 항목공식 인터페이스실무 의미
자동 모니터링 간격 조정monitoring_attrs/intervals/intervals_goal/워크로드가 바뀌어도 "관찰된 접근 비율"을 기준으로 정확도와 오버헤드를 자동 균형화합니다.
정교한 피드백 제어quotas/goals/, effective_bytesPSI, 노드 사용률, memcg 경로 사용률을 목표로 pageout 또는 tiering 강도를 조절할 수 있습니다.
필터 계층 분리core_filters/, ops_filters/정책 의도를 더 분명히 표현하고 디버깅 시 평가 순서를 추적하기 쉽습니다.
다중 목적지 마이그레이션dests/0/id, dests/0/weightCXL, DRAM, PMEM이 혼합된 환경에서 단순 1:1 노드 이동보다 현실적인 배치가 가능합니다.
행동 결과 역추적stats/nr_snapshots, tried_regions/"왜 회수했는가"뿐 아니라 "실제로 어디까지 시도했는가"를 사후 분석할 수 있습니다.
경량 관찰 모듈DAMON_STAT정책 적용 전 시스템 전체 idle 분포와 대역폭을 저비용으로 확인할 수 있습니다.
커뮤니티 활동: DAMON 개발 논의와 최신 패치 시리즈는 lore.kernel.org/damon/에서 확인할 수 있습니다. 운영 문서를 따라가면서 실제 변화도 추적하려면 릴리스 문서, lore 아카이브, damo 도구 저장소를 함께 보는 편이 좋습니다.

참고자료

권장 읽기 순서

공식 릴리스와 관리자 문서

공식 설계 문서와 API/FAQ

공식 소스 트리

문서 원본과 문서 기여용 링크

공식 도구와 커뮤니티