详细用法

DAMON 为不同用户提供以下接口。

  • DAMON 用户空间工具。 该工具适用于特权用户,例如希望使用即插即用、人性化界面的系统管理员。用户可以使用此工具以人性化的方式使用 DAMON 的主要功能。但它可能不会针对特殊情况进行高度优化。更多详情,请参阅其使用文档

  • sysfs 接口。 该接口适用于希望更优化地使用 DAMON 的特权用户空间程序员。通过此接口,用户可以通过读写特殊的 sysfs 文件来使用 DAMON 的主要功能。因此,您可以编写和使用您的个性化 DAMON sysfs 包装程序来代替您读写 sysfs 文件。DAMON 用户空间工具就是这类程序的一个例子。

  • 内核空间编程接口。 该接口适用于内核空间程序员。通过此接口,用户可以通过为您编写内核空间 DAMON 应用程序,最灵活、最有效地利用 DAMON 的所有功能。您甚至可以为各种地址空间扩展 DAMON。详情请参阅接口文档

sysfs 接口

当定义了 CONFIG_DAMON_SYSFS 时,DAMON sysfs 接口就会构建。它在其 sysfs 目录 <sysfs>/kernel/mm/damon/ 下创建多个目录和文件。您可以通过读写该目录下的文件来控制 DAMON。

一个简单的例子是,用户可以按如下方式监视给定工作负载的虚拟地址空间。

# cd /sys/kernel/mm/damon/admin/
# echo 1 > kdamonds/nr_kdamonds && echo 1 > kdamonds/0/contexts/nr_contexts
# echo vaddr > kdamonds/0/contexts/0/operations
# echo 1 > kdamonds/0/contexts/0/targets/nr_targets
# echo $(pidof <workload>) > kdamonds/0/contexts/0/targets/0/pid_target
# echo on > kdamonds/0/state

文件层级

DAMON sysfs 接口的文件层级结构如下所示。在下图中,父子关系用缩进表示,每个目录都有 / 后缀,每个目录中的文件用逗号(“,”)分隔。

/sys/kernel/mm/damon/admin
│ kdamonds/nr_kdamonds
│ │ 0/state,pid
│ │ │ contexts/nr_contexts
│ │ │ │ 0/avail_operations,operations
│ │ │ │ │ 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
│ │ │ │ │ │ │ regions/nr_regions
│ │ │ │ │ │ │ │ 0/start,end
│ │ │ │ │ │ │ │ ...
│ │ │ │ │ │ ...
│ │ │ │ │ schemes/nr_schemes
│ │ │ │ │ │ 0/action,target_nid,apply_interval_us
│ │ │ │ │ │ │ access_pattern/
│ │ │ │ │ │ │ │ sz/min,max
│ │ │ │ │ │ │ │ nr_accesses/min,max
│ │ │ │ │ │ │ │ age/min,max
│ │ │ │ │ │ │ quotas/ms,bytes,reset_interval_ms,effective_bytes
│ │ │ │ │ │ │ │ weights/sz_permil,nr_accesses_permil,age_permil
│ │ │ │ │ │ │ │ goals/nr_goals
│ │ │ │ │ │ │ │ │ 0/target_metric,target_value,current_value,nid
│ │ │ │ │ │ │ watermarks/metric,interval_us,high,mid,low
│ │ │ │ │ │ │ {core_,ops_,}filters/nr_filters
│ │ │ │ │ │ │ │ 0/type,matching,allow,memcg_path,addr_start,addr_end,target_idx,min,max
│ │ │ │ │ │ │ stats/nr_tried,sz_tried,nr_applied,sz_applied,sz_ops_filter_passed,qt_exceeds
│ │ │ │ │ │ │ tried_regions/total_bytes
│ │ │ │ │ │ │ │ 0/start,end,nr_accesses,age,sz_filter_passed
│ │ │ │ │ │ │ │ ...
│ │ │ │ │ │ ...
│ │ │ │ ...
│ │ ...

根目录

DAMON sysfs 接口的根目录是 <sysfs>/kernel/mm/damon/,它有一个名为 admin 的目录。该目录包含用于特权用户空间程序控制 DAMON 的文件。具有 root 权限的用户空间工具或守护进程可以使用此目录。

kdamonds/

admin 目录下,有一个名为 kdamonds 的目录,其中包含用于控制 kdamond 的文件(有关详细信息,请参阅设计文档)。最初,此目录中只有一个文件 nr_kdamonds。向该文件写入一个数字(N)会创建 0N-1 数量的子目录。每个目录代表一个 kdamond。

