page_alloc pcpu_spin_lock/_trylock/_unlock

发布时间:2026/10/5 22:53:19

page_alloc pcpu_spin_lock/_trylock/_unlock 通用宏的特化封装再加上两个 NUMA 相关的全局定义。一、PCP 专用宏对通用宏的薄封装/* struct per_cpu_pages specific helpers. */ #define pcp_spin_lock(ptr) \ pcpu_spin_lock(struct per_cpu_pages, lock, ptr) #define pcp_spin_trylock(ptr) \ pcpu_spin_trylock(struct per_cpu_pages, lock, ptr) #define pcp_spin_unlock(ptr) \ pcpu_spin_unlock(lock, ptr)作用把前面通用的pcpu_spin_*宏绑定到struct per_cpu_pages的lock成员调用方不用每次都写struct per_cpu_pages和lock这两个参数。参数固定化通用宏参数特化后固定为typestruct per_cpu_pagesmemberlockptr仍然由调用方传入per-CPU 变量指针展开对比pcp_spin_lock(zone-per_cpu_pageset) // 展开为 pcpu_spin_lock(struct per_cpu_pages, lock, zone-per_cpu_pageset) // 再展开为 ({ struct per_cpu_pages *_ret; pcpu_task_pin(); _ret this_cpu_ptr(zone-per_cpu_pageset); spin_lock(_ret-lock); _ret; })调用示例struct per_cpu_pages *pcp; pcp pcp_spin_lock(zone-per_cpu_pageset); /* 此时已 pin 锁住当前 CPU 的 pcp */ pcp-count--; ... pcp_spin_unlock(pcp);trylock 版本同样pcp pcp_spin_trylock(zone-per_cpu_pageset); if (!pcp) { /* 没拿到锁 */ } ... pcp_spin_unlock(pcp);设计意图减少重复PCP 操作非常频繁每次都写全参数冗长且易错。语义清晰pcp_spin_lock一眼看出是锁 PCP比通用宏更直观。保持灵活性底层还是通用宏若将来 PCP 锁语义变化只需改通用宏或这层薄封装。二、CONFIG_USE_PERCPU_NUMA_NODE_ID下的 NUMA 节点 ID#ifdef CONFIG_USE_PERCPU_NUMA_NODE_ID DEFINE_PER_CPU(int, numa_node); EXPORT_PER_CPU_SYMBOL(numa_node); #endif背景为什么要 per-CPU 的 numa_node通常情况下一个 CPU 属于哪个 NUMA 节点是静态的由 ACPI/SRAT 等固件信息决定可以用一张静态表如cpu_to_node[]查。但在某些平台上CPU 到 NUMA 节点的映射可能动态变化或查询静态表开销较大如跨节点访问表本身。这时就用每个 CPU 一个numa_node变量来缓存我这个 CPU 属于哪个节点。配置项CONFIG_USE_PERCPU_NUMA_NODE_ID当该配置开启时内核用 per-CPU 变量存节点 ID。关闭时节点 ID 通过其他方式如静态表cpu_to_node获取不占 per-CPU 空间。DEFINE_PER_CPU(int, numa_node)定义每个 CPU 一份int类型的numa_node。每个 CPU 访问自己的那份时用this_cpu_read(numa_node)或per_cpu(numa_node, cpu)。在 PCP 分配路径中常用来判断从哪个 NUMA 节点分配保证本地性。EXPORT_PER_CPU_SYMBOL(numa_node)把numa_node导出给可加载模块使用类似EXPORT_SYMBOL但针对 per-CPU 符号。模块里可以用per_cpu(numa_node, cpu)访问。典型使用int node numa_node_id(); // 通常内部就是读 per-CPU 的 numa_node若配置开启PCP 分配时用它决定本地节点、本地 zone减少跨节点访问。三、vm_numa_stat_key静态键DEFINE_STATIC_KEY_TRUE(vm_numa_stat_key);什么是 static key静态键static key是内核的一种运行时分支优化机制include/linux/jump_label.h。本质把几乎总是走某条分支的代码用static_branch_*()包装编译时生成可原地修改的跳转指令NOP / jmp。运行时通过static_branch_enable/disable()改写指令实现零开销的开/关开启时分支变成 NOP直接走启用路径关闭时分支变成 jmp跳到禁用路径。比普通if (flag)好在不启用时几乎没有分支预测和内存访问开销指令被改成 NOP 或跳转。DEFINE_STATIC_KEY_TRUE定义一个静态键初始状态为true启用。对比DEFINE_STATIC_KEY_FALSE初始为禁用。vm_numa_stat_key的用途控制NUMA 统计VM NUMA statistics是否启用。相关代码通常是if (static_branch_likely(vm_numa_stat_key)) __count_numa_event(...); // 或更新 NUMA 统计初始为 true默认启用 NUMA 统计。可通过 sysfs / 内核参数在运行时static_branch_disable(vm_numa_stat_key)关闭关闭后统计代码被优化掉几乎零开销。为什么用 static key 而不是普通变量NUMA 统计在每次页分配/释放的热路径上。如果只是普通if (numa_stat_enabled)每次都要读内存、做分支判断有开销。用 static key禁用时连判断都没有变成 NOP 或直接跳走对性能敏感路径友好。而是否启用 NUMA 统计正是长期不变、适合静态键的场景。四、与 PCP 分配路径的关系把这三块放一起看它们在 PCP/分配路径中的角色定义角色pcp_spin_lock/trylock/unlock操作 PCP 时安全地 pin 加锁numa_nodeper-CPU快速获取当前 CPU 的 NUMA 节点保证本地分配vm_numa_stat_key零开销地开关 NUMA 统计PCP 分配时典型流程示意pcp pcp_spin_lock(zone-per_cpu_pageset); ... if (static_branch_likely(vm_numa_stat_key)) __count_numa_event(zone, NUMA_HIT); ... pcp_spin_unlock(pcp);五、小结代码作用pcp_spin_lock对struct per_cpu_pages加锁封装pcpu_spin_lockpcp_spin_trylock对 PCP 非阻塞加锁失败返回NULLpcp_spin_unlock解 PCP 锁 unpinDEFINE_PER_CPU(int, numa_node)每 CPU 缓存所属 NUMA 节点 ID配置相关EXPORT_PER_CPU_SYMBOL(numa_node)导出给模块用DEFINE_STATIC_KEY_TRUE(vm_numa_stat_key)NUMA 统计开关静态键实现默认开启一句话总结这段代码用pcp_spin_*把通用 per-CPU 锁宏特化到struct per_cpu_pages简化 PCP 操作再定义 per-CPU 的numa_node缓存本 CPU 的 NUMA 节点保证本地分配和静态键vm_numa_stat_key以零开销方式开关 NUMA 统计三者共同服务于 PCP 分配路径的性能与 NUMA 局部性。
延伸阅读

