原文:吴一昊,杨勇 Linux阅码场

地址:CPU Cache Line伪共享问题的总结和分析

Table of Contents

1. 关于本文

2. 背景知识

2.1 存储器层次结构

2.2 多核架构

2.3 NUMA 架构

Cache

DRAM

Device

2.4 Cache Line

2.5 Cache 的结构

2.6 Cache 一致性

2.7 Cache Line 伪共享


1. 关于本文

本文基于 Joe Mario 的一篇博客 改编而成。 
Joe Mario 是 Redhat 公司的 Senior Principal Software Engineer,在系统的性能优化领域颇有建树,他也是本文描述的 perf c2c 工具的贡献者之一。 
这篇博客行文比较口语化,且假设读者对 CPU 多核架构,Cache Memory 层次结构,以及 Cache 的一致性协议有所了解。 
故此,笔者决定放弃照翻原文,并且基于原博客文章做了一些扩展,增加了相关背景知识简介。 
本文中若有任何疏漏错误,责任在于编译者。有任何建议和意见,请回复内核月谈微信公众号,或通过 oliver.yang at linux.alibaba.com 反馈。

2. 背景知识

要搞清楚 Cache Line 伪共享的概念及其性能影响,需要对现代理器架构和硬件实现有一个基本的了解。 
如果读者已经对这些概念已经有所了解,可以跳过本小节,直接了解 perf c2c 发现 Cache Line 伪共享的方法。 
(注:本节中的所有图片,均来自与 Google 图片搜索,版权归原作者所有。)

2.1 存储器层次结构

众所周知,现代计算机体系结构,通过存储器层次结构 (Memory Hierarchy) 的设计,使系统在性能,成本和制造工艺之间作出取舍,从而达到一个平衡。 
下图给出了不同层次的硬件访问延迟,可以看到,各个层次硬件访问延迟存在数量级上的差异,越高的性能,往往意味着更高的成本和更小的容量:

通过上图,可以对各级存储器 Cache Miss 带来的性能惩罚有个大致的概念。

2.2 多核架构

随着多核架构的普及,对称多处理器 (SMP) 系统成为主流。例如,一个物理 CPU 可以存在多个物理 Core,而每个 Core 又可以存在多个硬件线程。 
x86 以下图为例,1 个 x86 CPU 有 4 个物理 Core,每个 Core 有两个 HT (Hyper Thread),

从硬件的角度,上图的 L1 和 L2 Cache 都被两个 HT 共享,且在同一个物理 Core。而 L3 Cache 则在物理 CPU 里,被多个 Core 来共享。 
而从 OS 内核角度,每个 HT 都是一个逻辑 CPU,因此,这个处理器在 OS 来看,就是一个 8 个 CPU 的 SMP 系统。

2.3 NUMA 架构

一个 SMP 系统,按照其 CPU 和内存的互连方式,可以分为 UMA (均匀内存访问) 和 NUMA (非均匀内存访问) 两种架构。 
其中,在多个物理 CPU 之间保证 Cache 一致性的 NUMA 架构,又被称做 ccNUMA (Cache Coherent NUMA) 架构。

PS:NUMA(Non Uniform Memory Access Architecture)技术可以使众多服务器像单一系统那样运转,同时保留小系统便于编程和管理的优点。基于电子商务应用对内存访问提出的更高的要求,NUMA也向复杂的结构设计提出了挑战。非统一内存访问(NUMA)是一种用于多处理器的电脑记忆体设计,内存访问时间取决于处理器的内存位置。 在NUMA下,处理器访问它自己的本地存储器的速度比非本地存储器(存储器的地方到另一个处理器之间共享的处理器或存储器)快一些。

以 x86 为例,早期的 x86 就是典型的 UMA 架构。例如下图,四路处理器通过 FSB (前端系统总线) 和主板上的内存控制器芯片 (MCH) 相连,DRAM 是以 UMA 方式组织的,延迟并无访问差异,

