多层次的cache结构解决了CPU和DRAM之间处理速度不一致的问题,在Intel体系架构下,CPU核心和主存DRAM之间有着三层的cache。其中一层缓存L1和二层缓存L2在CPU核心(core)中,第三层在核外。一般每个核心都有一个私有的L1级和L2级Cache,同一个物理CPU上的多个核心共享一个L3级缓存,这样的设计是出于提高内存访问性能的考虑。但是这样就有一个问题了,每个核心之间的私有L1,L2级缓存之间需要同步啊。比如,核心1上的线程A对一个共享变量global_counter进行了加1操作,这个被写入的新值存到核心1的L1缓存里了;此时另一个核心2上的线程B要读global_counter了,但是核心2的L1缓存里的global_counter的值还是旧值,最新被写入的值现在还在核心1上。这就需要CPU有一个模块来保证,同一个内存的数据在同一时刻对任何对其可见的核心看来,数据是一致的,由第二章缓存图知道,这种专门的组件就是缓存控制器(Cbox,Bbox)。

缓存一致性 - MESI:

  处理器上有一套完整的协议,来保证Cache一致性。比较经典的Cache一致性协议当属MESI协议,奔腾处理器有使用它,很多其他的处理器都是使用它的变种。单核Cache中每个Cache line有2个标志:dirty和valid标志,它们很好的描述了Cache和Memory(内存)之间的数据关系(数据是否有效,数据是否被修改),而在多核处理器中,多个核会共享一些数据,MESI协议就包含了描述共享的状态。

  在MESI协议中,每个Cache line有4个状态,可用2个bit表示,它们分别是:

  M(Modified)和E(Exclusive)状态的Cache line,数据是独有的,不同点在于M状态的数据是dirty的(和内存的不一致)。

  E状态的数据是clean的(和内存的一致)。

  S(Shared)状态的Cache line,数据和其他Core的Cache共享。只有clean的数据才能被多个Cache共享。

  I(Invalid)表示这个Cache line无效。

在MESI协议中,每个Cache的Cache控制器不仅知道自己的读写操作,而且也监听(snoop)其它Cache的读写操作。每个Cache line所处的状态根据本核和其它核的读写操作在4个状态间进行迁移。

详细了解参考 : Cache一致性协议之MESI

Cache 类型:

Intel体系架构中,Cache 类型一共有 6 种:

Strong Uncacheable (UC):

  这种 cache 类型的 memory,任何读写操作都不经过 cache。一般是 memory-map 的 IO 地址可以使用这种类型。一般的 ram 强烈推荐不使用这种 cache,否则效率会非常低。

Uncacheable (UC-):

  特性与 UC(Strong uncacheable) 相同,唯一不同的是,这种类型的 memory,可以通过修改 MTRR 来把它改变成 WC

Write Combining (WC):

  这种类型的 cache,特性与 UC 相似,不同的地方是它可以被 speculative read(什么叫 speculative read?)每次 write 都可能被 delay,write 的内容会 buffer 到一个叫 “write combining buffer” 的地方。可以通过 对 MTRR 编程来设置 WC,也可以通过设置 PAT 来设置 WC(pat 是什么?)

Write – through (WT):

  这个很好理解,每次 write,都要 write 到 memory,同时 write 到对应的 cache(if write hits)。WT 方式保证了 cache 与 memory 是一致的。

Write – back (WB):

  这种类型的 memory,read 和 write,都跟一般的 cache 一样。只是 write 的时候,当写到了 cache 中,不会立即 write 到 memory 里(这个就跟 WT 不一样了)。CPU 会等到适当的时候再 write 到 memory 里—比如当 cache 满了。 这种类型是效率最高的类型,

Write-protected (WP):

  Read 跟 wb 一样,但每次 write,都会引起 cache invalidate

详细了解参考 :Cache学习

标记cache类型 - MTRR 和 PAT:

  MTRR (Memory Type Range Register)

  MTRR提供了这样一个机制:让不同范围的物理地址空间,具有不同的 cache 方法(UC,UC-,WC,WB,WT,WP 之类的)。MTRR 允许定义最多 96 个物理内存范围,通过 MSR 来指定不同范围的 MTRR 具有哪些 cache 方法。

  注意,在 variable-range 的 MTRR 中,是有对齐原则的:最小的范围是 4K,base 地址也至少是 4KB 对齐。如果范围大于 4K,那么范围必须是 2 的 N 次方(N 大于 12),base 地址对齐也必须是 2 的 N 次方。

对于 MTRR 的使用,有如下的一些规则:

1.) 如果 MTRR 没有被 enable(MSR IA32_MTRR_DEF_TYPE 中的 E flag 被 clear),那么所有的内存访问都使用 UC 类型。