更多相关文章

2026/10/5 22:48:19

STM32F469II 与 MR25H40CDF MRAM 工业存储方案实战

1. 为什么 MRAM 在工业嵌入式场景里越来越受关注搞过工业数据采集或者电力终端的朋友应该都有体会,选存储芯片这件事,很多时候比选主控还让人头疼。EEPROM 擦写寿命不够、FRAM 容量太小、NOR Flash 写入速度慢还怕掉电、SRAM 又得配电池。这几年 MRAM 慢…

2026/10/5 22:43:18

MRAM与PIC18F47Q10实战:SPI驱动、数据存储与工业可靠性设计

1. 项目缘起与方案选型:为什么是 MRAM 加 PIC18做嵌入式这行十几年,最头疼的往往不是算法多复杂,而是数据存不住。尤其是工业现场那些设备——PLC 扩展模块、智能仪表、电机驱动器——经常要在断电瞬间把关键参数、故障记录、累计运行时间保存…

2026/10/5 23:48:22

GESP等级考试C++5级20-素数判断法3

2.3 线性筛 埃氏筛里一个合数会被划多次(如 30 会被 2、3、5 各划一次),做了冗余工作。线性筛的核心目标:每个合数只被它的最小质因子划掉,且只划一次,从而做到严格 O(n)。 线性筛的原理:维护一个已找到的素数数组prime[],对每个 i: (1)若 i 没被标记过,说明 i …

2026/10/5 23:43:21

MR25H40CDF F-RAM工业存储设计:高可靠低延迟数据管道构建

1. MR25H40CDF不是“普通Flash”,它是一块带铁电特性的工业级非易失存储器很多人第一次看到MR25H40CDF这个型号,第一反应是:“哦,又一个SPI Flash?”——这恰恰是项目启动阶段最容易踩的第一个认知坑。我去年在给一家做…

2026/10/5 23:43:21

百考通AI精准适配不同学历层次的论文需求

在高校毕业季,毕业论文往往是压在学子心头的一座大山。从选题定题到框架搭建,从内容撰写到格式规范,繁琐的流程常常让专科、本科及研究生们焦头烂额。如今,百考通AI(https://www.baikaotongai.com)凭借智能…

2026/10/5 6:32:56

Jev+Agent接管浏览器:browser-use实战与jev-ultrafast性能优化

1. 从“Jev”说起:为什么我要把Agent接进浏览器“Jev”这个词最近在圈子里出现的频率越来越高,很多人第一次听到会以为是某个新模型的名字,其实它更像是一种思路——把Jev模型的能力当作底座,通过Agent的方式去接管浏览器&#xf…

2026/10/4 0:01:02

多智能体集群实战:DeepAgents编排、MCP与A2A协议及Skills体系

1. 从"单兵作战"到"集群协同":多智能体编排到底在解决什么问题如果你最近在折腾 Agent 相关的东西,大概率会有一种感觉:单个 Agent 能做的事情,其实很快就摸到天花板了。你给它一个提示词,挂几个工…

2026/10/5 17:38:27

无源低通滤波器设计实战:从RC到LC,手把手教你避开那些坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