Cache 原理

Cache基本概念、类型及一致性协议解析

memory hierarchy

 

cache 基本概念

cache line: 一条cache的大小

cache size: 整个cache的大小

offset: 对应cache line中的那个byte, eg:8byte cache line size, 需要3bit的offset

index: 对应哪条cache line, eg: 64byte cache 大小,每条cache line是8byte,所以一共有8条cache line, 需要3bit

tag: 对应地址位宽,比如48bit位宽, cache size是64byte, 需要48-6=42bit

performance 计算公式

AMAT = HitTime + MissRate * MissPenalty

https://www.youtube.com/watch?v=dkCM0Hc_v3Y&list=PLeWkeA7esB-PN8dBeEjWveHwnpQk7od0m&index=5

 

Reduce hit time

  1. way prediction
  2. column associative
  3. victim cache

Reduce Miss Penalty

  1.      early restart
  2.      merging write buffer

Reduce miss rate

     compiler optimizations

  1. instruction reordering: reorder procedures in memory; 2. profiling to look at conflicts 3

  2. data reordering: 1.merging arrays; 2. loop interchange; 3.loop fusion; 4.blocking

increasing cache bandwidth

  1. pileline cache access: pro: bandwidth; con: higher branch penalty
  2. multibanked cache: core i7 L1$ 4banks, L2$ 8banks
  3. nonblocking cache: hit under miss; hit under multiple miss/miss under miss; need Miss Status Holding Registers(MSHRs) 

reducing miss penalty or miss rate via prefetching

  1. sequential prefetching
  2. strided prefetching

 

直接映射缓存

两路组相连缓存

全相连缓存

 

一个四路组相连缓存实例问题

一条cache 实际需要的位宽: valid width + dirty width + tag width + data width

write through

没有dirty位

read: 

  hit: return data from cache

  miss:read data from memory to cache, then return data from cache

write:

  hit: write data to cache, then write data to lower memory

  miss:  write data to lower memory

write back

有dirty位

read: 

  hit: return data

  miss: if dirty, write dirty data to lower memory first, and then read data from memory to cache, market not diryt,  at last return data from cache

write:

  hit: write data to cache, mark dirty data

  miss: if dirty: write dirty data to lower memory first, and then read data from memory to cache(write allocate), then write data to cache, mark dirty data

 

各种buffer

victim cache

    

 

cache coherency

two types of protocol

snooping (or broadcast) based

  1. valid tag
  2. extra tag for sharing status
  3. monitor all bus transactiion

directory based

snooping protocol MESI/MOESI

Modified: 1. only valid copy in any cache; 2.different with main memory

Exclusive: 1. valid data, 2, only exist on this cache, 3. data same with main memory. 当别的缓存读取它时,状态变为共享;当前写数据时,变为已修改状态。

Shared: 1. valid copy, other cache may exist;  2. same with main memory

Invalid: the copy is out of date and can't be used; 2. need to fetch data from memory or other cache

Owned:

 

MSI flow

there are three L$ , and there are below operation: R1, R2, W3, R2, W1, W2, R3, R2

R1:  1. read data from main memory, and L1: value|S

R2: 1. read data from main memory, and :L1: value|S

W3: 1.read data from main memory 2. write data to cache, cache: value|M, and p0,p1 cache: value|I

R2: 因为cache tag是invalid, cache3 flush data to main memory and cache2, cache2,3 tag 变成S

W1: 因为1 tag是invalid, bus read, 然后write data, cache: value|M, cache2,3: value: I

W2:tag is invalid, p1 flush data to main memory and cache2; 2. p2 write, 

R3:tag is invalid, p2 flush, and p2,p3 cache: value|S

R2:tag is shared, the data is up-to-date copy

MSI protocol:

MESI protocol:

E: exclusive: other don't have copy

 

 

MOESI protocol:

 

 

当支持cache to cache transfer, 如果cache2中的数据被write 重写后,不会去更新main memory, 如果process 1再读A, 数据可以直接从cache2中来, 

不cache miss, 就不会write back 刷新main memory?

 

 

 

