背景

DAMON 提供基于访问模式的数据访问监控,并能通过 DAMOS scheme 对命中的内存区域执行动作。其中 DAMOS_COLLAPSE 把访问模式命中的热区折叠(collapse)成 huge page,以此扩大 TLB 覆盖范围、减少 TLB miss。这套机制的前提是 TLB 是许多系统的性能瓶颈,而 huge page 能有效缓解。

但 collapse 的量原本无法调优。DAMOS_COLLAPSE 会对所有符合访问模式的热区执行折叠,没有配额约束可言。这在裸机数据库、大数据服务器等长期运行的负载上会走向另一个极端:和 THP 设为 "always" 一样,持续 collapse 最终导致内存碎片化与浪费,这也是多数运维指南建议直接禁用 THP 的原因。此外 THP 是全局开关,缺乏按任务粒度控制哪些进程能用 huge page 的手段。

DAMOS_COLLAPSE 无配额调优,全量 collapse 致碎片
┌──────────────────────────────────────┐
│ DAMOS_COLLAPSE 把访问模式命中的热区  │
│ 折叠成 huge page                     │
└──────────────────┬───────────────────┘
                   ▼
┌──────────────────────────────────────┐
│ collapse 量不可调,命中即折叠,无法  │
│ 按目标比例控制                       │
└──────────────────┬───────────────────┘
                   ▼
┌──────────────────────────────────────┐
│ 数据库与大数据等裸机负载最终也走向内 │
│ 存碎片化                             │
└──────────────────────────────────────┘

问题

  • DAMOS_COLLAPSE 对所有命中热区折叠,折叠量无法按比例调优。
  • 裸机数据库与大数据等负载长期运行下同样走向内存碎片化。
  • THP 全局开关,无法按任务控制 huge page 使用。
  • 需要一种让 collapse 只在合适时机、按目标比例触发的方式。

方案

DAMON 已有一套 quota 自动调优(autotuning)架构:用户为 DAMOS 设 quota goal,指定 metric 和目标值(target_value),DAMON 每轮自测该 metric 的当前值(current_value),用二者接近程度算出 score,再据此调整 DAMOS 的有效配额(esz)。配额反过来约束 DAMOS_COLLAPSE 实际折叠多少页,形成让 metric 朝目标收敛的闭环。已有 active_mem_bp、inactive_mem_bp、node_eligible_mem_bp 等 metric 都按同一模式接入。

本系列给这套架构补上面向 huge page 的 metric。新增 DAMOS_QUOTA_HUGEPAGE_MEM_BP,由 damos_hugepage_mem_bp() 计算当前值:

static unsigned int damos_hugepage_mem_bp(void)
{
    unsigned long thp, total_pages, free_pages;

    total_pages = totalram_pages();
    free_pages = global_zone_page_state(NR_FREE_PAGES);

    if (total_pages <= free_pages)
        return 10000;

    thp = global_node_page_state(NR_ANON_THPS) +
                global_node_page_state(NR_SHMEM_THPS) +
                global_node_page_state(NR_FILE_THPS);
    return mult_frac(thp, 10000, total_pages - free_pages);
}

它把匿名、shmem、file 这 3 类 THP 的页数相加作分子,已用内存(总内存减空闲页)作分母,返回万分比(basis points,0-10000);目标 10% 就把 target_value 设为 1000。vmstat 的 per-cpu 计数有竞态,空闲页数可能暂时不小于总内存(idle 系统上分母算成 0 也归此类),此时直接返回 10000(即 100%),autotuning 把配额压到零,collapse 暂停直到统计刷新。damos_set_quota_goal_current_value() 的 switch 里只加 1 个 case 把该值写回 goal->current_value,后续的 score 计算与 quota 调整完全复用既有逻辑。sysfs 侧在 damos_sysfs_qgoal_metric_names[] 加一条 hugepage_mem_bp 映射。

新增 hugepage_mem_bp metric,复用 autotuning 自调 quota
┌────────────────────────────────────────┐
│ 新增 quota goal metric hugepage_mem_bp │
│ 测 huge page 占比                      │
└───────────────────┬────────────────────┘
                    ▼
┌────────────────────────────────────────┐
│ 复用现有 autotuning,按目标比例自调    │
│ DAMOS 的 quota                         │
└───────────────────┬────────────────────┘
                    ▼
┌────────────────────────────────────────┐
│ DAMOS_COLLAPSE 受 quota 约束,占比趋   │
│ 近用户目标                             │
└────────────────────────────────────────┘

收益

作者在 arm64 物理机(4 NUMA node、1 TB RAM)上用 mariaDB 10.5.29 加 sysbench(20 表、每表 300 万行)评估,DB 与 benchmark 框架分别 pin 到不同 NUMA node,无网络流量。DAMON 以 DAMOS_COLLAPSE 为动作、hugepage_mem_bp 为 quota goal 启动,测量的是 huge page 占比随时间能否收敛到目标。

hugepage_mem_bp 目标 goal tuner 收敛后 huge page 占比
1000(10%) temporal ~10.26%(达标)
1000(10%) consistent ~20.58%(超目标)
2500(25%) temporal ~25.68%(达标)
1000(10%) consistent ~45.11%(超目标)

temporal tuner 下占比精准落到目标附近(10%、25%),这正是 DAMOS_QUOTA_GOAL_TUNER_TEMPORAL「尽快把配额归零」语义的体现:达标后配额回落,collapse 自然停步。consistent tuner 则相反:它不把配额归零来封顶 DAMOS 策略,达标后 collapse 不停步,占比因此越过目标(表格里 20.58%、45.11%),与 temporal 的「达标停步」恰成对照。