【Linux内核】内存管理——缓存一致性问题

转载请注明出处: https://www.cnblogs.com/Ethan-Code/p/16652513.html

缓存一致性问题

问题1:多核CPU与cache的缓存一致性问题

多核CPU在访问内存时,每个核都有自己的cache,由于cache的写回机制,部分数据没有及时更新到内存,那么在不同线程访问同一个变量的时候就会出现不一致的情况

比如核心A访问address1,把address1的数据加载到A的cache中,核心B也访问address1并加载到B的cache中。如果核心A修改了这个数据,只会把cache中的数据修改并标记为dirty。在没有写回之前,核心B的cache中的同个数据还没改,当B去访问它时则会与A不一致。

要解决这一问题需要一种机制,来同步两个不同核心里面的缓存数据。要实现的这个机制的话,要保证做到下面这 2 点:

  1. 某个 CPU 核心里的 Cache 数据更新时,必须要传播到其他核心的 Cache,这个称为**写传播(Write Propagation)**
  2. 某个 CPU 核心里对数据的操作顺序,必须在其他核心看起来顺序是一样的,这个称为**事务的串行化(Transaction Serialization)**

事务串行化,也就是让不同核心看到的其他核心对于代码的执行顺序是一致的

要实现事务串行化,要做到 2 点:

  1. CPU 核心对于 Cache 中数据的操作,需要同步给其他 CPU 核心
  2. 要引入「锁」的概念,如果两个 CPU 核心里有相同数据的 Cache,那么对于这个 Cache 数据的更新,只有拿到了「锁」,才能进行对应的数据更新。

CPU用于保证缓存一致性,实现写传播和事务串行化,使用了基于总线嗅探的** MESI 协议**。

MESI代表4种状态,协议用状态机机制降低了总线带宽压力。

MESI状态
Modified已修改
Exclusive独占
Shared共享
Invalidated已失效

详情参考:https://xiaolincoding.com/os/1_hardware/cpu_mesi.html#mesi-%E5%8D%8F%E8%AE%AE

问题2:DMA与cache的缓存一致性问题

因为DMA是直接内存访问,对内存的访问不需要经过CPU,因此如果DMA修改了内存上的CPU访问过的数据,而CPU的cache中并不知道内存已经修改了,CPU读写内存的时候还是cache上的旧数据,造成缓存不一致问题。

也就是说,DMA和CPU可以异步地操作memory,解决访问冲突有两种方法,一种是禁止DMA目标地址范围内的cache功能。

一致性映射,代表函数:

void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp);   //分配禁止C域和B域的内存给DMA
void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr_t handle); 

在 arm 平台上会禁止页表项中的 C (Cacheable) 域以及 B (Bufferable)域。C 代表是否使用高速缓冲存储器, 而 B 代表是否使用写缓冲区。

一般驱动使用多,申请一片uncached mem ,这样无需考虑data 一致性。代码流程:对kernel页管理的页面属性设置成uncache,在缺页异常填TLB时,该属性就会写到TLB的存储属性域中。保证了dma_alloc_coherent映射的地址空间是uncached的。

dma_alloc_coherent首先对分配到的缓冲区进行cache刷新,之后将该缓冲区的页表修改为uncached,以此来保证之后DMA与CPU操作该块数据的一致性。

另一种解决冲突的方法:

  • 在DMA拷贝前,进行一次CACHE CLEAN,将cache内容dirty回写,清除cache,保证在DMA传输时间内不会有回写动作
  • 在DMA拷贝完成之后,进行一次CACHE FLUSH,保证CPU访问目的地址时cache会重新构建,目的地址的值一定是从DDR上读取最新数据。

就能很大概率避免一致性的问题。

问题3:外设寄存器与cache的缓存一致性问题

CPU访问外设的数据寄存器和状态寄存器时,也是需要将寄存器的值映射到内存上进行读写,外设寄存器的值由硬件修改,也可以由CPU读写,因此外设和CPU对寄存器映射的内存访问也是异步的。CPU访问外设寄存器的时候会建立内存映射,然后将内存缓存到cache中,若此时外设寄存器的值发生了改变,CPU是不会发现这个变化而继续访问cache中的旧数据的。

因此cache或写缓冲的存在会带来外设寄存器的缓存一致性问题。

最好将外设寄存器配置成uncache,并不适用写缓冲,让CPU在每次访问时都去读外设端口寄存器。

通常,有cache的平台都有办法对某一段地址范围禁用Cache,一般是在页表中设置的,可以设定哪些页面允许Cache缓存,哪些页面不允许Cache缓存,MMU不仅要做地址转换和访问权限检查,也要和Cache协同工作。


好文推荐:CPU缓存一致性
DMA导致的CACHE一致性问题解决方案
ARM外设寄存器Cache一致性问题

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux 内核内存管理一直是一个重要的领域,因为内存管理对于操作系统的性能和稳定性都有着很大的影响。随着计算机系统的不断发展,内存管理也需要不断地优化和改进。下面列出了一些 Linux 内核内存管理的优化措施: 1. Slab 分配器的优化:Slab 分配器是 Linux 内核中的一种高效的内存分配器,它可以在不同的缓存层次上进行对象的缓存和分配。在 Linux 内核的不同版本中,Slab 分配器都得到了很多的优化和改进,例如优化了缓存的查找和分配算法,增加了缓存的预先分配等。 2. HugeTLB 页面的使用:HugeTLB 页面是 Linux 中的一种大页面,相比于普通页面,它具有更高的性能和更少的 TLB 缓存失效。Linux 内核中可以通过 HugeTLB 来分配大块的物理内存,并将其映射到用户空间,从而提高应用程序的性能。 3. 内存压缩:内存压缩是 Linux 内核中的一种新特性,它可以将内存中的数据进行压缩,从而减少内存的使用量。内存压缩可以在内存紧张的情况下,提高系统的可用内存量,并减少系统的交换行为。 4. 内存回收的改进:内存回收是 Linux 内核中的一个重要功能,它可以回收未使用的内存,并将其重新分配给需要的应用程序。Linux 内核中的内存回收机制也得到了很多的优化和改进,例如增加了 KSM(Kernel Same-Page Merging)机制来减少内存的使用量,增加了 THP(Transparent Huge Pages)机制来提高内存的使用效率等。 5. NUMA(Non-Uniform Memory Access)优化:NUMA 是一种多处理器架构,它包括多个处理器和多个内存控制器,内存的访问时间不同。Linux 内核中可以通过 NUMA 优化来提高系统的性能,例如通过 NUMA 映射来减少不必要的内存访问和数据迁移等。 6. 内存管理的锁优化:内存管理Linux 内核中的一个核心功能,它需要对内存的访问进行管理,因此需要使用锁来保证数据的一致性。在 Linux 内核中,内存管理的锁也得到了很多的优化和改进,例如采用了读写锁和自旋锁等机制来提高锁的效率,减少锁的争用等。 以上是一些 Linux 内核内存管理的优化措施,这些措施在不同的场景下可以提高系统的性能和稳定性,让 Linux 操作系统更加出色。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值