DAMON (Data Access MONitor)

리눅스 커널의 DAMON(Data Access MONitor) 서브시스템을 심층 분석합니다. 리전(region) 기반 적응적 샘플링으로 오버헤드(Overhead)를 최소화하면서 메모리 접근 패턴을 모니터링하고, DAMOS(Data Access-aware Memory Operation Schemes)를 통해 콜드 페이지(Page) 회수, THP 프로모션, LRU 정렬 등을 자동으로 수행하는 구조를 커널 소스(mm/damon/) 기반으로 분석합니다. kdamond 커널 스레드(Kernel Thread), sysfs/debugfs 인터페이스, damo 유저스페이스 도구, NUMA 티어링 연동, 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 정렬). 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 모듈
역사: 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 등에서 대규모 프로덕션 환경에 적용 중입니다.

아키텍처

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은 프로세스(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 필터는 패턴 매칭을 통과한 리전 중에서 특정 조건의 페이지를 추가로 포함하거나 제외합니다. 커널 v6.3에서 도입되어 지속적으로 필터 타입이 추가되고 있습니다.

필터 타입설명예시 용도
anon익명 페이지(Anonymous Page)만 포함/제외파일 캐시(Cache)는 건드리지 않고 anonymous만 회수
memcg특정 cgroup의 페이지만 포함/제외특정 컨테이너(Container)의 메모리만 최적화
addr특정 주소 범위 포함/제외힙 영역만 타겟팅
young최근 접근된 페이지 포함/제외아직 따뜻한 페이지는 회수 제외
target특정 모니터링 대상만 포함/제외다중 프로세스 중 하나만 적용
/* include/linux/damon.h - 필터 구조체 */
struct damos_filter {
    enum damos_filter_type type;
    bool matching;             /* true: 매칭 시 포함, false: 매칭 시 제외 */
    union {
        unsigned short memcg_id;
        struct damon_addr_range addr_range;
        int target_idx;
    };
    struct list_head list;
};
설명 matching 필드가 true이면 필터 조건에 매칭되는 페이지만 액션 대상으로 포함하고, false이면 매칭되는 페이지를 제외합니다. 필터는 리스트로 연결되어 순서대로 평가되며, 첫 번째 매칭 필터의 결과가 적용됩니다. 예를 들어 {type=anon, matching=true} 필터를 설정하면 anonymous 페이지에만 액션이 적용됩니다.
DAMOS 필터 체인 평가 흐름 (Filter Chain Evaluation) 패턴 매칭 (Pattern Match) anon 불일치 memcg 불일치 addr 불일치 young 기본 포함 (Include) 일치 포함/제외 일치 포함/제외 예시 1: 파일 기반 페이지 → 제외됨 영역 R3 file-backed page anon 필터 일치! (non-anon) 제외됨 EXCLUDED 예시 2: 익명 페이지 + cgroup=web-app → 액션 적용 영역 R5 anon, web-app anon 필터 통과! memcg 필터 web-app 통과! 액션 적용 ACTION APPLIED ◆ 필터 평가 순서: anon → memcg → addr → young → target | 첫 번째 일치 필터가 최종 결정
DAMOS 필터 체인 평가: 각 필터는 순서대로 평가되며, 첫 번째 일치 필터가 포함/제외를 결정. 모든 필터 불일치 시 기본 포함(include)

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_schemes_stats
│       ├── pid              # kdamond 스레드 PID (읽기 전용)
│       └── contexts/
│           ├── nr_contexts
│           └── 0/
│               ├── operations       # vaddr/fvaddr/paddr
│               ├── monitoring_attrs/
│               │   ├── intervals/
│               │   │   ├── sample_us     # 샘플링 주기 (마이크로초)
│               │   │   ├── aggr_us       # 집계 주기
│               │   │   └── update_us     # 갱신 주기
│               │   └── nr_regions/
│               │       ├── min           # 최소 리전 수
│               │       └── max           # 최대 리전 수
│               ├── targets/
│               │   ├── nr_targets
│               │   └── 0/
│               │       ├── pid_target    # 대상 PID (vaddr)
│               │       └── regions/      # 초기 리전 (선택)
│               └── schemes/
│                   ├── nr_schemes
│                   └── 0/
│                       ├── action        # pageout/hugepage/...
│                       ├── access_pattern/
│                       ├── quotas/
│                       ├── watermarks/
│                       ├── filters/
│                       └── stats/        # 적용 통계

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

# 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

# 7. 통계 확인
echo update_schemes_stats > /sys/kernel/mm/damon/admin/kdamonds/0/state
cat .../contexts/0/schemes/0/stats/nr_applied
cat .../contexts/0/schemes/0/stats/sz_applied
설명 sysfs 인터페이스는 DAMON의 전체 설정을 디렉토리 계층 구조로 노출합니다. state 파일에 commit을 쓰면 현재 sysfs 설정이 실제 DAMON 설정에 반영되고, on을 쓰면 kdamond 스레드(Thread)가 시작됩니다. update_schemes_stats를 쓰면 DAMOS 통계가 갱신되어 stats/ 디렉토리에서 읽을 수 있습니다.

debugfs 인터페이스 (레거시)

초기 DAMON은 /sys/kernel/debug/damon/ debugfs 인터페이스를 사용했습니다. v5.18에서 sysfs 인터페이스가 도입된 이후 debugfs는 레거시로 분류되어 향후 제거될 예정입니다.

# 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/)를 사용하세요.

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 스캔으로 지연이 발생하지만, 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

컨테이너 환경: cgroup 필터

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

# 특정 cgroup의 메모리만 회수 대상으로 지정
MEMCG_ID=$(cat /sys/fs/cgroup/my-pod/memory.current 2>/dev/null; \
           cat /proc/cgroups | grep memory | awk '{print $2}')

# DAMOS 스킴에 memcg 필터 추가
echo 1 > .../schemes/0/filters/nr_filters
echo memcg > .../schemes/0/filters/0/type
echo "true" > .../schemes/0/filters/0/matching
echo ${MEMCG_ID} > .../schemes/0/filters/0/memcg_id

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/filters/nr_filters
echo anon > ${DAMON_CTX}/schemes/0/filters/0/type
echo "true" > ${DAMON_CTX}/schemes/0/filters/0/matching  # 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배로 설정하세요.

데이터베이스 버퍼 풀 최적화

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

더티 페이지 주의: 더티 페이지를 강제 회수하면 재접근 시 fsync() 비용이 발생합니다. 데이터베이스 체크포인트 주기와 조율하여 더티 페이지 비율을 낮게 유지하세요.
# 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 필터 matching=false → file-backed 페이지만 타겟
DAMON_CTX="/sys/kernel/mm/damon/admin/kdamonds/0/contexts/0"
echo 1 > ${DAMON_CTX}/schemes/0/filters/nr_filters
echo anon > ${DAMON_CTX}/schemes/0/filters/0/type
echo "false" > ${DAMON_CTX}/schemes/0/filters/0/matching  # 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 페이지 캐시와 이중 캐싱되므로 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%미미
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과 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/ 디렉토리를 통해 사용자 공간에서 확인할 수 있습니다.

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이 발생하여 오히려 성능이 저하될 수 있습니다. 프로덕션에서는 반드시 벤치마크를 통해 최적 값을 확인하세요.

커널 내부 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+불가가능 (분석)불가

자동 쿼터 튜닝 (DAMOS Quota Goal)

커널 v6.8에서 도입된 DAMOS Quota Goal은 사용자가 명시적 쿼터 값을 설정하는 대신, 목표 메트릭을 지정하면 DAMON이 자동으로 쿼터를 조절하는 피드백 루프입니다.

/* 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 값 */
    unsigned long target_value;      /* 목표 값 */
    unsigned long current_value;     /* 현재 값 (커널이 갱신) */
    struct list_head list;
};
설명 DAMOS_QUOTA_SOME_MEM_PSI_US는 메모리 PSI(Pressure Stall Information)의 some 값(마이크로초)을 목표로 합니다. 예를 들어 target_value를 10000(10ms)으로 설정하면, DAMON은 PSI some이 10ms를 넘지 않도록 쿼터를 자동 조절합니다. PSI가 높아지면(메모리 압박 증가) 쿼터를 늘려 더 많이 회수하고, PSI가 낮아지면 쿼터를 줄여 불필요한 회수를 방지합니다.