kdamonds/<N>/

在每个 kdamond 目录中,有两个文件(statepid)和一个目录(contexts)。

如果 kdamond 当前正在运行,读取 state 将返回 on,如果未运行,则返回 off

用户可以向 state 文件写入以下 kdamond 命令。

  • on: 开始运行。

  • off: 停止运行。

  • commit: 再次读取 sysfs 文件中除 state 文件之外的用户输入。

  • update_tuned_intervals: 使用自动调整后的 采样间隔聚合间隔 更新 kdamond 的 sample_usaggr_us 文件的内容。更多详细信息,请参阅intervals_goal 部分

  • commit_schemes_quota_goals: 读取基于 DAMON 的操作方案的配额目标

  • update_schemes_stats: 更新 kdamond 的每个基于 DAMON 的操作方案的统计文件内容。有关统计信息的详细信息,请参阅stats 部分

  • update_schemes_tried_regions: 更新 kdamond 的每个基于 DAMON 的操作方案的已尝试区域目录。有关基于 DAMON 的操作方案已尝试区域目录的详细信息,请参阅tried_regions 部分

  • update_schemes_tried_bytes: 仅更新 .../tried_regions/total_bytes 文件。

  • clear_schemes_tried_regions: 清除 kdamond 的每个基于 DAMON 的操作方案的已尝试区域目录。

  • update_schemes_effective_quotas: 更新 kdamond 的每个基于 DAMON 的操作方案的 effective_bytes 文件内容。更多详细信息,请参阅quotas 目录

如果状态为 on,读取 pid 将显示 kdamond 线程的 pid。

contexts 目录包含用于控制此 kdamond 将执行的监控上下文的文件。

kdamonds/<N>/contexts/

最初,此目录中只有一个文件 nr_contexts。向该文件写入一个数字(N)会创建 0N-1 数量的子目录。每个目录代表一个监控上下文(有关详细信息,请参阅设计文档)。目前,每个 kdamond 只支持一个上下文,因此只能向该文件写入 01

contexts/<N>/

在每个上下文目录中,有两个文件(avail_operationsoperations)和三个目录(monitoring_attrstargetsschemes)。

DAMON 支持多种类型的监控操作,包括虚拟地址空间和物理地址空间的监控操作。您可以通过读取 avail_operations 文件获取当前运行内核上可用的监控操作集列表。根据内核配置,该文件将列出不同的可用操作集。有关所有可用操作集及其简要说明的列表,请参阅设计文档

您可以通过向 avail_operations 文件中列出的某个关键字写入,并从 operations 文件中读取,来设置和获取 DAMON 将用于该上下文的监控操作类型。

contexts/<N>/monitoring_attrs/

用于指定监控属性的文件(包括所需的监控质量和效率)位于 monitoring_attrs 目录中。具体来说,此目录中存在两个目录:intervalsnr_regions

intervals 目录下,存在三个文件,分别用于 DAMON 的采样间隔(sample_us)、聚合间隔(aggr_us)和更新间隔(update_us)。您可以通过读写这些文件来设置和获取以微秒为单位的值。

nr_regions 目录下,存在两个文件,分别用于 DAMON 监控区域的下限和上限(minmax),它们控制着监控开销。您可以通过读写这些文件来设置和获取这些值。

有关间隔和监控区域范围的更多详细信息,请参阅设计文档(设计)。

contexts/<N>/monitoring_attrs/intervals/intervals_goal/

intervals 目录下,还存在一个用于 sample_usaggr_us 自动调整的目录,即 intervals_goal 目录。在该目录下,存在四个用于自动调整控制的文件,即 access_bpaggrsmin_sample_usmax_sample_us。有关调整机制的内部详情,请参阅该功能的设计文档。读写 intervals_goal 目录下的这四个文件,将显示和更新在设计文档中以相同名称描述的调整参数。调整从用户设置的 sample_usaggr_us 开始。在向 state 文件写入 update_tuned_intervals 后,可以从 sample_usaggr_us 文件中读取经过调整的这两个间隔的当前值。

contexts/<N>/targets/

最初,此目录中只有一个文件 nr_targets。向该文件写入一个数字(N)会创建 0N-1 数量的子目录。每个目录代表一个监控目标。

targets/<N>/