Slab cache 是 Linux 内核中用于管理小对象内存分配的一种高效机制,其设计目标是减少内存碎片并提高内存分配和释放的效率。Slab cache 的核心思想是将一组相同大小的对象预先分配在连续的内存区域中(称为 slab),并将这些对象以缓存的方式管理。 ### Slab cache 的基本结构 1. **kmem_cache**:每个 slab cache 对应一个 `kmem_cache` 结构,该结构是 slab 缓存的核心描述符。`kmem_cache` 中包含了缓存的基本属性,如对象大小、对齐方式、构造函数和析构函数等。此外,`kmem_cache` 还维护了与缓存相关的其他结构,如每 CPU 缓存和每个 NUMA 节点的缓存。 2. **array_cache**:每个 CPU 拥有一个本地缓存 `array_cache`,用于存储当前 CPU 最近释放的对象。这种设计减少了跨 CPU 的内存访问,从而提高了性能。`array_cache` 中的 `entry` 数组存储了这些对象的指针。 3. **kmem_cache_node**:每个 NUMA 节点对应一个 `kmem_cache_node` 结构,用于管理该节点上的 slab。`kmem_cache_node` 包含了三个链表: - **slabs_partial**:包含部分空闲对象的 slab。 - **slabs_full**:包含所有对象都被使用的 slab。 - **slabs_free**:包含所有对象都为空闲状态的 slab。 此外,`kmem_cache_node` 还包含一个共享的 `array_cache` 成员 `shared`,用于存储可以被其他节点访问的对象[^1]。 4. **slab**:每个 slab 是一组连续的内存页,用于存储多个相同大小的对象。每个 slab 中包含一个 `freelist` 指针,指向 slab 中第一个空闲对象的索引数组,以及一个 `s_mem` 指针,指向 slab 中第一个对象的起始地址。 5. **slab 描述符**:每个 slab 都有一个描述符,记录了 slab 的状态、对象大小、对象数量等信息。 ### Slab cache 的工作原理 1. **初始化**:当创建一个新的 slab cache 时,内核会根据对象的大小和对齐要求分配一组 slab。这些 slab 被初始化并加入到相应的 `kmem_cache_node` 的链表中。 2. **内存分配**: - 当请求分配一个对象时,首先检查当前 CPU 的 `array_cache`。如果 `array_cache` 中有空闲对象,则直接从 `array_cache` 中取出一个对象返回。 - 如果 `array_cache` 中没有空闲对象,则从对应的 `kmem_cache_node` 的 `slabs_partial` 链表中查找一个有空闲对象的 slab,并从中分配对象。 - 如果 `slabs_partial` 链表中也没有可用对象,则从 `slabs_free` 链表中取出一个完全空闲的 slab,并将其转换为 `slabs_partial` 状态,然后从中分配对象。 3. **内存释放**: - 当释放一个对象时,首先将其放入当前 CPU 的 `array_cache` 中。如果 `array_cache` 已满,则将其中的一部分对象归还到对应的 `kmem_cache_node` 的 `slabs_partial` 链表中。 - 如果对象被释放到 `kmem_cache_node` 中,则根据该 slab 的状态更新其所在的链表(如从 `slabs_full` 移动到 `slabs_partial`,或从 `slabs_partial` 移动到 `slabs_free`)。 4. **回收机制**:Slab cache 提供了回收机制,当系统内存紧张时,可以通过回收 `slabs_free` 链表中的 slab 来释放内存。某些标志(如 `SLAB_NO_REAP`)可以防止特定的 slab 被回收[^3]。 ### Slab cache 的优势 1. **高效性**:通过缓存常用对象,减少了频繁的内存分配和释放操作,提高了性能。 2. **减少碎片**:Slab cache 通过预分配固定大小的对象,减少了内存碎片。 3. **支持 NUMA**:通过 `kmem_cache_node` 结构,Slab cache 支持 NUMA 架构,能够有效地管理多节点内存[^2]。 ### 结构图解析 虽然无法直接绘制结构图,但可以通过文字描述来理解各个结构之间的关系: - 所有 slab 缓存都挂载在全局链表 `slab_caches` 上。 - 每个 `kmem_cache` 结构对应一个 slab 缓存,并包含每 CPU 的 `array_cache` 和每 Node 的 `kmem_cache_node`。 - 每个 `kmem_cache_node` 包含三个链表 `slabs_partial`、`slabs_full` 和 `slabs_free`,用于管理对应节点上的 slab。 - 每个 slab 描述符中包含多个对象,`freelist` 指向第一个空闲对象的索引,`s_mem` 指向第一个对象的起始地址。 ```c struct kmem_cache { struct array_cache __percpu *cpu_cache; // 每CPU缓存 struct kmem_cache_node *node[MAX_NUMNODES]; // 每Node缓存 // 其他成员... }; struct kmem_cache_node { struct list_head slabs_partial; // 部分空闲的slab链表 struct list_head slabs_full; // 完全使用的slab链表 struct list_head slabs_free; // 完全空闲的slab链表 struct array_cache *shared; // 共享缓存 // 其他成员... }; struct slab { struct list_head list; // 链表指针 unsigned long *freelist; // 指向第一个空闲对象的索引 void *s_mem; // 指向第一个对象的起始地址 // 其他成员... }; ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值