计算机基础学习笔记:操作系统篇之硬件结构,CPU Cache基础概念

三、CPU Cache的数据结构和读取过程

本文知识来源小林Coding阅读整理思考,原文链接请见该篇文章

Cache结构

CPU Cache 是由很多个 Cache Line 组成的,Cache Line 是 CPU 从内存读取数据的基本单位,而 Cache Line 是由各种**标志(Tag)+ 数据块(Data Block)**组成。

注:后续 线程、进程的单位结构 ,拿来一起对比。

在这里插入图片描述

CPU 读取数据的时候,无论数据是否存放到 Cache 中,CPU 都是先访问 Cache,只有当 Cache 中找不到数据时,才会去访问内存,并把内存中的数据读入到 Cache 中,CPU 再从 CPU Cache 读取数据。

CPU访问内存、Cache的具体过程

Cache和内存的映射

CPU 访问内存数据时,是一小块一小块数据读取的,具体这一小块数据的大小,取决于 coherency_line_size 的值,一般 64 字节。在内存中,这一块的数据我们称为内存块(Block,读取的时候我们要拿到数据所在内存块的地址。

对于直接映射 Cache 采用的策略,就是把内存块的地址始终「映射」在一个 CPU Cache Line(缓存块) 的地址,至于映射关系实现方式,则是使用「取模运算」,取模运算的结果就是内存块地址对应的 CPU Cache Line(缓存块) 的地址。

具体过程

如果内存中的数据已经在 CPU Cahe 中了,那 CPU 访问一个内存地址的时候,会经历以下步骤:

  1. 经过 指令周期的取码、译码—中指令的值,都是指令的内存地址【回顾CPU的执行过程】,需要去访问 内存地址,获取数据 进行 操作。
  2. 根据内存地址中索引信息,计算在 CPU Cahe 中的索引,也就是找出对应的 CPU Cache Line 的地址;【对比MySQL的B+树索引去映射管理文件】
  3. 找到对应 CPU Cache Line 后,判断 CPU Cache Line 中的有效位,确认 CPU Cache Line 中数据是否是有效的,如果是无效的,CPU 就会直接访问内存,并重新加载数据,如果数据有效,则往下执行;
  4. 对比内存地址中组标记和 CPU Cache Line 中的组标记,确认 CPU Cache Line 中的数据是我们要访问的内存数据,如果不是的话,CPU 就会直接访问内存,并重新加载数据,如果是的话,则往下执行;
  5. 根据内存地址中偏移量信息,从 CPU Cache Line 的数据块中,读取对应的字。

在这里插入图片描述

提升程序执行效率

  • 数据缓存
  • 指令缓存
  • 多核情况

→ 提升缓存的命中率!

对于数据缓存:

当访问地址时,CPU 会一次从内存中加载CPU Cache Line ( coherency_line_size,Linux通常为64字节) 大小的数据到 CPU Cache 。

而编程语言中的常见类型 一般在16字节以下;在操作数据时必然可一下子访问更多的数据,多余的数据则可缓存【缓存的是地址,而非具体数据】至Cache,那么在下次操作数据时,该数据正好时上次访问过的,则无需再去内存访问,则提升了命中率。

  • 遍历数组的情况时,按照内存布局顺序访问,将可以有效的利用 CPU Cache 带来的好处,这样我们代码的性能就会得到很大的提升。
  • 声明数组时的范围 也可按照 64字节/ 类型字节数 的倍数来声明,

对于指令缓存:

  • CPU的分支预测器

对于 if 条件语句,意味着此时至少可以选择跳转到两段不同的指令执行,也就是 if 还是 else 中的指令。那么,如果分支预测可以预测到接下来要执行 if 里的指令,还是 else 指令的话,就可以「提前」把这些指令放在指令缓存中,这样 CPU 可以直接从 Cache 读取到指令,于是执行速度就会很快。

对于多核CPU提升Cache命中率

在单核 CPU,虽然只能执行一个线程,但是操作系统给每个线程分配了一个时间片,时间片用完了,就调度下一个线程,于是各个线程就按时间片交替地占用 CPU,从宏观上看起来各个线程同时在执行。【线程上下文切换:几十微妙级别:测试方法见 https://www.modb.pro/db/415579

而现代 CPU 都是多核心的,线程可能在不同 CPU 核心来回切换执行,这对 CPU Cache 不是有利的,虽然 L3 Cache 是多核心之间共享的,但是 L1 和 L2 Cache 都是每个核心独有的,如果一个线程在不同核心来回切换,各个核心的缓存命中率就会受到影响,相反如果线程都在同一个核心上执行,那么其数据的 L1 和 L2 Cache 的缓存命中率可以得到有效提高,缓存命中率高就意味着 CPU 可以减少访问 内存的频率。

当有多个同时执行「计算密集型」的线程,为了防止因为切换到不同的核心,而导致缓存命中率下降的问题,我们可以把线程绑定在某一个 CPU 核心上,这样性能可以得到非常可观的提升。

在 Linux 上提供了 sched_setaffinity 方法,来实现将线程绑定到某个 CPU 核心这一功能。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值