The art of multipropcessor programming 读书笔记-硬件基础2

干货满满张哈希 等级 542 0 0

本系列是 The art of multipropcessor programming 的读书笔记,在原版图书的基础上,结合 OpenJDK 11 以上的版本的代码进行理解和实现。并根据个人的查资料以及理解的经历,给各位想更深入理解的人分享一些个人的资料

硬件基础

处理器和线程(processors and threads)

多处理器(multiprocessor)包括多个硬件处理器,每个都能执行一个顺序程序。当讨论多处理器架构的时候,基本的时间单位是指令周期(cycle):即处理器提取和执行一条指令需要的时间。

线程是一个顺序程序,是一个软件抽象。上下文切换(context switch)指的是处理器可以执行一个线程一段时间之后去执行另一个线程。处理器可以因为各种原因撤销一个线程或者从调度中删除该线程:

  • 线程发出了一个内存请求,而该请求需要一段时间才能完成
  • 线程已经运行了足够长的时间,该让别的线程执行了。

当线程被从调度中删除时,他可能重新在另一个处理器上执行。

互连线(interconnect)

目前常见的三种服务器基本互联结构:

  • SMP(symmetric multiprocessing,对称多处理)
  • NUMA(nonuniform memory access,非一致内存访问)

SMP 指多个 CPU 对称工作,无主次或从属关系。各 CPU 共享相同的物理内存。每个 CPU 访问内存中的任何地址所需时间是相同的,因此 SMP 也被称为一致存储器访问结构(即 UMA:Uniform Memory Access)。一般 SMP 架构中,CPU 和内存之间存在高速缓存。并且,处理器和主存都有用来负责发送和监听总线上广播信息的总线控制单元(bus controller)。整体结构如下图所示:

The art of multipropcessor programming 读书笔记-硬件基础2

这种结构最为容易实现,但是随着处理器的增多,总线并不能扩展导致总线终将过载。

在 NUMA 系统结构中,与 SMP 相反,一系列节点通过点对点网络互相连接,有点像一个小型的局域网,每个节点包含若干个处理器和本地内存。一个节点的本地存储对于其他节点也是可以访问的,当然,访问自己的本地内存要快于访问其他节点的内存。网络比总线复杂,需要更加复杂的协议,但是带来了扩展性。如下图所示: The art of multipropcessor programming 读书笔记-硬件基础2

从程序员的角度看,无论底层是 SMP 还是 NUMA,互连线都是有限的资源。写代码的时候,要考虑这一点避免使用过多的互联线资源。

内存(memory)

所有处理器共享内存,通常会被抽象成为一个很大的“”(words)数组,数组下标即为地址(address)。字长度和平台相关,现在多为 64 位,地址的最大长度也是这么长。64 位能表示的内存就已经很大了。

处理器访问内存的流程,简单概括包括:

  • 处理器通过给内存发送一个包含要读取的地址的消息,来获取内存上对应地址的值
  • 处理器通过给内存发送一个包含要写入的地址和值的消息数据写入后,内存回复一个确认消息

高速缓存(Cache)

缓存命中率

如果处理器一直直接从内存中读取,处理器直接访问内存消耗时间很长,可能需要几百个指令周期,这样效率会很低。一般需要引入若干个高速缓存(Cache):与处理器紧挨着的小型存储器,位于处理器和内存之间。

当需要读取一个地址的值时,访问高速缓存看是否存在:存在代表命中(hit),直接读取。不存在被称为缺失(miss)。同样的,如果需要写一个值到一个地址,这个地址在缓存中存在也就不需要访问内存了。

我们一般比较关心高速缓存中命中的请求比例,也就是缓存命中率

局部性与缓存行

大部分程序都表现出较高的局部性(locality):

  • 如果处理器读或写一个内存地址,那么它很可能很快还会读或写同一个地址
  • 如果处理器读或写一个内存地址,那么它很可能很快还会读或写附近的地址

针对局部性,高速缓存一般会一次操作不止一个字,而是一组临近的字,称为缓存行

多级高速缓存