然而,这种架构带来了严重的内存总线的性能瓶颈,影响了 x86 在多路服务器上的可扩展性和性能。

因此,从 Nehalem 架构开始,x86 开始转向 NUMA 架构,内存控制器芯片被集成到处理器内部,多个处理器通过 QPI 链路相连,从此 DRAM 有了远近之分。 
而 Sandybridge 架构则更近一步,将片外的 IOH 芯片也集成到了处理器内部,至此,内存控制器和 PCIe Root Complex 全部在处理器内部了。 
下图就是一个典型的 x86 的 NUMA 架构:

由于 NUMA 架构的引入,以下主要部件产生了因物理链路的远近带来的延迟差异:

  • Cache

    除物理 CPU 有本地的 Cache 的层级结构以外,还存在跨越系统总线 (QPI) 的远程 Cache 命中访问的情况。需要注意的是,远程的 Cache 命中,对发起 Cache 访问的 CPU 来说,还是被记入了 LLC Cache Miss。

  • DRAM

    在两路及以上的服务器,远程 DRAM 的访问延迟,远远高于本地 DRAM 的访问延迟,有些系统可以达到 2 倍的差异。 
    需要注意的是,即使服务器 BIOS 里关闭了 NUMA 特性,也只是对 OS 内核屏蔽了这个特性,这种延迟差异还是存在的。

  • Device

    对 CPU 访问设备内存,及设备发起 DMA 内存的读写活动而言,存在本地 Device 和远程 Device 的差别,有显著的延迟访问差异。

因此,对以上 NUMA 系统,一个 NUMA 节点通常可以被认为是一个物理 CPU 加上它本地的 DRAM 和 Device 组成。那么,四路服务器就拥有四个 NUMA 节点。 
如果 BIOS 打开了 NUMA 支持,Linux 内核则会根据 ACPI 提供的表格,针对 NUMA 节点做一系列的 NUMA 亲和性的优化。

在 Linux 上,numactl --hardware 可以返回当前系统的 NUMA 节点信息,特别是 CPU 和 NUMA 节点的对应信息。

2.4 Cache Line

Cache Line 是 CPU 和主存之间数据传输的最小单位。当一行 Cache Line 被从内存拷贝到 Cache 里,Cache 里会为这个 Cache Line 创建一个条目。 
这个 Cache 条目里既包含了拷贝的内存数据,即 Cache Line,又包含了这行数据在内存里的位置等元数据信息。

由于 Cache 容量远远小于主存,因此,存在多个主存地址可以被映射到同一个 Cache 条目的情况,下图是一个 Cache 和主存映射的概念图:

而这种 Cache 到主存的映射,通常是由内存的虚拟或者物理地址的某几位决定的,取决于 Cache 硬件设计是虚拟地址索引,还是物理地址索引。 
然而,由于索引位一般设计为低地址位,通常在物理页的页内偏移以内,因此,不论是内存虚拟或者物理地址,都可以拿来判断两个内存地址,是否在同一个 Cache Line 里。

Cache Line 的大小和处理器硬件架构有关。在 Linux 上,通过 getconf 就可以拿到 CPU 的 Cache Line 的大小,

$ getconf.exe -a | grep CACHE
LEVEL1_ICACHE_SIZE                  32768
LEVEL1_ICACHE_ASSOC                 8
LEVEL1_ICACHE_LINESIZE              64
LEVEL1_DCACHE_SIZE                  32768
LEVEL1_DCACHE_ASSOC                 8
LEVEL1_DCACHE_LINESIZE              64
LEVEL2_CACHE_SIZE                   262144
LEVEL2_CACHE_ASSOC                  4
LEVEL2_CACHE_LINESIZE               64
LEVEL3_CACHE_SIZE                   12582912
LEVEL3_CACHE_ASSOC                  16
LEVEL3_CACHE_LINESIZE               64
LEVEL4_CACHE_SIZE                   0
LEVEL4_CACHE_ASSOC                  0
LEVEL4_CACHE_LINESIZE               0

