ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Linux NUMA 内存性能与 locality 接口全解析:numaperf 文档与内核实现

Linux NUMA 内存性能与 locality 接口全解析:numaperf 文档与内核实现 Linux NUMA 内存性能与 locality 接口全解析numaperf 文档与内核实现【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linuxNUMANon-Uniform Memory Access平台上不同内存节点在带宽、延迟等性能特征上往往并不一致。本文以 Linux 内核文档 numaperf.rst 为骨架结合drivers/base/node.c、drivers/acpi/numa/hmat.c与include/linux/node.h的源码实现系统讲解内核如何通过 sysfs 暴露 NUMA locality、性能等级与内存侧缓存memory-side cache信息。读完本文你将掌握如何通过/sys/devices/system/node/下的access0/access1目录、initiators/targets符号链接与memory_side_cache目录完成异构内存平台上的内存选型与性能调优。1. NUMA Locality异构内存与访问等级1.1 异构内存的基本模型部分平台会在同一个计算节点compute node上挂接多种类型的内存。这些物理地址区间可能共享部分特征如 CPU 缓存一致性但在性能上差异明显——不同的介质类型如 DRAM、HBM、持久内存和总线会显著影响带宽与延迟。内核将每种内存类型按照 locality 和性能特征归入不同的域domain也就是不同的 node计算节点compute node包含 CPU拥有本地内存纯内存节点memory only node不提供 CPU但相对其他节点而言仍可能本地于一个或多个计算节点。文档给出了两个计算节点各带本地内存、并为每个计算节点配一个较慢内存节点的拓扑示例------------------ ------------------ | Compute Node 0 ----- Compute Node 1 | | Local Node0 Mem | | Local Node1 Mem | ----------------- ----------------- | | ----------------- ----------------- | Slower Node2 Mem | | Slower Node3 Mem | ------------------ -----------------1.2 内存发起者Memory Initiator与内存目标Memory Target文档定义了两个核心概念内存发起者memory initiator包含一个或多个可以发起内存请求设备的节点例如 CPU或独立的内存 I/O 设备GPU、NIC 等内存目标memory target包含一个或多个可被若干发起者访问的物理地址区间的节点。当存在多个内存发起者时它们访问同一内存目标的性能未必相同。每个initiator-target 对会被归入不同的等级访问类别ranked access class以刻画这种性能关系对某个目标性能最高的发起者被视为该目标的local initiator其访问类别为最高级0任意目标可以有多个 local initiator任意发起者也可以有多个 local 内存目标。从源码看drivers/base/node.c中的struct node_access_nodes正是承载这一关系的设备对象字段access保存访问等级coord在CONFIG_HMEM_REPORTING下保存异构内存性能坐标drivers/base/node.c#L81-L88。节点会以dev_set_name(dev, access%u, access)的方式命名该设备drivers/base/node.c#L170对应 sysfs 中的access0、access1等目录。1.3 通过符号链接查看 initiator 与 target 的关系为帮助应用程序把内存目标与合适的发起者匹配起来内核在两者之间建立了双向符号链接。文档给出了访问类别 0 的示例# symlinks -v /sys/devices/system/node/nodeX/access0/targets/ relative: /sys/devices/system/node/nodeX/access0/targets/nodeY - ../../nodeY # symlinks -v /sys/devices/system/node/nodeY/access0/initiators/ relative: /sys/devices/system/node/nodeY/access0/initiators/nodeX - ../../nodeX对应实现为register_memory_node_under_compute_node()它先在发起者节点与目标节点上各创建一个access%u设备再分别调用sysfs_add_link_to_group()在发起者的targets组、目标的initiators组中建立符号链接drivers/base/node.c#L727-L762。initiators与targets属性组在 drivers/base/node.c#L99-L113 定义。需要留意的语义细节一个发起者可以在同一访问类别下拥有多个内存目标这些目标之间性能并不必然相同访问类别 1对应源码中的ACCESS_COORDINATE_CPU专门用于区分CPU 发起者适合做通用任务调度与IO 发起者如 GPU、NIC。与类别 0 不同类别 1 只考虑包含 CPU 的节点。2. NUMA Performance从 sysfs 读取带宽与延迟应用程序可能希望根据节点性能特征来决定内存从哪个节点分配。当系统提供了这些属性时内核会将它们导出到内存节点访问类别 0 的发起者目录下/sys/devices/system/node/nodeY/access0/initiators/这些属性仅在从该访问类别下已建立链接的节点访问时才有意义。内核为 local initiators 导出的性能属性如下文档中的tree输出# tree -P read*|write* /sys/devices/system/node/nodeY/access0/initiators/ /sys/devices/system/node/nodeY/access0/initiators/ |-- read_bandwidth |-- read_latency |-- write_bandwidth -- write_latency单位约定带宽属性单位为MiB/second延迟属性单位为纳秒nanoseconds报告值对应平台的额定rated带宽与延迟。访问类别 1 采用相同形式但只包含 CPU 到内存活动的数值。2.1 源码中的属性生成机制drivers/base/node.c通过ACCESS_ATTR宏为上述四个属性生成_show回调统一从struct access_coordinate中读取数值并sysfs_emit输出ACCESS_ATTR(read_bandwidth);ACCESS_ATTR(read_latency);ACCESS_ATTR(write_bandwidth);ACCESS_ATTR(write_latency);见 drivers/base/node.c#L186-L208对应的数据结构struct access_coordinate定义于 include/linux/node.h#L29-L34四个字段的语义与 sysfs 属性一一对应字段含义read_bandwidth读带宽MB/swrite_bandwidth写带宽MB/sread_latency读延迟纳秒write_latency写延迟纳秒内核对外提供两个导出接口include/linux/node.h#L86-L89node_set_perf_attrs()设置给定访问类别的性能值并创建access%u/initiators/下的属性文件drivers/base/node.c#L216-L249node_update_perf_attrs()更新已有访问类别的性能值并通过sysfs_notify()通知用户态drivers/base/node.c#L257-L287。值得注意的是当访问类别为ACCESS_COORDINATE_CPU时node_set_perf_attrs()还会调用mempolicy_set_node_perf()同步更新内存策略mempolicy即性能坐标不仅面向用户态查询还会参与内核自身的策略决策。2.2 数据来源ACPI HMATdrivers/acpi/numa/hmat.c是这些属性的主要提供者。HMATHeterogeneous Memory Attribute Table异构内存属性表定义于 ACPI 6.2 规范的 Section 5.2.27内核解析后hmat_register_target_perf()调用node_set_perf_attrs()为每个内存目标按访问类别设置性能坐标drivers/acpi/numa/hmat.c#L853-L857__hmat_register_target_initiators()遍历最佳性能的发起者节点调用register_memory_node_under_compute_node()建立initiators/targets链接drivers/acpi/numa/hmat.c#L809-L822类别 0ACCESS_COORDINATE_LOCAL与类别 1ACCESS_COORDINATE_CPU分别注册drivers/acpi/numa/hmat.c#L834-L842。因此上述 sysfs 属性是否出现、取值多少取决于平台固件是否提供 HMAT 表以及内核是否开启CONFIG_HMEM_REPORTING。3. NUMA Cache内存侧缓存Memory-Side Cache3.1 层级模型与术语系统内存可以构建成多层结构用较小的、性能更高的内存为较大的、性能较低的内存提供透明缓存从而形成大地址空间。发起者感知到的系统物理地址由层级中的最后一层提供系统则用高层性能内存透明缓存对更慢层次的访问。文档给出的关键术语far memory远内存层级中的最后一层内存near memory近内存系统提供的最快缓存层。编号方向与 CPU 缓存相反CPU 缓存L1/L2/L3从 CPU 视角编号级别越高性能越低而内存侧缓存以最后一层内存为中心编号越高越靠近 CPU、离 far memory 越远。内存侧缓存不能由软件直接寻址软件访问某个系统地址时系统优先从近内存缓存返回命中数据未命中则访问下一级内存直到命中或直达 far memory。应用使用这种系统无需感知缓存属性但可以可选地查询内存缓存属性以最大化性能。当内核能从平台发现这些信息例如通过 ACPI HMAT时会把这些属性挂到 NUMA 节点的内存目标上。3.2 sysfs 目录结构内核首次为一个节点注册内存缓存时会创建如下目录/sys/devices/system/node/nodeX/memory_side_cache/如果该目录不存在说明系统要么没有内存侧缓存要么内核无法获取该信息。每个缓存级别的属性放在其级别索引目录下/sys/devices/system/node/nodeX/memory_side_cache/indexA/ /sys/devices/system/node/nodeX/memory_side_cache/indexB/ /sys/devices/system/node/nodeX/memory_side_cache/indexC/文档给出的单级缓存示例# tree /sys/devices/system/node/node0/memory_side_cache/ /sys/devices/system/node/node0/memory_side_cache/ |-- index1 | |-- indexing | |-- line_size | |-- size | -- write_policy3.3 属性语义属性含义indexing0 表示直接映射direct-mapped缓存非 0 表示其他基于索引的多路组相联multi-way associativityline_size缓存未命中时从下一缓存级别读取的字节数size该缓存级别提供的字节数write_policy0 表示写回write-back非 0 表示写透write-through3.4 源码实现drivers/base/node.c中node_init_cache_dev()创建名为memory_side_cache的设备drivers/base/node.c#L339-L361node_add_cache()为每个缓存级别创建index%d设备%d为缓存级别号并挂载缓存属性组drivers/base/node.c#L368-L415同一节点重复注册同一级别会打印attempt to add duplicate cache level告警CACHE_ATTR宏生成了size、line_size、indexing、write_policy、address_mode五个只读属性drivers/base/node.c#L302-L316——比文档示例多出一个address_mode属性即地址模式。这些字段的类型与枚举定义在 include/linux/node.h#L48-L81enum cache_indexing { NODE_CACHE_DIRECT_MAP, NODE_CACHE_INDEXED, NODE_CACHE_OTHER, }; enum cache_write_policy { NODE_CACHE_WRITE_BACK, NODE_CACHE_WRITE_THROUGH, NODE_CACHE_WRITE_OTHER, }; struct node_cache_attrs { enum cache_indexing indexing; enum cache_write_policy write_policy; u64 size; u16 line_size; u8 level; u16 address_mode; };在 HMAT 数据源侧hmat_register_target_cache()遍历目标上登记的缓存列表逐一调用node_add_cache()完成注册drivers/acpi/numa/hmat.c#L844-L851。4. 内核实现路径总览将文档中的用户可见接口与内核源码对应起来可以总结出如下数据流固件层面平台在 ACPI 表中提供 HMATHeterogeneous Memory Attribute Table见 ACPI 6.2 规范 Section 5.2.27内核解析drivers/acpi/numa/hmat.c解析 HMAT建立内存目标target、内存发起者initiator与缓存层级cache的内部模型sysfs 暴露hmat_register_target_initiators()→register_memory_node_under_compute_node()→accessN/initiators/与accessN/targets/双向符号链接hmat_register_target_perf()→node_set_perf_attrs()→accessN/initiators/下的read_bandwidth、read_latency、write_bandwidth、write_latencyhmat_register_target_cache()→node_add_cache()→memory_side_cache/indexN/下的size、line_size、indexing、write_policy、address_mode用户态消费应用、调度器或内存管理工具读取上述只读属性结合访问类别与性能坐标做内存分配决策。5. 使用建议与注意事项先确认平台能力检查/sys/devices/system/node/nodeX/下是否存在access0/access1与memory_side_cache目录不存在即表示平台未提供 HMAT 或内核无法获取信息也需确认内核是否开启CONFIG_HMEM_REPORTING与CONFIG_ACPI_HMAT区分访问类别类别 0ACCESS_COORDINATE_LOCAL刻画节点间最近发起者的性能类别 1ACCESS_COORDINATE_CPU只反映 CPU 到内存的性能适合与任务调度结合使用单位易错点带宽以 MiB/s 计、延迟以纳秒计报告的是平台额定值而非实测值直接比较时应保持单位一致缓存属性只读可选memory_side_cache的信息仅用于性能优化参考应用无需依赖它们即可正常运行若需实测可结合基准工具自行验证额定值与实际表现的差异内存策略联动设置 CPU 访问坐标时内核会同步更新 mempolicy这意味着性能坐标不仅暴露给用户态也会影响内核的内存分配行为。6. 延伸阅读内核文档原文Documentation/admin-guide/mm/numaperf.rst节点 sysfs 接口核心实现drivers/base/node.c性能坐标与缓存属性数据结构定义include/linux/node.h#L22-L81ACPI HMAT 解析与注册逻辑drivers/acpi/numa/hmat.c异构内存属性表HMAT规范出处ACPI 6.2 规范 Section 5.2.27【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表