高性能编程:三级缓存(LLC)访问优化
作者:ciuwaalu,腾讯 TEG 后台开发工程师
AMD 服务器,多线程应用绑核,选取不同的 CPU 核,性能差距可达50%。
最近有幸因项目拿到一台 AMD EPYC 系列测试服务器,发现了一些奇怪的现象。
这台测试服务器拥有双路 AMD EPYC 7552 处理器,属于第二代 Rome(Zen2)架构,单路 48 个物理核,双路总计 192 个逻辑核(线程),有两个 NUMA 节点。
为了进行测试,预先编写了一个简单的多线程程序:
两个线程,分别为生产者、消费者,模拟 route-worker 模型;
三个线程,分别为生产者、转发者、消费者,模拟 pipeline 模型。
线程间采用无锁队列通信。生产者依次写入 1 ~100000000,消费者取出数字求和。线程每次写入或读取队列数据后执行一些无意义循环用于消耗时间,模拟业务逻辑。
所有线程分别绑核,避免线程迁移导致 Cache 抖动,且绑定的核心属于同一个 CPU。所有队列均在这个 CPU 的本地内存上进行分配,避免跨 NUMA 的远程内存访问。
奇怪的现象
测试发现,线程绑到不同的核上,有显著的性能差异:
绑核说明:
核 #4 #5 #6 #8 #12 #100 均为同一个 CPU,不存在跨 NUMA 访问内存的情况;
核 #4 #100 是一对 SMT 核心,即同一个物理核虚拟出来的两个逻辑核;
黄条涉及的核 #48 属于另一个 CPU,存在跨 NUMA 访问内存的情况,仅供对比。
测试结果反映了一个很奇怪的现象:线程绑核,在同一个 NUMA 选取不同的核心,性能差距竟然达到 50%(route-worker 模型 #4#5 vs #4#8)甚至 140%(pipeline 模型 #4#5#6 vs #4#8#12)。
这究竟是为什么呢?
复杂的内存层次模型
这要从内存层次说起。通常,根据延迟时间从小到大,内存层次可以划分为:(1)L1,一级缓存;(2)L2,二级缓存;(3)L3,又叫 LLC,三级缓存;(4)内存。
在具体实现上,传统的 Intel 至强系列模型比较简单:
每个物理核虚拟出两个逻辑核(TR1/TR2,TR3/TR4)
每个物理核独有 L1 和 L2
所有物理核共享 L3
这就解释了一些高性能程序开发的优化策略:
避免跨 NUMA 的远程内存访问,除了降低访问延迟,对 L3 也更友好
将线程绑核,避免 Cache 抖动,具体是避免 L1 和 L2 的抖动
共享 L3 的存在是透明的,软件上不关心,也无法关心
这一切,在 AMD 的体系结构中发生了变化。
AMD 于 2017 年发布了 Zen 架构,其中一个重要的设计原则是:一块 CPU 由多个 CCX(CPU Complex)堆叠而成。那么,CCX 是什么呢?简单来说,CCX 实际上就是 4 个物理核(8 个逻辑核)+ L3。CCX 通过 IF 总线与 IO Die 连接(Rome),实现 CCX 间互通以及与内存、IO 的通信。
图片来源:https://frankdenneman.nl/2019/10/14/amd-epyc-naples-vs-rome-and-vsphere-cpu-scheduler-updates/
所以,AMD EPYC 的内存模型就和传统模型有了很大区别:L3 并不由所有物理核共享,而是由同一个 CCX 内的 4 个物理核共享。与 NUMA 引入的“远程内存”概念类似,CCX 引入了“远程 L3”的概念。
在网上找到一个访问延迟表,供参考:
事件 | 延迟 |
---|---|
一个 CPU 周期(2.3GHz 主频) | 0.4 ns |
访问 L1 | 1.6 ns |
访问 L2 | 4.8 ns |
访问 L3 | 15.2 ns |
访问远程 L3 | 63 ns |
访问本地内存 | 75 ns |
访问远程内存 | 130 ns |
结论与优化建议
结论是,在 AMD 服务器下,如果要获得更高的性能,要针对 L3 进行优化,方法为:把一组任务(线程、进程)绑定到同一个 CCX 下的核心。
那怎样才能知道哪些核心是同一个 CCX 呢?可以使用 hwloc-ls 命令:
可以看出:#0 #96 #1 #97 #2 #98 #3 #99 是 4 个物理核 8 个逻辑核,它们共享了 16 MB 的 L3,所以这几个核属于同一个 CCX。
因此,绑核的时候,可以绑 #0 #1 #2 #3 #96 #97 #98 #99,又或者 #4 #5 #6 #7 #100 #101 #102 #103,以此类推。
文章开头的测试结果就很好解释了:#4 #5 #6 是同一个 CCX,因为它们共享 L3,每次读写队列其实都是读写 L3,所以性能高;#4 #8 #12 分属 3 个不同的 CCX,每次写队列,都会使得其它 CCX 的 L3 数据失效,导致读队列时必须要从内存中读取,所以性能差。
最后,可以通过:
perf stat -e r510143,r510243,r510843,r511043,r514043 ./xxx 查看 L3 的访问情况,PMC Code 来自 AMD的官方文档:
可以看到绑核 #4 #8 读取内存次数几乎是绑核 #4 #5 的 3 倍。
高性能编程:三级缓存(LLC)访问优化相关推荐
- (原创)使用AsyncTask(带修改线程池方式)+自定义ImageLoader+LRU算法对图片三级缓存及其显示优化(只有在ListView滑动停止的时候才去网络请求获取图片数据)
前言: 以前看了些关于图片优化处理缓存比较全的视频(感谢慕风网),现在回顾觉得还是挺好的也就总结出来下,感觉针对图片做处理这块还真的用的比较多,本文章只要使用异步线程AsyncTask.自定义的Ima ...
- 如果20万用户同时访问一个热点缓存,如何优化你的缓存架构?
点击上方"蓝字", 右上角选择"设为星标" 周一至周五上午11点45!精品技术文章准时送上! 本文转载自公众号:石杉的架构笔记 目录 (1)为什么要用缓存集群 ...
- 高性能程序设计,缓存为王
作者 | 一凡sir,全栈工程师,慕课网精英讲师 来源 | 慕课网(imooc.com) 背景 我们在程序设计时,有一个极其重要的非功能性指标:性能,总是无时无刻不缠绕在程序员的脑海,尤其是我们开发的 ...
- Java专家系列:CPU Cache与高性能编程
认识CPU Cache CPU Cache概述 随着CPU的频率不断提升,而内存的访问速度却没有质的突破,为了弥补访问内存的速度慢,充分发挥CPU的计算资源,提高CPU整体吞吐量,在CPU与内存之间引 ...
- 高性能MySQL-3rd-(六)查询性能优化
2019独角兽企业重金招聘Python工程师标准>>> /* * -------------------------------------------------------- * ...
- 面试指南|GO高性能编程精华PDF
原文:https://dablelv.blog.csdn.net/article/details/122281882 代码的稳健.可读和高效是我们每一个 coder 的共同追求,本文将结合 Go 语言 ...
- Go 高性能编程技法
作者:dablelv,腾讯 IEGggG 后台开发工程师 代码的稳健.可读和高效是我们每一个 coder 的共同追求.本文将结合 Go 语言特性,为书写效率更高的代码,从常用数据结构.内存管理和并发, ...
- Go云原生高性能编程技法,值得观看
代码的稳健.可读和高效是我们每一个 coder 的共同追求.本文将结合 Go 语言特性,为书写效率更高的代码,从常用数据结构.内存管理和并发,三个方面给出相关建议.话不多说,让我们一起学习 Go 高性 ...
- Go 高性能编程心法探秘
万字长文,耐心阅读 目录 常用数据结构 1.反射虽好,切莫贪杯 2.避免重复的字符串到字节切片的转换 3.指定容器容量 4.字符串拼接方式的选择 4.1 行内拼接字符串推荐使用运算符+ 4.2 非行内 ...
最新文章
- 【Win7下Android native code的编译和调试】
- python函数定义的要点_python基础之函数重点
- 研究者设计了Fastball任务早期诊断阿尔茨海默病
- add svn 多个文件_深圳信狮SVN技术文档
- python中的wheel有什么用_什么是Python Wheels?为什么要学Python Wheels
- C#学习笔记二(函数高级参数)
- Linux下的进程相关编程
- EXE与SYS通信(缓冲模式)
- 澳大利亚.新西兰C#考试题
- php实现关键字搜索mysql数据_PHP实现多个关键词搜索查询功能示例
- Linux学习总结(44)——Linux操作系统基础知识
- apache + subversion + Windows认证
- x等于5y等于8c语言表达式,《C语言程序设计》复习参考题.doc
- ECMAscript6入门(1)
- 精准测试系列产品白皮书2020版
- 2020年书法落款_2020鼠年书法落款怎么写?
- C Primer Plus (第六版) 第十四章_编程练习答案
- python 数据、曲线平滑处理
- Vue笔记(适合后端人员开发的快速入门)
- vue打包时候报错(压缩css错误) building for production...Error processing file: static/css/app.e8b75d3d19abc5bbb
热门文章
- understanding shader mat4 * vec4 calculation​
- CodeForces - 1452E Two Editorials(二阶差分)
- CodeForces - 1096D Easy Problem(线性dp)
- 洛谷 - P2754 [CTSC1999]家园(最大流+并查集)
- PAT (Basic Level) 1044 火星数字(模拟)
- 机器学习_机器不学习:从Spark MLlib到美图机器学习框架实践
- 华为如何在开发者选项观察错误日志_资讯:华为Mate 40 Pro屏幕供应商曝光;iPhone 13第一版原型机曝光;王者荣耀日均日活用户过亿...
- Lua和C++交互详细总结
- OD 调试带启动参数的程序
- (四)boost库之正则表达式regex