作者:ciuwaalu,腾讯 TEG 后台开发工程师

AMD 服务器,多线程应用绑核,选取不同的 CPU 核,性能差距可达50%。

最近有幸因项目拿到一台 AMD EPYC 系列测试服务器,发现了一些奇怪的现象。

这台测试服务器拥有双路 AMD EPYC  7552  处理器,属于第二代 Rome(Zen2)架构,单路 48 个物理核,双路总计 192 个逻辑核(线程),有两个 NUMA 节点。

为了进行测试,预先编写了一个简单的多线程程序:

  1. 两个线程,分别为生产者、消费者,模拟 route-worker 模型;

  2. 三个线程,分别为生产者、转发者、消费者,模拟 pipeline 模型。

线程间采用无锁队列通信。生产者依次写入 1 ~100000000,消费者取出数字求和。线程每次写入或读取队列数据后执行一些无意义循环用于消耗时间,模拟业务逻辑。

所有线程分别绑核,避免线程迁移导致 Cache 抖动,且绑定的核心属于同一个 CPU。所有队列均在这个 CPU 的本地内存上进行分配,避免跨 NUMA 的远程内存访问。

奇怪的现象

测试发现,线程绑到不同的核上,有显著的性能差异:

绑核说明:

  1. 核 #4 #5 #6 #8 #12 #100 均为同一个 CPU,不存在跨 NUMA 访问内存的情况;

  2. 核 #4 #100 是一对 SMT 核心,即同一个物理核虚拟出来的两个逻辑核;

  3. 黄条涉及的核 #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)访问优化相关推荐

  1. (原创)使用AsyncTask(带修改线程池方式)+自定义ImageLoader+LRU算法对图片三级缓存及其显示优化(只有在ListView滑动停止的时候才去网络请求获取图片数据)

    前言: 以前看了些关于图片优化处理缓存比较全的视频(感谢慕风网),现在回顾觉得还是挺好的也就总结出来下,感觉针对图片做处理这块还真的用的比较多,本文章只要使用异步线程AsyncTask.自定义的Ima ...

  2. 如果20万用户同时访问一个热点缓存,如何优化你的缓存架构?

    点击上方"蓝字", 右上角选择"设为星标" 周一至周五上午11点45!精品技术文章准时送上! 本文转载自公众号:石杉的架构笔记 目录 (1)为什么要用缓存集群 ...

  3. 高性能程序设计,缓存为王

    作者 | 一凡sir,全栈工程师,慕课网精英讲师 来源 | 慕课网(imooc.com) 背景 我们在程序设计时,有一个极其重要的非功能性指标:性能,总是无时无刻不缠绕在程序员的脑海,尤其是我们开发的 ...

  4. Java专家系列:CPU Cache与高性能编程

    认识CPU Cache CPU Cache概述 随着CPU的频率不断提升,而内存的访问速度却没有质的突破,为了弥补访问内存的速度慢,充分发挥CPU的计算资源,提高CPU整体吞吐量,在CPU与内存之间引 ...

  5. 高性能MySQL-3rd-(六)查询性能优化

    2019独角兽企业重金招聘Python工程师标准>>> /* * -------------------------------------------------------- * ...

  6. 面试指南|GO高性能编程精华PDF

    原文:https://dablelv.blog.csdn.net/article/details/122281882 代码的稳健.可读和高效是我们每一个 coder 的共同追求,本文将结合 Go 语言 ...

  7. Go 高性能编程技法

    作者:dablelv,腾讯 IEGggG 后台开发工程师 代码的稳健.可读和高效是我们每一个 coder 的共同追求.本文将结合 Go 语言特性,为书写效率更高的代码,从常用数据结构.内存管理和并发, ...

  8. Go云原生高性能编程技法,值得观看

    代码的稳健.可读和高效是我们每一个 coder 的共同追求.本文将结合 Go 语言特性,为书写效率更高的代码,从常用数据结构.内存管理和并发,三个方面给出相关建议.话不多说,让我们一起学习 Go 高性 ...

  9. Go 高性能编程心法探秘

    万字长文,耐心阅读 目录 常用数据结构 1.反射虽好,切莫贪杯 2.避免重复的字符串到字节切片的转换 3.指定容器容量 4.字符串拼接方式的选择 4.1 行内拼接字符串推荐使用运算符+ 4.2 非行内 ...

最新文章

  1. 【Win7下Android native code的编译和调试】
  2. python函数定义的要点_python基础之函数重点
  3. 研究者设计了Fastball任务早期诊断阿尔茨海默病
  4. add svn 多个文件_深圳信狮SVN技术文档
  5. python中的wheel有什么用_什么是Python Wheels?为什么要学Python Wheels
  6. C#学习笔记二(函数高级参数)
  7. Linux下的进程相关编程
  8. EXE与SYS通信(缓冲模式)
  9. 澳大利亚.新西兰C#考试题
  10. php实现关键字搜索mysql数据_PHP实现多个关键词搜索查询功能示例
  11. Linux学习总结(44)——Linux操作系统基础知识
  12. apache + subversion + Windows认证
  13. x等于5y等于8c语言表达式,《C语言程序设计》复习参考题.doc
  14. ECMAscript6入门(1)
  15. 精准测试系列产品白皮书2020版
  16. 2020年书法落款_2020鼠年书法落款怎么写?
  17. C Primer Plus (第六版) 第十四章_编程练习答案
  18. python 数据、曲线平滑处理
  19. Vue笔记(适合后端人员开发的快速入门)
  20. vue打包时候报错(压缩css错误) building for production...Error processing file: static/css/app.e8b75d3d19abc5bbb

热门文章

  1. understanding shader mat4 * vec4 calculation​
  2. CodeForces - 1452E Two Editorials(二阶差分)
  3. CodeForces - 1096D Easy Problem(线性dp)
  4. 洛谷 - P2754 [CTSC1999]家园(最大流+并查集)
  5. PAT (Basic Level) 1044 火星数字(模拟)
  6. 机器学习_机器不学习:从Spark MLlib到美图机器学习框架实践
  7. 华为如何在开发者选项观察错误日志_资讯:华为Mate 40 Pro屏幕供应商曝光;iPhone 13第一版原型机曝光;王者荣耀日均日活用户过亿...
  8. Lua和C++交互详细总结
  9. OD 调试带启动参数的程序
  10. (四)boost库之正则表达式regex