现代处理器中一般不止一级缓存,而是多级缓存,从离处理器最近到最远分别是 L1 Cache,L2 Cache 和 L3 Cache:

  • L1 Cache 通常和处理器位于同一个芯片,离处理器最近,访问仅需要 1~3 个指令周期
  • L2 Cache 通常和处理器位于同一个芯片,处于边缓位置,访问需要通过更远的铜线,甚至更多的电路,从而增加了延时,一般在 8 ~ 11 个指令周期左右
  • L3 Cache L1/L2 为每个处理器私有的,这样导致对于很多相同的数据,也只能每个处理器独有的缓存各保存一份。所以需要考虑引入一个所有处理器共用的缓存,这就是 L3 缓存。L3 缓存的材质以及布线都和 L1/L2 不同,需要更长的时间访问,一般在 20 ~ 25 个指令周期左右

高速缓存内存有限,在同一时刻只有一部分内存单元被放置在高速缓存中,因此我们需要缓存替换策略。如果替换策略可以替换任何缓存行,则该高速缓存是全相联(fully associative)的。相反,如果只能替换一个特定的缓存行,他就是直接映射(direct mapped)的。如果取其折中,即允许使用一组大小为 k 的集合中任一缓存行来替换,则称为k 级组相联(k-way set associative)的。

一致性(coherence)

当一个处理器访问另一个处理器已经装载入高速缓存的主存地址的时候,就会发生共享(sharing,或者称为争用 contention)。需要考虑缓存一致性的问题,因为如果一个处理器要更新共享的缓存行,则另一个处理器的副本需要作废以免读取到过期的值。

MESI 缓存一致性协议,缓存行存在以下四种状态:

  • Modified:缓存行被修改,最终一定会被写回入主存,在此之前其他处理器不能再缓存这个缓存行。
  • Exclusive:缓存行还未被修改,但是其他的处理器不能将这个缓存行载入缓存
  • Shared:缓存行未被修改,其他处理器可以加载这个缓存行到缓存
  • Invalid:缓存行中没有有意义的数据

举例:假设处理器和主存由总线连接,如图所示:

The art of multipropcessor programming 读书笔记-硬件基础2

a) 处理器 A 从地址 a 读取数据,将数据存入他的高速缓存并置为 Exclusive

b) 处理器 B 从地址 a 读取数据,处理器 A 检测到地址冲突,响应缓存中 a 地址的数据,之后, 地址 a 的数据被 A 和 B 以 Shared 状态装入缓存

c) 处理器 B 对于 a 进行写操作,状态修改为 Modified,并广播提醒 A(所有其他已经将该数据装入缓存的处理器),状态置为 Invalid。

d) 随后 A 还需要访问 a,它会广播这个请求,B 将修改过的数据发到 A 和主存上,并且置两个副本状态为 Shared。

当处理器访问逻辑上不同的数据,但是这些数据恰好处于同一内存行,这种情况被称为错误共享(false sharing)

自旋(Spinning)

自旋即:某个处理器不断地检查内存中的某个字,等待另一个处理器改变它。

对于具有高速缓存的 SMP 或者 NUMA 系统结构,自旋仅消耗非常少的资源。根据上面我们对于 MESI 的介绍,第一次读取地址时,会产生一个高速缓存缺失,将该地址的内容加载到缓存块中。此后,只要数据没有改变,处理器仅从高速缓存读取数据,不需要占用互连线。当这个地址被修改时,处理器也会接收到 Invalid 并且重新请求这个数据并获取到修改。

为何 TTASLock 要优于 TASLock。

通过之前的分析,我们可以知道, TASLock 的每次 LOCKED.compareAndSet(this, false, true) 的时候,都会产生修改信号,占用互连线带宽。while 循环每次都执行,会产生大量修改信号。但是 TTASLock 的 LOCKED.get(this) 仅仅是一次本地自旋。所以 TTASLock 要比 TASLock 性能快得多。

收藏
评论区

相关推荐