在每个目标目录中,有一个文件(pid_target)和一个目录(regions)。

如果您向 contexts/<N>/operations 写入 vaddr,则每个目标都应该是一个进程。您可以通过将进程的 pid 写入 pid_target 文件来向 DAMON 指定该进程。

targets/<N>/regions

对于 fvaddrpaddr 监控操作集,用户需要设置监控目标地址范围。对于 vaddr 操作集,这不是强制性的,但用户可以选择将初始监控区域设置为特定的地址范围。更多详细信息,请参阅设计文档

对于此类情况,用户可以通过向此目录下的文件写入适当的值,明确地设置所需的初始监控目标区域。

最初,此目录中只有一个文件 nr_regions。向该文件写入一个数字(N)会创建 0N-1 数量的子目录。每个目录代表一个初始监控目标区域。

regions/<N>/

在每个区域目录中,您会找到两个文件(startend)。您可以通过分别读写这些文件来设置和获取初始监控目标区域的起始和结束地址。

每个区域不应与其他区域重叠。目录 Nend 应等于或小于目录 N+1start

contexts/<N>/schemes/

用于基于 DAMON 的操作方案(DAMOS)的目录。用户可以通过读写此目录下的文件来获取和设置方案。

最初,此目录中只有一个文件 nr_schemes。向该文件写入一个数字(N)会创建 0N-1 数量的子目录。每个目录代表一个基于 DAMON 的操作方案。

schemes/<N>/

在每个方案目录中,存在七个目录(access_patternquotaswatermarkscore_filtersops_filtersfiltersstatstried_regions)和三个文件(actiontarget_nidapply_interval)。

action 文件用于设置和获取方案的操作。可以写入和从文件中读取的关键字及其含义与设计文档中的列表相同。

target_nid 文件用于设置迁移目标节点,这仅在 actionmigrate_hotmigrate_cold 时才有意义。

apply_interval_us 文件用于设置和获取方案以微秒为单位的应用间隔

schemes/<N>/access_pattern/

给定基于 DAMON 的操作方案的目标访问模式的目录。

access_pattern 目录下,存在三个目录(sznr_accessesage),每个目录包含两个文件(minmax)。您可以通过分别读写 sznr_accessesage 目录下的 minmax 文件来设置和获取给定方案的访问模式。请注意,minmax 构成一个闭区间。

schemes/<N>/quotas/

给定基于 DAMON 的操作方案的配额目录。

quotas 目录下,存在四个文件(msbytesreset_interval_mseffective_bytes)和两个目录(weightsgoals)。

您可以通过分别向这三个文件写入值,设置以毫秒为单位的时间配额、以字节为单位的大小配额和以毫秒为单位的重置间隔。然后,DAMON 会尝试在 reset_interval_ms 内,将 action 应用于 access_pattern 的内存区域时,仅使用最多 时间配额 毫秒,且仅应用于最多 bytes 字节的内存区域。将 msbytes 都设置为零会禁用配额限制,除非至少设置了一个目标

时间配额在内部转换为大小配额。在转换后的大小配额和用户指定的大小配额之间,较小的一个将被应用。根据用户指定的目标,有效大小配额会进一步调整。读取 effective_bytes 将返回当前有效的尺寸配额。该文件并非实时更新,因此用户应通过向相关 kdamonds/<N>/state 文件写入特殊关键字 update_schemes_effective_quotas 来请求 DAMON sysfs 接口更新该文件的统计内容。

weights 目录下,存在三个文件(sz_permilnr_accesses_permilage_permil)。您可以通过向 weights 目录下的这三个文件写入值,以千分之几的单位设置大小、访问频率和年龄的优先级权重

schemes/<N>/quotas/goals/

给定基于 DAMON 的操作方案的自动配额调整目标目录。

最初,此目录中只有一个文件 nr_goals。向该文件写入一个数字(N)会创建 0N-1 数量的子目录。每个目录代表一个目标和当前成就。在多个反馈中,使用最佳的一个。

每个目标目录包含四个文件,即 target_metrictarget_valuecurrent_valuenid。用户可以通过读写这些文件来设置和获取设计文档中指定的配额自动调整目标的四个参数。请注意,用户还应向 kdamond 目录state 文件写入 commit_schemes_quota_goals 以将反馈传递给 DAMON。

schemes/<N>/watermarks/

给定基于 DAMON 的操作方案的水印目录。