자동 튜닝 알고리즘

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/metric
echo 5000 > .../schemes/0/quotas/goals/0/target_value

# 초기 쿼터는 보수적으로 설정 (자동 튜닝이 조절)
echo 5 > .../schemes/0/quotas/ms
echo 64000000 > .../schemes/0/quotas/bytes
프로덕션 권장: 자동 쿼터 튜닝은 워크로드 변동이 큰 환경(CI/CD 파이프라인, 웹 서버)에서 특히 유용합니다. 고정 쿼터는 피크 시에 부족하고 유휴 시에 과잉되지만, 자동 튜닝은 실시간으로 적응합니다.

접근 패턴 분석 기법

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 페이지)모든 페이지 (비트맵)
자동화커널 내부 자동 루프유저스페이스 폴링 필요
오버헤드 (1GB RSS)~100 PTE 확인/주기~256K PTE 확인/주기
접근 빈도 정보nr_accesses (다단계)idle/non-idle (이진)
자동 액션DAMOS (pageout, hugepage 등)없음 (외부 도구 필요)
필터링anon/memcg/addr/young/target없음
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)맵에 누적합니다. 유저스페이스 도구가 이 맵을 주기적으로 읽어 히트맵을 생성하거나, 특정 임계값 초과 시 알림을 발생시킬 수 있습니다. 향후 DAMON에 BPF 기반 커스텀 스킴 액션이 추가되면, DAMOS의 기본 액션(pageout 등)을 넘어선 유연한 정책 구현이 가능해질 전망입니다.
# 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/filters/0/type
cat .../schemes/0/filters/0/matching
# anon 필터가 matching=true이면 file-backed 페이지 제외

