
【免费下载链接】cpu-performance-engineeringA reading path for CPU performance engineering, from one instruction to production inference. Primary sources only, with a runnable benchmark for every section.项目地址https://gitcode.com/gh_mirrors/cp/cpu-performance-engineering点击查看免费下载写多线程代码时性能瓶颈往往不丢在 CPU 的算术单元而丢在核与核之间的缓存行乒乓和内存排序上。本文基于开源项目 cpu-performance-engineering——一条从单条指令到生产环境推理的 CPU 性能优化阅读路径每一章都配一个可复现的 benchmark——拆解 x86 与 Arm 上内存模型、原子操作、锁和无锁结构的成本来源并给出可以自己重跑的实测数据。先建立一个结论并发程序的代价是「缓存行在跑」并发章节里所有性能开销最终都能归到一件事一条 cache line 在多个核之间来回搬运。现代 CPU 的每个核都有独立的 L1 缓存硬件靠缓存一致性协议MESI 类保证大家看到的内存一致——核心规则只有一条写会失效。当核 A 要写某一行其他核手里这一行的副本立刻作废写方必须先把这一行以可写状态抢到手里。于是同时写同一行的核越多这一行被抢得越频繁性能被串行化得越狠行的粒度是硬件参数x86 服务器平台是 64 字节Arm 服务器是 128 字节padding 规则必须按目标机器自己的值来定行一旦跨出 socketNUMA单次搬运就是几百纳秒的量级——这比核间乒乓还贵一个数量级。x86 与 Arm 内存模型差异同样的 C 代码不同的成本**内存模型memory model**规定的是你的读和写按什么顺序被其他核看到。两大架构风格截然不同直接决定了编译器为同一段 C 生成什么指令对比项x86TSO 强模型Arm弱内存模型默认排序强store 不能越过更早的 store弱读、写都可被硬件/编译器重排memory_order_relaxed普通mov读写普通ldr/strrelease / acquire 语义普通 store / load 即满足必须stlr/ldarmemory_order_seq_cst原子加一条lock xadd原子指令 屏障视 ISA 而定屏障barrier成本相对便宜可能显著三个要点记住就够用了x86 强在默认就接近人脑直觉代价是硬件更保守seq_cst的写侧就是一条lock xadd。Arm 弱在给硬件更多重排自由默认更快但每次想堵住重排都要显式付一笔ldar/stlr/dmb。C 的 memory order 本质上是成本档位relaxed、acquire/release、seq_cst不只是语义差别它们映射到不同的指令性能差异是可以被测量出来的。项目在并发章节列出的内存模型一手资料C 内存模型奠基论文、原子操作的规范条文、内存顺序到 x86/Arm 指令的映射表、内核 memory-barriers 文档都在 misc/notes/sections/09-concurrency.md 中想深挖从这里进。锁到底花多少成本mutex 的三个成本来源 互斥锁的成本分两层量级差好几个数量级必须分开看快路径无竞争一次缓存行往返就算没人跟你抢lock unlock也意味着锁变量的那一行离开当前核再回来一次。无竞争环境的锁开销就是一次行传输的延迟大约几十纳秒。慢路径有竞争进内核竞争一旦发生就要进内核把线程挂起、再唤醒。Linux 的 futex 设计就是为此无竞争永不进内核竞争了才进一次。所以竞争频率是锁的第一成本源每次进内核 调度延迟比快路径贵 1~2 个数量级普通自旋锁不可扩展所有线程挤在同一把锁变量上线程越多行乒乓越凶吞吐量随核数超线性下滑。队列锁MCS正是为此设计——每个等待者自旋在自己独占的缓存行上把乒乓降到最少Single Writer 原则让每个变量只有一个写者其余线程读快照写竞争直接消失。这是整个并发优化的第一原则。最容易踩的坑伪共享false sharing两个线程各自写自己的变量却恰好落在同一条缓存行里。硬件不关心变量归属只看到这行又被别人写了于是照样乒乓——这就是伪共享。仓库里的 benchmark misc/benchmarks/09-false-sharing/ 测的就是这个T 个线程各自原子自增一个计数器对比计数器间隔 8 字节与pad 到独占一行两种布局测试机Apple M4 Pro128 字节缓存行单核约 4.49 GHz线程数相邻布局ns/次自增填充布局ns/次自增慢了多少11.5621.5581.00×27.1251.5974.46×426.3391.79114.71×8244.9581.811135.23×数据说明了三件事单线程时两种布局完全一样——成本不来自布局本身而来自第二个核碰了同一行相邻布局的变慢随线程数超线性增长8 线程 135 倍因为 T 个核在轮流抢同一行且 8 线程时行还要在两个 L2 集群之间跨来跨去每个计数器 pad 到独立 128 字节行后单次自增约 1.8 ns接近无内存流量的下限且随线程数近线性扩展。规避方法极简给每个共享变量_Alignas(64)x86或_Alignas(128)Arm让它们独占缓存行或改设计每线程在私有位置累加任务结束时再归并——一人一行。完整原始数据见 results/summary.md实现含自旋屏障、逐轮 CPU 落点记录见 bench.c。无锁结构真的快吗三个认知纠偏 ⚡lock-free 只表示不阻塞绝不等于快。新手最常踩的三个认知坑1. 无锁的代价同样是缓存行乒乓无锁队列的每次入队/出队都要对头尾指针做原子 CAS。CAS 的语义是先把行拿到可写状态再比较写入所以多核争用同一队列端点时行照样乒乓——区别只是线程在用户态自旋而不是进内核睡眠。争用程度相同时成本量级和锁是一样的。2. 无锁结构还有一份隐藏账单ABA 与内存回收指针可能被释放后以相同地址重新分配值相等可能比较的是两个不同对象——ABA 问题。解法要额外记账而已退休的节点在读者还可能持有它时不能直接 free需要 Hazard Pointers 或 RCU 这类安全内存回收机制。这是看起来几行代码的无锁结构没写出来的工程成本。3. 读写两侧的成本是不对称的RCURead-Copy Update是不对称的极端例子读侧无锁、无原子操作成本近乎为零写侧要等所有旧读者离场才能更新代价全部由写者承担。由此得到选型规则访问模式推荐方向读多写极少RCU / 无锁读写侧付代价读写均衡锁 Single Writer 原则写争用极高分区 / 每线程私有队列 批量归并work-stealing 线程池的 deque 正是这种形态私有路径快偷取这条少走的争用路径才付原子操作的钱自己动手复现七字段证据规则 项目有一条铁律任何性能数字必须带齐七个字段——CPU 型号与微架构、使用的核数、频率含 turbo/SMT 状态、编译器与 flags、workload、baseline、测量方法——缺一项数字不进仓库。这条规则让某人说快 10 倍这种说法无处遁形。复现 false sharing 只需两条命令在对应目录下./run.sh # 完整跑一轮约 65 秒 QUICK1 ./run.sh # 冒烟测试约 5 秒每次运行会把机器描述、时钟估计、每轮线程落在哪个核都写进results/raw.txt并回贴到 README让你能核对这个数字是谁的锅。14 个 benchmark 的总索引在 misc/benchmarks/README.md。新手实用清单内存模型与原子操作优化六条 ✅每个共享变量只有一个写者其余线程读快照Single Writer 原则高频写变量各自独占一条缓存行_Alignas(64)/_Alignas(128)或把计数器做成每线程私有数组本地累加、事后归并把共享写降到每任务一次选满足正确性的最低 memory order先确认没有排序依赖再用relaxed换掉seq_cst降竞争频率优先于换更强的锁分区、批处理让锁的快路径保持不进内核测别猜用硬件计数器找出争用的行用可复现的 benchmark 验证改动。下一步读什么项目完整阅读路径第 9 章 Concurrency 起README.md并发章节一手资料清单内存模型、锁、无锁、RCU、work-stealingmisc/notes/sections/09-concurrency.md伪共享 benchmark 全量数据misc/benchmarks/09-false-sharing/README.md跨 socket 的行更贵first touch 与 NUMA 放置misc/benchmarks/10-first-touch/README.md赞分享【免费下载链接】cpu-performance-engineeringA reading path for CPU performance engineering, from one instruction to production inference. Primary sources only, with a runnable benchmark for every section.项目地址https://gitcode.com/gh_mirrors/cp/cpu-performance-engineering点击查看免费下载相关推荐TinyWebServer无锁编程原子操作与内存屏障TinyWebServer无锁编程原子操作与内存屏障 在高并发的Linux服务器开发中传统锁机制如互斥锁、信号量常常成为性能瓶颈。TinyWebServ后端网络/通信DiceDB原子操作无锁数据结构DiceDB原子操作无锁数据结构 引言现代数据库的性能挑战 在高并发场景下传统数据库往往面临严重的锁竞争问题。当多个客户端同时访问共享数据时互斥锁Mu数据库缓存后端GetQzonehistory 指南免费导出 QQ 空间十年说说的完整备份GetQzonehistory 指南免费导出 QQ 空间十年说说的完整备份 空间里堆着上千条老说说翻到第二页就放弃了GetQzonehistory 是个免网页爬虫数据分析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考