2.5 Cache 的结构

前面 Linux getconf 命令的输出,除了 *_LINESIZE 指示了系统的 Cache Line 的大小是 64 字节外,还给出了 Cache 类别,大小。 
其中 *_ASSOC 则指示了该 Cache 是几路关联 (Way Associative) 的。

下图很好的说明了 Cache 在 CPU 里的真正的组织结构,

一个主存的物理或者虚拟地址,可以被分成三部分:高地址位当作 Cache 的 Tag,用来比较选中多路 (Way) Cache 中的某一路 (Way),而低地址位可以做 Index,用来选中某一个 Cache Set。 
在某些架构上,最低的地址位,Block Offset 可以选中在某个 Cache Line 中的某一部份。

因此,Cache Line 的命中,完全依靠地址里的 Tag 和 Index 就可以做到。关于 Cache 结构里的 Way,Set,Tag 的概念,请参考相关文档或者资料。这里就不再赘述。

2.6 Cache 一致性

如前所述,在 SMP 系统里,每个 CPU 都有自己本地的 Cache。因此,同一个变量,或者同一行 Cache Line,有在多个处理器的本地 Cache 里存在多份拷贝的可能性,因此就存在数据一致性问题。 
通常,处理器都实现了 Cache 一致性 (Cache Coherence)协议。如历史上 x86 曾实现了 MESI 协议以及 MESIF 协议。

假设两个处理器 A 和 B, 都在各自本地 Cache Line 里有同一个变量的拷贝时,此时该 Cache Line 处于 Shared 状态。当处理器 A 在本地修改了变量,除去把本地变量所属的 Cache Line 置为 Modified 状态以外, 
还必须在另一个处理器 B 读同一个变量前,对该变量所在的 B 处理器本地 Cache Line 发起 Invaidate 操作,标记 B 处理器的那条 Cache Line 为 Invalidate 状态。 
随后,若处理器 B 在对变量做读写操作时,如果遇到这个标记为 Invalidate 的状态的 Cache Line,即会引发 Cache Miss, 
从而将内存中最新的数据拷贝到 Cache Line 里,然后处理器 B 再对此 Cache Line 对变量做读写操作。

本文中的 Cache Line 伪共享场景,就基于上述场景来讲解,关于 Cache 一致性协议更多的细节,请参考相关文档。

2.7 Cache Line 伪共享

Cache Line 伪共享问题,就是由多个 CPU 上的多个线程同时修改自己的变量引发的。这些变量表面上是不同的变量,但是实际上却存储在同一条 Cache Line 里。 
在这种情况下,由于 Cache 一致性协议,两个处理器都存储有相同的 Cache Line 拷贝的前提下,本地 CPU 变量的修改会导致本地 Cache Line 变成 Modified 状态,然后在其它共享此 Cache Line 的 CPU 上, 
引发 Cache Line 的 Invaidate 操作,导致 Cache Line 变为 Invalidate 状态,从而使 Cache Line 再次被访问时,发生本地 Cache Miss,从而伤害到应用的性能。 
在此场景下,多个线程在不同的 CPU 上高频反复访问这种 Cache Line 伪共享的变量,则会因 Cache 颠簸引发严重的性能问题。

下图即为两个线程间的 Cache Line 伪共享问题的示意图,