오버헤드가 높은 경우

# 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
v5.15DAMON 코어 프레임워크 최초 머지, debugfs 인터페이스, vaddr/paddr opsCONFIG_DAMON
v5.16DAMOS(Data Access-aware Memory Operation Schemes) 도입CONFIG_DAMON
v5.17DAMON_RECLAIM 모듈, 워터마크 기반 프로액티브 회수CONFIG_DAMON_RECLAIM
v5.18sysfs 인터페이스(/sys/kernel/mm/damon/admin/), fvaddr opsCONFIG_DAMON_SYSFS
v5.19DAMOS 쿼터 시스템 도입-
v6.0DAMON_LRU_SORT, LRU_PRIO/LRU_DEPRIO 액션CONFIG_DAMON_LRU_SORT
v6.2DAMOS 워터마크 자동 비활성화 개선-
v6.3DAMOS 필터 프레임워크 (anon, memcg, addr)-
v6.5young 필터, target 필터 추가-
v6.7DAMOS apply interval 설정-
v6.8자동 쿼터 튜닝 (DAMOS Quota Goal), PSI 기반-
v6.9MIGRATE_HOT/MIGRATE_COLD 액션, NUMA 티어링-
v6.10+다중 kdamond 개선, BPF 연동 논의-

DAMON 발전 방향

DAMON은 활발하게 발전 중인 서브시스템으로, 다음과 같은 방향으로 개선이 진행 중입니다:

커뮤니티 활동: DAMON 개발은 lore.kernel.org/damon/ 메일링 리스트에서 활발하게 논의됩니다. SeongJae Park이 메인테이너이며, Meta, Google, Amazon, Samsung 등에서 기여하고 있습니다.

참고자료

커널 문서

LWN 기사

커널 소스

발표 자료