在 watermarks 目录下,存在五个文件(metricinterval_ushighmidlow),用于设置度量、度量检查之间的时间间隔以及三个水印。您可以通过分别向这些文件写入来设置和获取这五个值。

可以写入 metric 文件的关键字及其含义如下。

  • none: 忽略水印

  • free_mem_rate: 系统的空闲内存率(千分之几)

The interval should written in microseconds unit.

schemes/<N>/{core_,ops_,}filters/

给定基于 DAMON 的操作方案的过滤器目录。

core_filtersops_filters 目录分别用于由 DAMON 核心层和操作集层处理的过滤器。filters 目录可用于安装过滤器,无论它们由哪个层处理。由 core_filtersops_filters 请求的过滤器将先于 filters 中的过滤器安装。所有这三个目录都有相同的文件。

使用 filters 目录可能会导致对给定过滤器在目录文件下的评估顺序的预期有些混乱。因此,建议用户使用 core_filtersops_filters 目录。filters 目录将来可能会被弃用。

最初,该目录中只有一个文件 nr_filters。向该文件写入一个数字(N)会创建 0N-1 数量的子目录。每个目录代表一个过滤器。过滤器按数字顺序进行评估。

每个过滤器目录包含九个文件,即 typematchingallowmemcg_pathaddr_startaddr_endminmaxtarget_idx。您可以向 type 文件写入过滤器的类型。有关可用类型名称、其含义以及它们在哪个层处理的信息,请参阅设计文档

对于 memcg 类型,您可以通过将内存 cgroup 从 cgroups 挂载点的路径写入 memcg_path 文件来指定感兴趣的内存 cgroup。对于 addr 类型,您可以分别向 addr_startaddr_end 文件指定范围的起始和结束地址(开区间)。对于 hugepage_size 类型,您可以分别向 minmax 文件指定范围的最小和最大大小(闭区间)。对于 target 类型,您可以向 target_idx 文件指定 DAMON 上下文监控目标列表中的目标索引。

您可以向 matching 文件写入 YN,以指定过滤器是否针对与 type 匹配的内存。您可以向 allow 文件写入 YN,以指定是否允许对满足 typematching 的内存应用操作。

例如,下面将 DAMOS 操作限制为仅应用于除 /having_care_already 之外的所有内存 cgroup 的非匿名页。

# cd ops_filters/0/
# echo 2 > nr_filters
# # disallow anonymous pages
echo anon > 0/type
echo Y > 0/matching
echo N > 0/allow
# # further filter out all cgroups except one at '/having_care_already'
echo memcg > 1/type
echo /having_care_already > 1/memcg_path
echo Y > 1/matching
echo N > 1/allow

有关 DAMOS 过滤器设计文档的更多详细信息,包括不同 allow 的多个过滤器如何工作、何时支持每个过滤器以及统计信息的差异,请参阅DAMOS 过滤器设计文档

schemes/<N>/stats/

DAMON 会计算每个方案的统计数据。这些统计数据可用于方案的在线分析或调整。有关统计数据的更多详细信息,请参阅设计文档

可以通过分别读取 stats 目录下的文件(nr_triedsz_triednr_appliedsz_appliedsz_ops_filter_passedqt_exceeds)来检索统计信息。这些文件并非实时更新,因此您应通过向相关的 kdamonds/<N>/state 文件写入特殊关键字 update_schemes_stats,来请求 DAMON sysfs 接口更新这些文件的内容以获取统计信息。

schemes/<N>/tried_regions/

此目录最初有一个文件 total_bytes

当特殊关键字 update_schemes_tried_regions 被写入相关的 kdamonds/<N>/state 文件时,DAMON 会更新 total_bytes 文件,使其读取时返回方案尝试区域的总大小,并在此目录下创建从 0 开始的整数命名的目录。在相应方案的下一个应用间隔期间,每个目录都包含文件,这些文件暴露了相应方案的 action 在此目录下尝试应用于的每个内存区域的详细信息。这些信息包括区域的地址范围、nr_accessesage

向相关的 kdamonds/<N>/state 文件写入 update_schemes_tried_bytes 将仅更新 total_bytes 文件,而不会创建子目录。

当另一个特殊关键字 clear_schemes_tried_regions 被写入相关的 kdamonds/<N>/state 文件时,这些目录将被删除。

此目录的预期用途是调查方案的行为,以及类查询的有效数据访问监控结果检索。特别是对于后一种用例,用户可以将 action 设置为 stat,并将 access pattern 设置为他们想要查询的感兴趣模式。