CPU Cache Line伪共享问题的总结和分析相关推荐

  1. CPU Cache Line:CPU缓存行/缓存块

    <CPU Cache Line伪共享问题的总结和分析> 以下文章来源于小林coding ,作者小林coding Table of Contents CPU Cache 有多快? CPU C ...

  2. 7个示例科普CPU Cache line

    CPU cache一直是理解计算机体系架构的重要知识点,也是并发编程设计中的技术难点,而且相关参考资料如同过江之鲫,浩瀚繁星,阅之如临深渊,味同嚼蜡,三言两语难以入门.正好网上有人推荐了微软大牛Igo ...

  3. 深入理解CPU cache:组织、一致性(同步)、编程

    <CPU Cache Line:CPU缓存行/缓存块> <CPU Cache Line伪共享问题的总结和分析> <内存管理:Linux Memory Management ...

  4. CPU Cache下的伪共享和缓存行

    本文转载自https://blog.csdn.net/karamos/article/details/80126704 认识CPU Cache CPU Cache概述 随着CPU的频率不断提升,而内存 ...

  5. 一篇对伪共享、缓存行填充和CPU缓存讲的很透彻的文章

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

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

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

  7. CPU Cache与高性能编程

    目录 认识CPU Cache CPU Cache概述 Cache Line伪共享及解决方案 Cache Line伪共享分析 Cache Line伪共享处理方案 Padding 方式 Contended ...

  8. Linux内存管理:ARM64体系结构与编程之cache(3):cache一致性协议(MESI、MOESI)、cache伪共享

    目录 为什么系统软件人员要深入了解cache? cache一致性协议 神马是MESI协议? MESI的操作 MESI状态图 演示:初始化状态为I的cache line 当本地CPU的缓存行状态为I时, ...

  9. 从CPU cache一致性的角度看Linux spinlock的不可伸缩性(non-scalable)

    凌晨一点半的深圳雨夜: 豪雨当夜惊起有人赏,笑叹落花无声空飘零. 喜欢这种豪雨,让人兴奋.惊起作文以呜呼之感叹! 引用上一篇文章: 优化多核CPU的TCP新建连接性能–重排spinlock:https ...

最新文章

  1. Linux系统的安装(自动引导安装、网络安装、分区选择)
  2. .net ajax批量删除,asp.net 全部选中与取消操作,选中后的删除(ajax)实现无刷新效果...
  3. vCenter Converter Standalone使用文档
  4. ThreadLocal与Synchronized的用法
  5. python中range 函数_pythonrange,range函数的用法
  6. AOP 详解 、AOP 中通知类型 、AOP 两种实现方式(Schema-base 和 AspectJ)
  7. iis7 下php 环境配置文件,IIS7.X配置PHP运行环境小结_php
  8. Robomaster视觉教程(二)Win10+VS201x+Opencv3.4.x环境搭建
  9. Could not find method jackOptions() for arguments
  10. (python)域名查询服务(whois)程序+检查5位以内域名到期时间邮件报警抢注域名
  11. IP地址的定义及分类
  12. 百度地图-根据经纬度定位示例-百度地图单点标注(整理)
  13. GEE-Python遥感大数据分析、管理与可视化实践技术
  14. 三种古典密码的认识(置换密码,代换密码和轮换密码)
  15. 【ICPC-369】uva 12096 The SetStack Computer
  16. Office 2016 VOL版安装文件
  17. 2022 极术通讯-从CPU、DSA到软硬件融合
  18. Java很傻,但是IDE很聪明,Intellij IDEA 是一款好产品
  19. 编写河北大学官网界面
  20. 【稳定性day3】蘑菇街的运维体系 - 如何撑住双十一

热门文章

  1. ASP.NET Core默认注入方式下如何注入多个实现(多种方式)
  2. rman copy相关
  3. 掐头法和去尾法记音标
  4. 【转】自学成才秘籍!机器学习深度学习经典资料汇总
  5. 配置文件的读取添加webconfig
  6. Spring -- 入门,装备集合,自动装配,分散装配,自定义编辑器
  7. Oracle的dbms_jobs 自动计划
  8. postgreSQL源码分析——索引的建立与使用——GIST索引(3)
  9. 10-4-文章评论管理
  10. linux修改ip dhcp,Linux下在静态IP与动态DHCP之间切换的脚本