安卓内存优化
Android内存 1.Android内存分配与回收机制 从Application Framework、Dalvik/Art、Linux内核三个部分来讲解关于Androd内存相关的知识 (1)Application Framework (https://imghelloworld.osscnbeijing.a
The art of multipropcessor programming 读书笔记-硬件基础1
本系列是 The art of multipropcessor programming 的读书笔记,在原版图书的基础上,结合 OpenJDK 11 以上的版本的代码进行理解和实现。并根据个人的查资料以及理解的经历,给各位想更深入理解的人分享一些个人的资料 硬件基础首先,我们无需掌握大量的底层计算机系统结构设计知识的细节,如果大家对于计算机系统结构非常感兴趣,
The art of multipropcessor programming 读书笔记-硬件基础2
本系列是 The art of multipropcessor programming 的读书笔记,在原版图书的基础上,结合 OpenJDK 11 以上的版本的代码进行理解和实现。并根据个人的查资料以及理解的经历,给各位想更深入理解的人分享一些个人的资料 硬件基础 处理器和线程(processors and threads)多处理器(multiprocess
MySQL索引基本概念笔记
好的文章: [http://database.51cto.com/art/200910/156685.htm](https://www.oschina.net/action/GoToLink?url=http%3A%2F%2Fdatabase.51cto.com%2Fart%2F200910%2F156685.htm) 官网:MySQL如何使用索引
ART运行时无缝替换Dalvik虚拟机的过程分析
  Android 4.4发布了一个ART运行时,准备用来替换掉之前一直使用的Dalvik虚拟机,希望籍此解决饱受诟病的性能问题。老罗不打算分析ART的实现原理,只是很有兴趣知道ART是如何无缝替换掉原来的Dalvik虚拟机的。毕竟在原来的系统中,大量的代码都是运行在Dalvik虚拟机里面的。开始觉得这个替换工作是挺复杂的,但是分析了相关代码之后,发现思路是
Apache Spark 3.0 GraphX编程指南
学习地址:[https://spark.apache.org/docs/latest/graphx-programming-guide.html](https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fspark.apache.org%2Fdocs%2Flatest%2Fgraphx-progr
Art of Unit Test (1)
### Glossary * SUT SYSTEM UNDER TEST * CUT CLASS UNDER TEST * MUT METHOD UNDER TEST ### Tests without Use of Stub You do not have to use stub when there are no external de
Codeforces Round #544 (Div. 3) C. Balanced Team [暴力剪枝]
You are a coach at your local university. There are n n students under your supervision, the programming skill of the i i -th student is a i ai . You have to create a team for a ne
Epigrams on Programming
### Alan J. Perlis ##### Yale University _This text has been published in SIGPLAN Notices Vol. 17, No. 9, September 1982, pages 7 - 13. I'm offering it here online until ACM stop
GUI programming with wxPython 之 XRC
一、概念 XRC(XML Resource)的设计来源于wxWidgets,它的想法很简单,就是将界面设计的工作从程序中独立出来。具体的做法是,创建单独的XML文件,负责界面设计,程序运行的时候载入,生成界面。这样做的好处是显而易见的。首先,将繁琐的外观设计代码从程序中去掉,程序更清晰易读。其次,XRC文件独立于程序,程序运行时才调用,因此可以随意更换外观
Golang查缺补漏(一)
### [Go语言高级编程(Advanced Go Programming)](https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fbooks.studygolang.com%2Fadvanced-go-programming-book%2F) [Go语言高级编程(Advanced G
Opa:透明化Web编程
**Announcing Opa: Making Web Programming Transparent** **Opa:透明化Web编程** **posted by hbbio on Thu 25th Aug 2011 22:14 UTC** **发表于:2011年8月26日 北京时间06:14** "Opa, a new opensour
Spring Aspect Oriented Programming
    本文是一篇Spring AOP的基础知识分析文章,其中不牵扯源码分析,只包含AOP中重要概念的讲解,分析,以及Spring AOP的用法。     Spring 从2.0版本引入了更加简单却强大的基于xml和AspectJ注解的面向切面的编程方式。在深入了解如何用Spring 进行面向切面的编程前,我们先了解AOP中的几个重要的基本概念,这几个概念
Springmvc 发送邮件功能
1、引入相关jar包 <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity</artifactId> <version>1.7</version> </dependency>