tried_regions/<N>/

在每个区域目录中,您会找到五个文件(startendnr_accessesagesz_filter_passed)。读取这些文件将显示相应基于 DAMON 的操作方案 action 尝试应用的区域属性。

示例

以下命令应用了一个方案,该方案表示:“如果内存区域的大小在 [4KiB, 8KiB] 之间,并且在 [10, 20] 的聚合间隔内,每聚合间隔的访问次数在 [0, 5] 之间,则将该区域换出。对于换出操作,每秒仅使用最多 10 毫秒,并且每秒换出不超过 1GiB 的内存。在此限制下,优先换出年龄较长的内存区域。此外,每 5 秒检查一次系统的空闲内存率,当空闲内存率低于 50% 时开始监控和换出,但如果空闲内存率大于 60% 或低于 30% 则停止。”

# cd <sysfs>/kernel/mm/damon/admin
# # populate directories
# echo 1 > kdamonds/nr_kdamonds; echo 1 > kdamonds/0/contexts/nr_contexts;
# echo 1 > kdamonds/0/contexts/0/schemes/nr_schemes
# cd kdamonds/0/contexts/0/schemes/0
# # set the basic access pattern and the action
# echo 4096 > access_pattern/sz/min
# echo 8192 > access_pattern/sz/max
# echo 0 > access_pattern/nr_accesses/min
# echo 5 > access_pattern/nr_accesses/max
# echo 10 > access_pattern/age/min
# echo 20 > access_pattern/age/max
# echo pageout > action
# # set quotas
# echo 10 > quotas/ms
# echo $((1024*1024*1024)) > quotas/bytes
# echo 1000 > quotas/reset_interval_ms
# # set watermark
# echo free_mem_rate > watermarks/metric
# echo 5000000 > watermarks/interval_us
# echo 600 > watermarks/high
# echo 500 > watermarks/mid
# echo 300 > watermarks/low

请注意,强烈建议使用像 damo 这样的用户空间工具,而不是如上所述手动读写文件。上述内容仅为一个示例。

监控结果的跟踪点

用户可以通过 tried_regions 获取监控结果。此接口对于获取快照很有用,但对于完整记录所有监控结果可能效率不高。为此,提供了两个跟踪点,即 damon:damon_aggregateddamon:damos_before_applydamon:damon_aggregated 提供完整的监控结果,而 damon:damos_before_apply 提供每个基于 DAMON 的操作方案(DAMOS)将要应用的区域的监控结果。因此,damon:damos_before_apply 对于记录 DAMOS 的内部行为,或基于 DAMOS 目标访问模式的类查询的高效监控结果记录更有用。

当监控开启时,您可以使用支持跟踪点的工具(如 perf)记录跟踪点事件并显示结果。例如

# echo on > kdamonds/0/state
# perf record -e damon:damon_aggregated &
# sleep 5
# kill 9 $(pidof perf)
# echo off > kdamonds/0/state
# perf script
kdamond.0 46568 [027] 79357.842179: damon:damon_aggregated: target_id=0 nr_regions=11 122509119488-135708762112: 0 864
[...]

perf 脚本输出的每一行代表一个监控区域。前五个字段与其他跟踪点输出通常相同。第六个字段(target_id=X)显示该区域监控目标的 ID。第七个字段(nr_regions=X)显示该目标的监控区域总数。第八个字段(X-Y:)显示该区域的起始(X)和结束(Y)地址(以字节为单位)。第九个字段(X)显示该区域的 nr_accesses(有关计数器的更多详细信息,请参阅设计文档)。最后,第十个字段(X)显示该区域的 age(有关计数器的更多详细信息,请参阅设计文档)。

如果事件是 damon:damos_beofre_apply,则 perf script 输出将大致如下所示

kdamond.0 47293 [000] 80801.060214: damon:damos_before_apply: ctx_idx=0 scheme_idx=0 target_idx=0 nr_regions=11 121932607488-135128711168: 0 136
[...]

输出的每一行代表一个监控区域,即在跟踪时刻即将应用每个基于 DAMON 的操作方案的区域。前五个字段照常。除了 damon_aggregated 跟踪点的输出外,它还显示方案在上下文的 kdamond 上下文列表中的 DAMON 上下文索引(ctx_idx=X),以及方案在上下文方案列表中的索引(scheme_idx=X)。