cache 订阅
Caché,是 一种后关系型数据库。能并发访问同一数据的数据库技术。 展开全文
Caché,是 一种后关系型数据库。能并发访问同一数据的数据库技术。
信息
定    义
一种后关系型数据库
作    用
对事务数据的实时查询
针对对象
为专业开发者而设计
中文名
Caché
Caché简介
什么是 Caché?。它独一无二地提供了三种整合的、能并发访问同一数据的数据库技术:成熟的对象访问方式,高性能的 SQL 访问方式以及丰富的多维访问。在对象数据、关系型数据以及多维数据视图之间不需要映射,这样就大大节省了开发和运行时间。
收起全文
精华内容
参与话题
问答
  • CPU | Cache 基本概念和基本原理

    千次阅读 2019-01-07 23:34:29
    一 、Cache的基本概念 Allocation  在cache中发现一个位置,并把新的cache数据存到这个位置的过程。这个处理过程可能包括 evicting(驱逐)cache中已存在的数据,从而为新的数据腾出空间。 Associativity 关联...

    一 、Cache的基本概念

    Allocation

             在cache中发现一个位置,并把新的cache数据存到这个位置的过程。这个处理过程可能包括 evicting(驱逐)cache中已存在的数据,从而为新的数据腾出空间。

    Associativity    关联方式

             指每个Set(集)里包含的line frames(行帧)数。也就是cache的way(路)数。

    Capacity miss   容量失效

             因为cache的容量限制,导致不能包括一个程序的整个working set(工作集),从而造成cache失效。这是三个cache失效原因(容量、强制、冲突)之一。

    Compulsory miss   强制失效

             有时称为首次引用失效。强制失效是一种肯定发生的一种失效,因为数据事先从没有使用过也就没有机会被cache。但有些情况也被称为强制失效,尽管它们不是第一被引用的数据,比如对非写定位的cache进行同一位置的重复写,以及对一个不被cache内存区域的存取。这是三个cache失效原因(容量、强制、冲突)之一。

    Conflict miss   冲突失效

             由于Associativity的限制导致的而非容量限制造成的cache失效。

    Clean   干净

             一个有效的cache行,它的内容没有被更高层内存或CPU修改写过,我们称这个cache行是“干净”的,显然相反状态是dirty(“脏”)

    Coherence   一致性

             如果读内存任意地址的数据返回的总是这个地址的数据最近的更新,我们说内存系统是一致的。存取指CPU和EDMA等的存取。

    Direct-mapped cache   直接映射cache

             直接映射cache映射低层内存的每个地址到cache的一个单一位置。这样低层内存的多个地址可能被映射到cache中的同一位置上。它相当于1-way set-associative cache。

    Dirty   脏

             对writeback回写cache,写到达多级存储结构的某一层,并更新这一层内容,但并不更新更低层的内存,这样,当一个cache行有效并包含更新后的数据,但却不更新下一更低层的内存,我们说这个cache是“脏”的,显然一个有效行的相反状态是“干净”。

    DMA   直接内存存取

             直接内存存取,通常一个DMA操作copy一个内存块从一个区域到另一个区域,或在外设和内存之间传输数据。对C64x DSP,DMA传输使用EDAM,这些DMA传输与程序执行是并行的。从cache一致性角度,EDMA的存取可以看成是另外一个并行处理器。

    Eviction   驱逐

             从cache移出一个line从而为新的数据腾出空间的过程我们成为Eviction。Eviction可以由用户发出的writeback-invalidate产生,被驱逐的line我们称为victim line。当victim line是dirty(“脏”)的时候,数据必须回写道下一级存储器中以维持内存的一致性。

    Execute packet   执行包

             在一个周期里并行执行的一个指令块,一个执行包可以包含1-8个指令。

    Fetch packet   取指包

             1个周期里存取的包含8条指令的指令块。显然一个取指包可以包含多个执行包,这样可能消耗多个周期。

    First-reference miss   首次引用失效

             是强制失效的一种形式。见强制失效。

    Fully-associative cache   全关联cache

             任何内存地址都可以被存储在cache的任何位置。这样的cache非常灵活,但通常硬件上不可实现。这种cache同直接映射cache和集关联cache形成鲜明对比,这两种cache在定位策略方面都有更多的限制,全关联cache只具有概念上的意义,当分析直接映射cache和集相关cache性能时对区分冲突失效和容量失效是有用的,全关联cache等价于这样一个集关联cache:它有line frame个way,仅有一个set。

    Higher-level memory   高层内存

    在多级内存系统中,距离CPU较近的内存称为高层内存。在C64x系统中,最高层内存通常是L1层CACHE,这一层的内存直接同CPU相连。较高层内存通常充当较低层内存的CACHE。

    Hit   命中

             当请求的内存地址的数据在cache中,我们说cache命中。命中的反义词是miss(失效)。Cache的命中使cpu的阻塞时间最短,因为从cache中取数据要比从原始位置取更快。在某一层内存的“失效”可能在较低层“命中”。

    Invalidate   无效

             将一个有效的行标记为无效行的过程。这相当于废弃了这一行的内容,但并不回写任何更新的数据。当与writeback组合时,会先将dirty数据更新到保存有这个地址的下一层内存。这通常用于维持内存的一致性。

    Least Recently Used(LRU)allocation

             对于set-associative和fully-associative cache,最近最少使用原则被用来一个set里选择一个line frame作为被驱逐的line,用来保存新的cache数据。

    Line   行

             是cache处理的最小单位块。显然一个cache行的尺寸要比CPU或高层内存存取的数据尺寸要大。例如尽管CPU可以进行单字节的存取,但如果发生一次读失效,则cache会将整个cache行的数据读入。

    Line frame   行帧

             Cache的一个位置,包含被cache的数据(一行)、一个关联的tag地址,这个行的状态信息状态信息包括这一行是否valid(有效)、dirty(脏)、LRU状态

    Line size   行尺寸

             一个行的尺寸,单位字节。

    Load through

             当CPU请求在第一级和第二级cache中都失效时,数据从外部内存获得,同时会存储在第一级和第二级内存中,如果一个cache,它保存数据并同时把数据送到高一层cache中,这种cache我们称之为load-through cache。相对于那种首先存储数据到低层然后第二步再把数据送到高层的cache,这种cache可以减少阻塞时间。

    Long-distance access   长距离存取

             CPU对不被cache内存区域数据的存取。显然,由于这种存取,不会影响cache的状态,但速度会比较慢。

    Lower-level memory   低层内存

             在多级内存系统中,距离CPU较远的内存称为低层内存。在C64x系统中,最低层内存包括L2以下的外部系统内存和内存映射的外设。

    LRU

             表示cache line的最近最少使用的状态信息。

    Memory ordering   内存访问排序

        定义在内存里以什么样的顺序看内存操作的结果,有时称为consistency(连贯性)。在分级结构的特定层的强内存访问排序表示在这一层上不可能以不同与程序序的顺序来观察内存存取的结果。松散内存访问排序允许内存分级体系结构以不同的顺序看内存操作的结果,注意强排序并不要求系统内存以程序序顺序操作,而仅仅是使操作的结果在其它请求者看来是与程序序一致的。

    Miss   失效

             当请求的内存地址的数据不在cache中,就是说发生了cache失效。一个cache失效,会引起阻塞请求者直到line frame被定位,数据从低层内存中获得为止。在某些情况下,比如CPU对L1D出现写失效,阻塞CPU是不必要的。Cache失效通常分为三种类型:强制失效、冲突失效和容量失效。

    Miss pipelining

             服务单一的cache失效的过程需要多个流水周期。如果对连续的失效处理进行流水线操作,显然就增加对失效处理的效率,降低了阻塞周期。

    Read allocate

    读失效cache是仅在发生读失效时才在cache中定位空间并把数据读入。写失效发生时不会产生数据读入到cache中,而是直接把写数据送到下一层cache中。

    Set

             Line frames的一个集合。直接映射的cache一个set包含一个line frameN-way set-associative cache每个set包含N个line frameFull-associative cache仅有一个set这个唯一的set包含所有的line frames

    Set-associative cache   集相关cache

             一个set-associative cache包含多个line frames用于cache低层内存。当为一个新的line数据定位一个空间时,选择哪个line frame是基于cache的定位策略的。C64x是基于LRU策略的。

    Snoop   侦测

             是lower-level memory(低层内存)查询higher-level memory(高层内存)以确定高层内存是否包含给定地址的数据的一种方法。Snoop的主要目的是通过允许低层内存请求高层内存进行数据更新来维持内存的一致性,snoop操作可以触发writeback(回写),或更普通的writeback-invalidate(回写并无效),触发writeback-invalidate(回写并无效)操作的snoop有时又称为snoop-invalidates。

    Tag   标签

             地址高位作为一个Tag存储在line中,在决定cache是否命中的时候,cache控制器会查询Tag。

    Thrash

             当存取操作引起cache性能遭受严重损坏,我们说thrash cache了。Thrash的原因可以有很多:一个可能是算法在短时间存取太多的数据而很少或根本不重复使用。也就是说working set太大。这样的算法将引起非常严重的容量失效。另一种情况是算法重复存取一小组不同地址的数据,这些数据映射到cache的相同set,这样就人为造成严的冲突失效。

    Touch

             对一个给定地址的存储器操作,我们称之为touch那个地址。Touch也可以指读数组元素或存储器地址的其它范围,定位它们在一个特定层cache的唯一目的。一个CPU中心环用作touch一个范围的内存是为了定位它到cache经常被引用作为一个touch环。Touching一个数组是软件控制预取数据的一种形式。

    Valid   有效

             当一个cache line保存从下一级内存取的数据,那么这个line frame就是有效的。无效状态发生在line frame不保存任何数据,或者说还没有被cache的数据,或先前cache的数据由于某种原因(内存一直性要求、程序要求等)被无效。有效的状态并不表示数据是否已经被修改(其实这有另外的状态来表示,即dirty或clean)。

    Victim

    从cache移出一个line从而为新的数据腾出空间的过程我们成为Eviction。Eviction可以由用户发出的writeback-invalidate产生,被驱逐的line我们称为victim。当victim line是dirty(“脏”)的时候,数据必须回写到下一级存储器中以维持内存的一致性。

    Victim Buffer

             保存victim直到它们背回写的特殊buffer。Victim lines被移到victim buffer,这样位新的数据腾出空间。

    Victim Writeback

             当victim line是dirty(“脏”)的时候,数据必须回写道下一级存储器中以维持内存的一致性。我们称这个过程为Victim Writeback

    Way

             对set-associative cache,每个set包含多个line frames。每个set包含的line frames数被称为way。以set做为行,line frame作为列,那么一列的line frames集合称为一个way。例如,一个4-way set-associative cache有4个way,每个set有4个关联的line frames,结果,对于一个可cache的内存地址,在cache中有4个可能的映射位置。

    Working Set

             程序或算法就是数据和指令代码的集合。在一个特定时间内被引用的这个集合我们称为working set(工作集)。通常,对于一个算法,我们需要考虑高层内存的工作集,对于整个程序我们需要考虑底层内存的工作集。

    Write allocate

             对于一个write allocate cache,如果发生写失效,就会定位一个空间并将失效的数据读入到cache中。空间定位按照LRU原则。一旦数据被读入到cache中,就进行写操作,对write allocate cache,仅更新当前层的内存,写的数据并不立刻送到下一层更低的内存。

    Writeback   回写

             将一个有效的但为脏的cache line回写到较低层内存的过程。回写后的这个cache line我们称之为clean(“干净”)。回写后的cache line状态依然为有效。

    Writeback cache   回写cache

             回写cache仅修改它自己的写命中的数据,它不会立刻更新下一级较低层内存的内容。数据在将来某时被回写,如:当这个cache line被驱逐时,或当低层内存向高层内存snoop这个地址时,当然也可以直接通过程序发送writeback命令。一个写命中,会引起对应的line被标记为dirty(“脏”),也就是说数据被更新了,但还没来得及更新低层内存。

    Writeback-invalidate   回写后使无效

    将一个有效的但为脏的cache line回写到较低层内存并置这些cache line为无效状态的过程。对C64x,对一组cache line进行Writeback-invalidate时,仅回写那些有效且为脏的cache lines,但却置那一组中的所有cache lines为无效。

    Write merging

             Write merging是组合多个独立的写操作成一个、位宽更大的写操作。显然这可以改善了内存系统的性能。例如,对C64x CPU,L1D写缓冲在某些情况下(如果它们是对同一个双字地址的写)能合并多个写。

    Write-through cache

             对于一个write-through cache,能把所有的写直接旁路到较低层内存。Cache中永远不包含更新的数据,这样做的结果是cache line永远不会是dirty。C64x的cache并不使用这种cache。

    二、Cache的基本原理

    1.寻址

    寻址及数据获取

    CPU对cache内存(这里指主存main memory,通常是DDR内存)的寻址类似,都需要被访问对象的地址,但寻址过程有点差别:

    CPU访问内存时,通常有两个动作:

    1.在EPN(Effective Page Number,上图中的Page Number部件)完成虚实地址转换,EPN经过Hash Function后在TLB中查找并得到RPN(Real Page Number),如果TLB Miss,RPN将通过慢速的页表查找来获得,最终完成虚拟地址到物理地址:页框(PageNumber)的转换;

    2.CLN(Cache Line Number,上图中的Line Number部件)查找合适的CacheBlock。

    ( TLB:TLB是Translation Lookaside Buffer的简称,可翻译为“地址转换后援缓冲器”,也可简称为“快表”。简单地说,TLB就是页表的Cache,其中存储了当前最可能被访问到的页表项,其内容是部分页表项的一个副本。

    参考文献:TLB的作用及工作过程,MMU和cache详解     TLB工作原理 )

    Cache Block的查找和Page Number的转换可以同步进行。

    在多处理器系统中,CLN索引得到的Cache Block中的数据可能不是有效的数据,因此还需要做进一步的比较:PA与Cache Block中的Address进行比较,如果结果相同且状态位匹配,表明Cache Hit,此时CPU通过Byte Select and Align部件获得所需的数据。如果Cache miss,则需要通过PA进一步索引在内存中获取数据

    Cache Block组成

    一个CacheBlock由地址、状态位和数据单元组成:

    ·Data:Cache Block中的数据,其长度为32或64,视CPU而定

    ·Status:Cache Block的状态,在大部分处理器中,该字段包含的是MESI、MOESI或者MESIF这些信息状态。某些处理器还包含一个L位,表示当前CacheBlock是否可用锁定,许多将Cache模拟成SRAM的处理器就是利用了这个L位。

    ·Real Address Tag:简称RAT,记录当前Cache中存放的数据和哪个地址相关,RAT中存放一部分物理地址信息,虽然CPU的物理地址可能有48位,但Cache中的地址位不需要这么多:

    CPU访问Cache使用的地址

    从Cache的角度来看,CPU的地址可用划分为:

    ·Real Address Tag:该字段以单个Cache中的RAT的字段长度相同,CPU使用地址中的RAT字段与Cache中对应的字段以及状态位进行联合比较,判断其访问数据是否命中

    ·Cache Line Index:和CLN的作用类似,CPU使用该字段在Cache中选择某一个Entry,如果是组相联(Set-Associative)方式组织的Cache,则选择某一组Entry.

    ·Bank:在Multi-Bank的系统中,CPU访问Cache时,不同Bank可用并发访问。

    ·Byte:Cache的端口位宽,目前大部分系统的Cache总线位宽为128位或64位

    Bank和Byte字段之和确定了单个Cache的Data字段长度,也就是通常说的CacheLine的长度,上图所示的CacheLine长度为26= 64 Bytes,目前大部分的CacheLine大小都为64Bytes,部分原因是因为DDR3SDRAM的一次BurstLine为8,一次Burst操作访问的数据大小为64Bytes

    展开全文
  • Cache简介(一)

    千次阅读 多人点赞 2018-01-23 18:44:21
    cache是干啥的? 在以前,CPU的主频比较慢,CPU和内存DRAM之间速度差别不是很大,存储数据或者指令还OK。但是CPU的飞速发展,CPU大哥速度已经飞快,而内存速度却跟不上大哥的步伐,所以大哥每次要读取或者写入内存...

    cache是干啥的?
    在以前,CPU的主频比较慢,CPU和内存DRAM之间速度差别不是很大,存储数据或者指令还OK。但是CPU的飞速发展,CPU大哥速度已经飞快,而内存速度却跟不上大哥的步伐,所以大哥每次要读取或者写入内存的时候都要等一等小弟,这个时候怎么办。cache就出来了,它类似与一个第三方。位于内存和CPU之间,速度非常快,所以CPU就把数据直接写入cache,然后CPU就可以干其他的了,剩下的事情就交给cache这个跑腿的,cache在合适的时机可以慢慢的把数据写入内存,也就是相当于解了CPU的燃眉之急。

    说白了,CPU要读数据首先是在cache中读,如果cache命中,也叫cache hit,CPU就可以极快的得到该地址处的值。如果cache miss 也就是没有命中,它就会通过总线在内存中去读,并把连续的一块单元加载到cache中,下次好使用。

    cache大多是SRAM(静态RAM),而内存大多是DRAM(动态随即存储)或者DDR(双倍动态随机存储)。
    cache容量一般非常小,因为价格贵,所以cache小是有道理的。一级cache一般就几KB,cache 的单位又分成cache line ,它是从内存单元加载到cache中的最小单元,一般为几个字大小,32字节或者64字节偏多。(因为时间局部性和空间局部性所以加载一次是以一个cache单元为最小单位)

    cache有两种模式(写回模式) 和 (写通模式)
    写回?写通? 回哪儿?通哪儿?
    当然是内存啊!!!

    简单介绍,写通也就是当CPU写入cache的时候,将数据再从cache 中写到内存中,这两个过程要都结束后,CPU的写入操作才算完成,也就是时刻保持内存和缓存的同步,这显然是很耗时的。

    什么是多级cache?
    一级cache 有指令cache和数据cache之分,这使整个系统更加高效,因为1Lcache 容量小,所以有了多级cache ,比如二级cache ,他容量大,但是速度就要比1Lcache 慢些,但比内存快多了。三级cache就更一些了。

    写回也就是当CPU写入cache中的时候,数据不会马上从cache中写到内存里面,而是等待时机成熟后写入(比如 发生cache miss,其他内存要占用该cache line的时候将该单元写回到内存中,或者一定周期后写入到内存中 ,或者其它地核需要读取该内存的时候)。

    内存写入cache的时候,如果cache 满了,则用一定的算法淘汰,比如随机淘汰还有或者LRU淘汰(用的少的被淘汰 常用)来替换掉原来的cache line 单元。

    下面说CPU如何高效查询cache,介绍三种模式

    1、全相连模式。
    也就是一定大小的内存块,可以映射到cache的任何一个cache line当中。
    很好理解,CPU查询cache line 却要花很多时间。不可取不可取。

    2、直接映射
    也就是内存按照cache line 的大小按照顺序映射到cache中,比如cache大小为1kb,每个cache line 为32字节。则共有32个cache line。CPU的内存空间为4G,
    内存 cache
    0x0~0x19 ————–> cache line 0
    0x20~0x39 ————–> cache line 1
    0x40~0x59 ————–> cache line 2
    ………..
    0x400~0x419 —————> cache line 0
    0x420~0x439 —————-> cache line 1

    也就是一个内存的地址有确定的cache line 号,所以查询速度很快,但是问题又来了,多个地址竞争同一个cache line ,而且程序具有空间局部性,可能或造成很多的cache没被使用,而有几个cache line却被频繁的换入换出。也不行。

    3、N WAY cache。(N路cache)

    这个方法综合了前面两种方法,也就是cache被分为N份,如4路cache ,cache总容量被四等分,比如1kb的cache,cache line大小为32字节,每一路cache有256字节容量,也就是8个单元的cache line。
    这怎么映射的呢?

    内存也是被分为cache line 的大小为一个映射单位。但是内存0x0~0x19就存在cache line 0,(四路简单粗暴的理解为有四个cache line 0、cache line 1…cache line 7 而这四个cache line 0又被合称为一个集合也就是cache set),0x0~0x19就可以随机选择存储在四路当中的某一路,这样就不用被频繁的换入换出,又索引的很快。
    实际上可以这样理解当N等于1的时候也就是直接映射,当N恰好等于 (内存大小/缓存大小) 时就相当于全相连模式。

    展开全文
  • cache结构与工作原理

    万次阅读 多人点赞 2017-11-23 14:44:55
    在经历N次的阅读之后,终于明白了cache的结构和工作原理。  首先,要想理解cache,先理解内存。内存的简单表示如下图,内存里面的内容的查找是根据地址来进行的,也就是说内存包含两点①地址②内存的内容(存的...

    在经历N次的阅读之后,终于明白了cache的结构和工作原理。

        首先,要想理解cache,先理解内存。内存的简单表示如下图,内存里面的内容的查找是根据地址来进行的,也就是说内存包含两点①地址②内存的内容(存的数据),根据地址来找数据。

                                                                                     图1   内存的结构

        上图的0000~0008是地址,A~I是存的数据,cpu根据地址去寻找数据。图中的一个字母代表一个字节的数据。

        我们都清楚,cache中的数据就是物理内存中的数据的子集,那么对于物理内存的一个数据,根据cache中可以放置这个数据位置的多少,可以分为三种:①如果cache中只有一个位置可以容纳这个数据,则为直接映射的cache;②如果cache中有多个地方可以放置这个数据,它就是组相联的cache;③如果cache中的任何地方都可以放置这个数据,那么它就是全相连的cache;如下图2所示:

                                                                            图2  cache的三种组成方式

        更详细的讲,cache的结构其实和内存的结构类似,也包含地址和内容,只是cache的内容除了存的数据(data)之外,还包含存的数据的物理内存的地址信息(tag),因为CPU发出的寻址信息都是针对物理内存发出的,所以cache中除了要保存数据信息之外,还要保存数据对应的地址,这样才能在cache中根据物理内存的地址信息查找物理内存中对应的数据。(当然为了加快寻找速度,cache中一般还包含一个有效位(valid),用来标记这个cache line是否保存着有效的数据)。一个tag和它对应的数据组成的一行称为一个cache line。如下图所示,下表中的一行就是一个cache line。

                                                                      图3   cache的基本结构

    具体的Data、Valid、Tag各有多大,在介绍了内存的地址划分之后再在下文中讲。

    知道了cache的结构之后,如何在cache中去寻找对应的数据呢?简单起见,我们先选择 直接映射的cache组成方式进行下文的分析

    首先对于一段物理内存(block),该物理内存上的每个字节的地址划分为以下几段:[3]

                                                                               图4   处理器物理内存地址的划分

    这样的话物理内存中的数据到cache的映射关系如下图5所示:

                                                                                    图5   cache的查找过程

        上图的映射原则就是:根据物理地址的中间三位(index字段)来定位当前数据应该在cache的哪一行,把物理地址的tag字段和该地址对应的内容放入对应的cache line的tag字段和data字段,并把相应的valid位置1。那么在之后进行cache寻找的时候就可以根据cache line的tag字段来辨认当前line中的数据是数据哪个block的。

        上图5中的地址00 000 00~11 111 11按照图4的原则进行地址划分:地址的最高两位为Tag字段;中间三位为index字段;最低两位为Block Offset 字段;由于Block Offset是两位,也就是一个block的大小是2²=4个字节的数据,也就是一个cache line的data字段包含4个字节的数据;index为3位,说明cache共包含2³=8个组(对于直接映射的cache,也称为8个行);很明显,cache的一个行中只能存储1 块(Block )=4字节的数据,但是按照图5的映射方式,会有2^(tag位数) = 2^2 = 4块的数映射到同一个行,此时通过Tag字段的比较来辨别是不是我们要取数据的地址,如果不是的话,也就是发生了cache的缺失。如图5的Block 0和Block 1的index字段都是000,按照上面的理论它们都应该映射到第 000=0行(这儿的行也就是组,因为图5是直接映射的cache),但是现在第0行的内容是K、L、M、N,也就是Block 1的内容,为什么呢?仔细看该cache line的tag=01,映射到第0行的块只有Block 1的tag字段=01,所以可以得知此时该cache line中存储的数据是Block 1的数据,此时如果CPU发出的访存请求是访问Block 0 的话,也就是发生了缺失。此时进一步定量分析的话,共有4个数据块竞争使用cache 第0行的位置,也就是说cache的命中率为25%。

        上面的过程总结起来就是:物理内存的索引字段(Index)选择cache 的行,通过对比物理内存和cache line的Tag来判断是否命中。块偏移字段(Block Offset)可以从cache line的数据块中选择期望数据。注意在这个过程中cache的index是不占空间的,它就类似于物理内存的地址,对于物理内存来说是通过地址去寻找数据,对于cache来说,是通过index来找到对应的cache line,或者更通俗的讲就是:cache line的地址对应的就是物理内存的index字段。

        此时该cache的容量计算如下:每一个cache line的数据字段占4个字节,共2³=8行,所以数据占据4×8=32个字节,一个cache line中tag字段和valid位占2+1=3bit,整个cache的tag+valid=3bit×8行=24bit=3Byte,通常情况下我们都是一cache中数据部分占的空间表示cache的容量,也就是32字节,但是实际上,它还额外多占用了3字节的存储空间[4]。

     

        图5的分析是针对直接映射的cache进行的,对于组相联或者全相连的cache的分析与之类似。如果是组相连的cache,每个组(set)里面包含多个行(line),通过内存地址的index字段来寻址组,确定组之后再根据tag来确定是否命中;对于全相连的cache,就不需要index字段了,因为全相连的cache相当于只有一个组的组相连cache。这是只需要根据要寻址的地址的tag来逐一与cache中的tag字段比较,如果有与之匹配的cache line,也就是cache hit了,如果遍历整个cache,也没有找到匹配的cache line,那就是cache miss了。

     

    注:为了叙述的简单性,省略了内存地址通过TLB的的虚实转换部分,由[1]可知,内存地址的Tag部分其实是需要先经过TLB的转化才能够去和cache line的tag部分去进行匹配的。

     

    参考:

    [1]Cache的工作原理

    [2]每个程序员都应该了解的 CPU 高速缓存

    [3]计算机体系结构:量化研究方法 Hennessy   P411

    [4]超标量处理器设计 姚永斌  P21

     

    展开全文
  • 深入理解Cache

    千次阅读 多人点赞 2018-07-13 14:53:14
    存储器是分层次的,离CPU越近的存储器,速度越快,每字节的成本越高,同时容量也因此越小。寄存器速度最快,离CPU最近,成本最高,所以个数容量有限,其次是高速缓存(缓存也是分级,有L1,L2等缓存),再次是主存...
    存储器是分层次的,离CPU越近的存储器,速度越快,每字节的成本越高,同时容量也因此越小。寄存器速度最快,离CPU最近,成本最高,所以个数容量有限,其次是高速缓存(缓存也是分级,有L1,L2等缓存),再次是主存(普通内存),再次是本地磁盘。
                         
         寄存器的速度最快,可以在一个时钟周期内访问,其次是高速缓存,可以在几个时钟周期内访问,普通内存可以在几十个或几百个时钟周期内访问。

        
              (注 本图来自Ulrich Drepper大牛的讲稿,如有侵权,通知即删)

        存储器分级,利用的是局部性原理。我们可以以经典的阅读书籍为例。我在读的书,捧在手里(寄存器),我最近频繁阅读的书,放在书桌上(缓存),随时取来读。当然书桌上只能放有限几本书。我更多的书在书架上(内存)。如果书架上没有的书,就去图书馆(磁盘)。我要读的书如果手里没有,那么去书桌上找,如果书桌上没有,去书架上找,如果书架上没有去图书馆去找。可以对应寄存器没有,则从缓存中取,缓存中没有,则从内存中取到缓存,如果内存中没有,则先从磁盘读入内存,再读入缓存,再读入寄存器。

        本系列的文章重点介绍缓存cache。了解如何获取cache的参数,了解缓存的组织结构,了解cache对程序的影响,了解如何利用cache提升性能。

         本文作为系列文章的第一篇,讲述的如何获取cache的组成结构和如何获取cache的参数。

        cache分成多个组,每个组分成多个行,linesize是cache的基本单位,从主存向cache迁移数据都是按照linesize为单位替换的。比如linesize为32Byte,那么迁移必须一次迁移32Byte到cache。 这个linesize比较容易理解,想想我们前面书的例子,我们从书架往书桌搬书必须以书为单位,肯定不能把书撕了以页为单位。书就是linesize。当然了现实生活中每本书页数不同,但是同个cache的linesize总是相同的。

        所谓8路组相连( 8-way set associative)的含义是指,每个组里面有8个行。
     
        我们知道,cache的容量要远远小于主存,主存和cache肯定不是一一对应的,那么主存中的地址和cache的映射关系是怎样的呢?

        拿到一个地址,首先是映射到一个组里面去。如何映射?取内存地址的中间几位来映射。

        举例来说,data cache: 32-KB, 8-way set associative, 64-byte line size

        Cache总大小为32KB,8路组相连(每组有8个line),每个line的大小linesize为64Byte,OK,我们可以很轻易的算出一共有32K/8/64=64 个组。

        对于32位的内存地址,每个line有2^6 = 64Byte,所以地址的【0,5】区分line中的那个字节。一共有64个组。我们取内存地址中间6为来hash查找地址属于那个组。即内存地址的【6,11】位来确定属于64组的哪一个组。组确定了之后,【12,31】的内存地址与组中8个line挨个比对,如果【12,31】为与某个line一致,并且这个line为有效,那么缓存命中。

        OK,cache分成三类,
        1 直接映射高速缓存,这个简单,即每个组只有一个line,选中组之后不需要和组中的每个line比对,       因为只有一个line。

        2 组相联高速缓存,这个就是我们前面介绍的cache。 S个组,每个组E个line。

       3 全相联高速缓存,这个简单,只有一个组,就是全相联。不用hash来确定组,直接挨个比对高位地址,来确定是否命中。可以想见这种方式不适合大的缓存。想想看,如果4M 的大缓存 linesize为32Byte,采用全相联的话,就意味着4*1024*1024/32 = 128K 个line挨个比较,来确定是否命中,这是多要命的事情。高速缓存立马成了低速缓存了。

       描述一个cache需要以下参数 :
        1 cache分级,L1 cache, L2 cache, L3 cache,级别越低,离cpu越近
        2  cache的容量
        3  cache的linesize
        4  cache 每组的行个数.
        组的个数完全可以根据上面的参数计算出来,所以没有列出来.
        Intel手册中用这样的句子来描述cache:
        8-MB L3 Cache, 16-way set associative, 64-byte line size 

        如何获取cache的参数呢,到了我们的老朋友cpuid指令,当eax为0x2的时候,cpuid指令获取到cache的参数. 下面给出代码:

       
    1. #include<stdio.h>
    2. #include<stdlib.h>

    3. int d_eax;
    4. int d_ebx;
    5. int d_ecx;
    6. int d_edx;

    7. int parse_cache()
    8. {
    9.  asm
    10.          (
    11.    "movl $2,%eax\n\t"
    12.    "cpuid\n\t"
    13.    "mov  %eax,d_eax\n\t"
    14.    "mov  %ebx,d_ebx\n\t"
    15.    "mov  %ecx,d_ecx\n\t"
    16.    "mov  %edx,d_edx\n\t"
    17.          );
    18. printf("d_eax : %x\nd_ebx : %x\nd_ecx : %x\nd_edx : %x\n",
    19.         d_eax,d_ebx,d_ecx,d_edx);
    20. return 0;
    21. }
    22. int main()
    23. {
    24. parse_cache();
    25. return 0;
    26. }

    1. root@libin:~/program/assembly/cache# ./test
    2. d_eax : 55035a01
    3. d_ebx : f0b2dd
    4. d_ecx : 0
    5. d_edx : 9ca212c
        我的电脑上运行结果如上图,查看intel的手册可知
    1. EAX
    2. (55h) Instruction TLB: 2-MB or 4-MB pages, fully associative, 7 entries
    3. (03h) Data TLB: 4-KB Pages, 4-way set associative, 64 entries
    4. (5Ah) Data TLB0: 2-MB or 4-MB pages, 4-way associative, 32 entries
    5. (01h) Instruction TLB: 4-KB Pages, 4-way set associative, 32 entries
    6. EBX:
    7. (F0h) 64-byte Prefetching
    8. (B2h) Instruction TLB: 4-KB pages, 4-way set associative, 64 entries
    9. (DDh) 3rd-level cache: 3-MB, 12-way set associative, 64-byte line size
    10. EDX:
    11. (09h) 1st-level Instruction Cache: 32-KB, 4-way set associative, 64-byte line size
    12. (CAh) Shared 2nd-level TLB: 4-KB pages, 4-way set associative, 512 entries
    13. (21h) 256KB L2 (MLC), 8-way set associative, 64-byte line size
    14. (2Ch) 1st-level data cache: 32-KB, 8-way set associative, 64-byte line size

    参考文献:
    1 Intel? Processor Identification andthe CPUID Instruction
    2 Professional Assembly Language  Richard Blum著
    3 深入理解计算机系统

        首先言明,本文严格意义上将不能算作原创,因为我写这些东西只不过是博客 Gallery of Processor Cache Effect的学习心得,不能将版权划到自己名下,毕竟咱不是喜欢45度角仰望天空的郭四姑娘。由于原文是英文版,而且作者用的是C++。原文提到的实验,我做了一部分,加深了对Cache的理解。英文比较好的兄弟就不必听我聒噪了,直接点链接看原文好了。

        OK,继续我们的探索之旅。深入理解cache(1)得到了我的PC的cache参数如下:
    L1 Cache :    32KB ,    8路组相连,linesize为 64Byte             64个组
    L2 Cache:256KB     8路组相连,linesize为 64Byte            512个组
    L3 Cache: 3MB       12路组相连,linesize为 64Byte         4096个组
    EAX(55h) Instruction TLB: 2-MB or 4-MB pages, fully associative, 7 entries(03h) Data TLB: 4-KB Pages, 4-way set associative, 64 entries(5Ah) Data TLB0: 2-MB or 4-MB pages, 4-way associative, 32 entries(01h) Instruction TLB: 4-KB Pages, 4-way set associative, 32 entriesEBX:(F0h) 64-byte Prefetching(B2h) Instruction TLB: 4-KB pages, 4-way set associative, 64 entries(DDh) 3rd-level cache: 3-MB, 12-way set associative, 64-byte line sizeEDX:(09h) 1st-level Instruction Cache: 32-KB, 4-way set associative, 64-byte line size(CAh) Shared 2nd-level TLB: 4-KB pages, 4-way set associative, 512 entries(21h) 256KB L2 (MLC), 8-way set associative, 64-byte line size(2Ch) 1st-level data cache: 32-KB, 8-way set associative, 64-byte line size、
           1 测试cache的linesize 
        代码看起来有点长,但是分成了3段。先看第一个测试,测试cache的linesize。

        我们知道,cache的迁移是以linesize为单位的,所以,用户纵然只访问一个int,PC需要从主存拷贝1条line 进入Cache,对于我的电脑来说,就是copy 64B。

        看下面的代码,测试linesize,如果K=1,遍历整个数组,如果K=16,只访问16倍数位置的值。依次类推。如果K=16,乘法的个数是K=1的时候1/16。我们可以推测,K=16的时候,程序执行时间是K=1的时候的1/16左右。是不是这样的。看下第一个测试用例的结果。
    1. int test_cache_linesize(int array[],int len,int K)
    2. {
    3.     int i;
    4.     for( i = 0;i<len;+= K)
    5.     {
    6.           array[i] *=3;
    7.     }
    8.     return 0;
    9. }

              当K = 1 ,2,4 ......16的时候,虽然计算乘法的次数相差很大,但是,代码执行的时间是相近的都是80ms附近,但是当K = 32,64的时候,随着计算乘法的次数减半,代码执行的时间也减半。

        原因在于,16 = (linesize)/sizeof(int)= 64/4,当K <16的时候,第一个int不命中,接下来的都命中的,乘法的个数虽然减半,但是从主存向Cache拷贝数据并没有减半。乘法消耗的指令周期要远低于从主存往cache里面copy数据,所以当K<16 的时候,既然从主存Cp数据到Cache的次数是相同的,那么总的执行时间差距不大就可以理解了。

        当K>16的时候,每次都需要去主存取新的line,所以步长K增大一倍,去主存copy数据到cache的次数就减少为原来的一半,所以运行时间也减少为 原来的1半。

        2 Cache的大小。
        我的PC 有三级Cache,容量分别是32K  256K ,3M .这些参数对程序有什么影响呢。

      下面的测试代码,执行的次数是一样的,都是64M次但是array的大小不一样。我们分别传入参数为1K,2K ,4K ,8K.....64MB 。在执行之前我们先分析下。

        目前,如果array的大小是多大,循环执行的次数是一样的。我们的1级Cache大小是32KB,也就是最多容纳8192个int。如果我们的数组大小就是8192个int,那么除了第一次执行需要将数据从 主存-->L3 Cache--->L2 Cache -->L1 Cache传上来,后面再次执行的时候,由于整个数组全在L1 Cache,L1 Cache命中,速度很快。当然如果数组大小小于8192个int,L1更能容纳的下。8192是个坎。数组大于8192个int,性能就会下降一点。

        如果我们的array大小大于L1 cache容量会怎样呢?看下我们的L2 Cache,大小256KB,即64K个int,换句话说,如果数组长度小于64K个int,也不赖,至少L2 Cache 容纳的下,虽然L1 Cache每写满32KB就需要将交换出去。换句话说,64K是个坎,数组大于64K个int,性能就会下降。

        L3Cache我就不说,毕竟我不是唐僧,一样的情况,对于我的3M 缓存,3M/4 = 768K 是个坎,如果数组大于768个int,那么性能又会下降。

        好了可以看下面的图了,和我们想的一样,
        当低于8192的时候,都是120ms 左右,
        [8192,64K ]的时候,都是200ms 左右
        [64K ,768K ]的时候,都是300ms左右
        大于768的时候,1200ms左右。
    1. int test_cache_capacity(int array[],int cap)
    2. {
    3.     int i;
    4.     int lenmod = cap -1;
    5.     int times = 64*SIZE_1MB;
    6.      for(= 0;i<times;i++)
    7.      {
    8.          array[(i*16) & (lenmod)]++;/*16 means linesize/sizeof(int) = 16*/
    9.      }
    10.      return 0;
    11. }


          第三部分我就不讲了,源代码给出大家可以自己在电脑上研究。不过第三部分要比较难懂,而且我前面提到的那篇讲的也不是很好懂。 

        下面是我的测试全代码
    /* http://igoro.com/archive/gallery-of-processor-cache-effects/ */

    #include<stdio.h>
    #include<stdlib.h> 
    #include<linux/types.h>
    #include<string.h>

    #define SIZE_1KB (1024)
    #define SIZE_1MB (1024*1024)

    #define NUMBER 64*SIZE_1MB 
    #define MILLION 1000000

    __u64 rdtsc()
    {
      __u32 hi;
        __u32 lo;
        
        __asm__ __volatile__
        (
         "rdtsc":"=a"(lo),"=d"(hi)
        );
        return (__u64)hi<<32|lo;
    }

    __u64 gettime()
    {
           struct timeval tv;
            gettimeofday(&tv,NULL);
            return ((__u64)(tv.tv_sec))*MILLION+tv.tv_usec;
    }

    int test_cache_linesize(int array[],int len,int K)
    {
     int i;
        for( i = 0;i<len;+= K)
        {
              array[i] *=3;
        }
        return 0;
    }

    int test_cache_capacity(int array[],int cap)
    {
        int i;
        int lenmod = cap -1;
        int times = 64*SIZE_1MB;
         for(= 0;i<times;i++)
         {
             array[(i*16) & (lenmod)]++;/*16 means linesize/sizeof(int) = 16*/
         }
         return 0;
    }

    int test_cache_associative(int array[],int size,int K)
    {
        int i;
         int cur =0;
         __u64 begin;
         __u64 end;
         begin =gettime();
         for( i = 0;i<SIZE_1MB;i++)
         {
             array[cur]++;
             cur += K;
             if(cur >= size)
             cur = 0;
         }
         end = gettime();
        
         printf("when size = %10d, K = %10d : test_cache_associative cost %14llu us\n",
         size,,end-begin);
         return 0;
    }
    int test_cache()
    {
        int *array = NULL;
        array = malloc(NUMBER*sizeof(int));
        __u64 begin ;
        __u64 end;
        int i;
        int K;
        int cap ;
        int size;
        if(array == NULL)
        {
             printf("malloc space for array failed \n");
             return -1;
        }
        
        for(= 0;i<NUMBER;i++)
        {
         array[i] = i;
        }
       
       printf("---------test cache linesize-------------------------------------------\n");
        for(= 1;< 64*1024;*= 2) 
        {
             begin = gettime();
             test_cache_linesize(array,NUMBER,K);
             end = gettime();
             printf("when K = %10d,multiply %10d times,cost %14llu us,average cost %llu us\n",
             K,NUMBER/K,end - begin,(end-begin)/(NUMBER/K));
             if(== 1)
             {
                         begin = gettime();
                         test_cache_linesize(array,NUMBER,K);
                         end = gettime();
                         printf("when K = %10d,multiply %10d times,cost %14llu us,average cost %llu us\n",
                                 K,NUMBER/K,end - begin,(end-begin)/(NUMBER/K));
             }
             
         } 
        
        printf("-----------test cache capacity-------------------------------------------\n");
        for(cap = 1024;cap <= NUMBER;cap *= 2)
        {
             begin =gettime();
             test_cache_capacity(array,cap);
             end = gettime();
             printf("when cap = %10d,cost %14llu us\n",
             cap,end-begin);
             if(cap == 2*SIZE_1MB/sizeof(int))
             {
                  begin =gettime();
                  test_cache_capacity(array,3*SIZE_1MB/sizeof(int));
                  end = gettime();
                  printf("when cap = %10d,cost %14llu us\n",
                           3*SIZE_1MB/sizeof(int),end-begin);
             }
                    
        }
        printf("-----------test cache associative ---------------------------------------\n");

        for(size = 1*SIZE_1MB;size >= 4*SIZE_1KB;size /= 2)
        { 
             for(= 64;<= 576 ;+= 64) 
             {
                  test_cache_associative(array,size,K); 
             } 
        }
        free(array);
        return 0;
            
    }

    int main()
    {
         test_cache();
         return 0;
    }
    出自:http://blog.chinaunix.net/uid-24774106-id-2777989.html
    展开全文
  • cache(缓存)浅析

    万次阅读 多人点赞 2018-04-24 10:21:40
    cache 缓存
  • cache是什么文件?

    千次阅读 2017-09-12 11:16:46
    通常人们所说的Cache就是指缓存SRAM。 SRAM叫静态内存,“静态”指的是当我们将一笔数据写入SRAM后,除非重新写入新数据或关闭电源,否则写入的数据保持不变。 由于CPU的速度比内存和硬盘的速度要快得多,所以在存取...
  • [linux]Cache过高解决办法

    千次阅读 2018-07-06 15:02:11
    在Linux系统中,我们经常用free命令来查看系统内存的使用状态。在一个RHEL6的系统上,free命令的显示内容大概是这样一个状态:这里的默认显示单位是kb,我的服务器是128G内存,所以数字显得比较大。...
  • Cache简介

    千次阅读 2015-12-14 20:45:54
    Cache  Cache一词来源于法语,其原意是“藏匿处,隐秘的地方”,而自从被应用于计算机科学之后,就已经成为了英语中的一个计算机体系结构专有名词。  Sun Microsystems的前首席科学家Billy Joy,作为BSD unix,...
  • cache介绍

    2019-06-06 14:56:00
    原帖地址: http://www.wowotech.net/memory_management/458.html?from=timeline今天探究的主题是cache。... 为什么需要cache memory 在思考cache是什么之前我们首先先来思考第一个问题:我们的程...
  • Cache 的基本概念与工作原理

    千次阅读 2019-05-06 13:09:39
    cache 英 [kæʃ] 美 [kæʃ] n. 隐藏物(如武器);(秘密)贮存物;高速缓冲存储器 v. 匿藏,隐藏(尤指武器);把(数据)存入高速缓冲存储器;高速缓存 1.背景知识 随着 CPU 技术的飞速发展,常用的处理器飞奔在越来越...
  • 计算机缓存Cache以及Cache Line详解

    万次阅读 多人点赞 2018-06-06 10:56:36
    1.计算机存储体系简介 存储器是分层次的,离CPU越近的存储器,速度越快,每字节的成本越高,同时容量也因此越小。寄存器速度最快,离CPU最近,成本最高,所以个数容量有限,其次是高速缓存(缓存也是分级,有L1,...
  • cache

    千次阅读 2018-11-01 17:39:40
    CPU,内存和cache之间的关系 和 cache的操作 https://blog.csdn.net/vanbreaker/article/details/7470830 cache和内存的关联方式(associativity) https://blog.csdn.net/vanbreaker/article/details/7475093 ...
  • 静态字段缓存基本使用 /// <summary> /// 1 客户端缓存-CDN缓存-反向代理缓存-本地缓存 /// 2 本地缓存原理和手写基础实现 /// 3 缓存更新/过期/多线程测试 /// 4 缓存类库封装和缓存应用总结 ...
  • Cache

    千次阅读 2010-11-22 10:48:00
    Cache的工作原理 Cache的工作原理是基于程序访问的局部性。 对大量典型程序运行情况的分析结果表明,在一个较短的时间间隔内,由程序产生的地址往往集中在存储器逻辑地址空间的很小范围内。指令地址的分布本来就是...
  • jetcache官网教程

    万次阅读 多人点赞 2018-05-09 22:58:57
    jetcache简介JetCache是一个基于Java的缓存系统封装,提供统一的API和注解来简化缓存的使用。 JetCache提供了比SpringCache更加强大的注解,可以原生的支持TTL、两级缓存、分布式自动刷新,还提供了Cache接口用于...
  • namespace Coldairarrow.Util { /// <summary>... public enum CacheType { /// <summary> /// 使用内存缓存(不支持分布式) /// </summary> Memory, /// <summary>
  • Cache

    千次阅读 2016-09-01 23:14:04
    Cache失效的原因 强制性失效 (Compulsory miss): 当第一次访问一个块时,该块不在 Cache中, 需从下一级存储中调入 Cache, 这就是强制性失效。这种失效也称为冷启动失效,或首次访问失效。(增加块大小,预取) 容量...
  • Django缓存Cache详解

    万次阅读 多人点赞 2018-07-30 12:48:17
    缓存(Cache)对于创建一个高性能的网站和提升用户体验来说是非常重要的,然而对我们这种只用得起拼多多的码农而言最重要的是学会如何使用缓存。今天我们就来看看缓存Cache应用场景及工作原理吧,并详细介绍如何在...
  • Guava Cache 使用学习

    万次阅读 2018-02-05 20:01:51
    缓存框架Guava Cache部分源码分析 概述 缓存是日常开发中经常应用到的一种技术手段,合理的利用缓存可以极大的改善应用程序的性能。 Guava官方对Cache的描述连接 缓存在各种各样的用例中非常有用。例如,当...
  • cache机制

    万次阅读 2012-08-10 22:27:08
    cache机制 转载地址:http://www.cnblogs.com/liloke/archive/2011/11/20/2255737.html 在阅读文章前,您应该具备基本的存储器层次结构知识,至少要了解局部性原理。要详细了解cache基本原理,可以参考...

空空如也

1 2 3 4 5 ... 20
收藏数 1,206,685
精华内容 482,674
关键字:

cache