2.) 如果 MTRR 被 enable 了:

  访问的地址在 0-1M 之间的话,并且 fix-ranges MTRR 是 enable 的,那么就使用 fix-range 的 MTRR 指定的 cache type。

  访问的地址在 1M 以上,那么就通过 variable-ranges MTRR 指定的 type 来决定:

     如果只有一个 variable-range MTRR 包含了这个地址,那么就使用该 MTRR 的 type;

     如果有一个以上 variable-range MTRR 包含了这个地址,并且这些 MTRR 的 type 都一样,那也使用这个 type;

     如果有一个以上 variable-range MTRR 包含了这个地址,并且其中一个 MRTT 的 type 是 UC,那就使用 UC;

     如果有一个以上 variable-range MTRR 包含了这个地址,并且 type 是 WT 和 WB,那么就使用 WT(WT 优先);

      如果以上规则都没满足,那么这块地址的访问的 cache type 是 undefine;

  3. ) 如果访问的地址没有 fix 或者 variable range 的 MTRR match 到,那么就使用系统默认的 cache type。

  MTRR 初始化: 在系统 hardware reset 时,CPU 会自动清除 variable-ranged MTRR 的 flag,并且会清除掉 MSR IA32_MTRR_DEF_TYPE 的 E 标志(表示 disable 所有的 MTRR). 在初始化 MTRR 之前,软件(bios 或者 OS)必须初始化所有的 fix ranged 和 variable ranged MTRR 为 0。然后软件再根据系统需求的实际情况去设置各个 MTRR。

  PAT (Page Attribute Table)

  MTRR 是基于物理地址空间来决定某块物理地址具有什么样子的 cache 属性。而 PAT 是对 MTRR 的补充,PAT 允许 CPU 基于线性地址来决定某个 page(线性地址页)具有什么样子的 cache 属性。PAT 是在页表项或者页目录项里指定的,并且 PAT 要与页表项或者页目录项里的 PCD 和 PWT 这两个 bit 一起来决定某个 page 具有什么样子的 cache 属性(UC,UC-,WB,WT,WC)。

  这些 cache 属性在 PAT 概念里的编码如下:可以通过 CPUID(EAX=1)来判断当前 CPU 是否支持 PAT。软件可以通过编程 MSR IA32_PAT(277H) 来设置 PAT 的相关属性。注意,只要是支持 PAT 的 CPU,PAT 就一定是打开的,也就是说,CPU 没有 control bit 可以控制 PAT 的开和关。那么,系统怎样来指定某个页具有什么样子的 cache 属性呢?页表中的 PAT,PCD,PWT 占 3 个 bit,这 3 个 bit 组合起来,可以索引到 MSR IA32_PAT(277H) 的某个 PA,这个 PA 的值,也就是那 5 种 cache 的 encoding 值。

  或许你有这样一个疑问:既然 PAT 是基于线性地址的,那么是否存在这样的情况:当一个物理页表被 MMU 映射到了不同的两个 page,并且这两个 page entry 的 pat 属性都是不一样的,那怎么办? 这个问题,从 intel 的角度来看,是 undefine 的。即 INTEL 不建议 OS 这样做,如果非要这样做,导致的后果 unknow,也就是后果自负。

Cache地址映射:

  cache 是体系结构中很重要的一个设计,也是有关存储体系中的一个重要环节,考虑到现实的应用中,由于开发了虚拟地址这个概念,即每个进程都可以拥有一个完整的虚拟地址空间,这样,CPU 在执行两道不同的进程,而进程的指令访问都是基于虚拟地址的,因此,可能出现的情况是:进程 A 在被执行一段时间后,由于进程调度,被切换出去,需要执行进程 B,而进程 A 的 PCA(进程 A 的取指地址指针)所指向的一段代码正在 cache 中,而进程 B 的 PCB,由于是虚拟地址概念,有可能 PCB=PCA(经过虚实地址转换后,物理 PCB 绝对不会等于物理 PCA),如果在 cache 中利用 PCB 去访问 PCA,则会导致 cache hit,但这个时候 cache hit 其实是错误的,因为 cache 中存放的是进程 A 的指令。 

  Cache到物理地址的映射按照工作原理来分有physical index physical tagged, virtual index virtual tagged, physical index virtual tagged等几种分法:

  Physical index physical tagged是一种最容易理解的操作方式,cache针对物理地址进行操作,简单粗暴,而且不会有歧义。但是这种方式的缺陷也很明显,在多进程操作系统中,每个进程拥有自己独立的地址空间,指令和代码都是以虚拟地址的方式存在,cpu发出的memory access的指令都是以虚拟地址的方式发出,这样的话,对于每一个memory access的操作,都要先等待MMU将虚拟地址翻译为物理地址,这是一种串行的方式,效率较低。

  Virtual index virtual tagged是纯粹用虚拟地址来寻址,这种方式带来了更多的问题,每一行数据在原有tag的基础上都要将进程标识加上以区分多个进程之间的相同地址,而在处理共享内存时也比较麻烦,共享内存在不同的进程中的虚拟地址不相同,如何同步是个问题。 
  现在比较多的是采用virtual index physical tagged的方式,virtual index的含义是当cpu发出一个地址请求之后,低位地址去和cache中的index匹配, physical tagged是指虚拟地址的高位地址去和mmu中的页表匹配以拿到物理地址(index和取物理地址这两个过程是并行的),然后用从mmu中取到的物理地址作为tag(或者tag的一部分)去和cache line的tag位匹配,这样既保证了同一地址在cache中的唯一性(有个例外,cache alias)又能将mmu和cache并行工作,提高了效率。

详细了解参考 :Cache浅析

  

Intel x86_64 Architecture Background 3的更多相关文章

  1. Intel x86_64 Architecture Background 1

    首先讲一下什么是Intel x86,x86是指intel的开发的一种32位指令集,从386开始时代开始的一直沿用至今,是一种cisc指令集.x84_64是x86 CPU开始迈向64位的时候,有2选择: ...

  2. Intel x86_64 Architecture Background 2

    这里是在学习Intel x86_64体系架构时学习到的一些概念,记录下来以供日后参考.如果有错的地方,欢迎指正! CPU上下文切换(context switch): 这个概念第一次听到对我来说是完全陌 ...

  3. Atlas 安装报错 package Atlas-2.2.1-1.x86_64 is intended for a x86_64 architecture

    安装atlas 报错: package Atlas-2.2.1-1.x86_64 is intended for a x86_64 architecture 百度了好久没找到相关信息,最后看见官网文档 ...

  4. InfiniBand 与Intel Omni-Path Architecture

    Intel Omni-Path Architecture (OPA) 是一种与InfiniBand相似的网络架构 可以用来避免以下PCI总线一些缺陷: 1.由于采用了基于总线的共享传输模式,在PCI总 ...

  5. Intel Omin-Path Architecture 搭建调优与测试

    OPA在Centos上的搭建 1. 首先确认Omni-Path Host Fabric Interfaces (HFIs) # yum install –y pciutils # lspci -vv ...

  6. [中英对照]Introduction to DPDK: Architecture and Principles | DPDK概论: 体系结构与实现原理

    [中英对照]Introduction to DPDK: Architecture and Principles | DPDK概论: 体系结构与实现原理   Introduction to DPDK: ...

  7. Optimizing subroutine calls based on architecture level of called subroutine

    A technique is provided for generating stubs. A processing circuit receives a call to a called funct ...

  8. Intel MIC

    http://en.wikipedia.org/wiki/Intel_MIC Intel MIC From Wikipedia, the free encyclopedia     Intel Man ...

  9. Game Engine Architecture 4

    [Game Engine Architecture 4] 1.a model of multiple semi-independent flows of control simply matches ...

随机推荐

  1. IDEA报错: Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'spring.datasource.url' in value "${spring.datasource.url}"

    运行审核流模块: 在ActivitiServiceApplication模块日志报错: Error starting ApplicationContext. To display the auto-c ...

  2. Java:匿名类,匿名内部类

    本文内容: 内部类 匿名类 首发日期 :2018-03-25 内部类: 在一个类中定义另一个类,这样定义的类称为内部类.[包含内部类的类可以称为内部类的外部类] 如果想要通过一个类来使用另一个类,可以 ...

  3. 安装VisualSVN Server 报"Service 'VisualSVN Server' failed to start. Please check VisualSVN Server log in Event Viewer for more details"错误.原因是启动"VisualSVN Server"失败

    安装VisualSVN Server 报"Service 'VisualSVN Server' failed to start. Please check VisualSVN Server ...

  4. Django2.0.1开发框架搭建

    1.使用vs2017创建空白django项目 2.右键python环境的env---安装python包  升级django到2.0.1和setuptools到38.4.0版本,具体环境如下: 3.配置 ...

  5. 什么是ORM?为啥要是用ORM?

    了解orm,先了解以下概念: 什么是“持久化” 持久(Persistence),即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘).持久化的主要应用是将内存中的数据存储在关系型的数据库中 ...

  6. Unity3d自制字体

    这篇教学中会使用到BMFont 这个工具 准备好Unity5.3.2版本,其他版本会有异常 一.制作字体 下载链接: http://www.angelcode.com/products/bmfont/ ...

  7. CRM项目之stark组件(1)

    admin组件 admin组件的简单使用 Django 提供了基于 web 的管理工具. Django 自动管理工具是 django.contrib 的一部分.你可以在项目的 settings.py ...

  8. SALALchemy Session与scoped_session的源码分析

    我们发现Session与scoped_session都有一些方法: 但是scoped_session的源码里面没有设置这些方法让我们从源码里去窥探下源码在哪里设置了这些方法: Session里面的方法 ...

  9. LinkedList与ArrayList的区别

    我们都知道LinkedList和ArrayList相比: 1.LinkedList插入删除相对较快,而查询较慢: 2.ArrayList插入删除相对较慢,而查询很快(详细可查看从源码的角度分析List ...

  10. Spark远程调试参数

    Spark远程调试脚本: #调试Master,在master节点的spark-env.sh中添加SPARK_MASTER_OPTS变量 export SPARK_MASTER_OPTS="- ...