编程高手必学的内存知识
海纳
华为编译器高级专家,原 Huawei JDK 团队负责人
20674 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 33 讲
编程高手必学的内存知识
15
15
1.0x
00:00/00:00
登录|注册

14 | CPU Cache:访存速度是如何大幅提升的?

你好,我是海纳。
经过上一节课的学习,我们了解到不同的物理器件,它们的访问速度是不一样的:速度快的往往代价高、容量小;代价低且容量大的,速度通常比较慢。为了充分发挥各种器件的优点,计算机存储数据的物理器件不会只选择一种,而是以 CPU 为核心,由内而外地组建了一整套的存储体系结构。它将各种不同的器件组合成一个体系,让各种器件扬长避短,从而形成一种快速、大容量、低成本的内存系统。
而我们要想写出高性能的程序,就必须理解这个存储体系结构,并运用好它。因此,今天这节课我们就来看看常见的存储结构是如何搭建的,并借此把握好影响程序性能的主要因素,从而对程序性能进行优化。

存储体系结构的核心

作为程序员,我们肯定是希望有无限资源的快速存储器,来存放程序的数据。而现实是,快速存储器的制造成本很高,速度慢的存储器相对便宜。所以从成本角度来说,计算机的存储结构被设计成分层的,一般包括寄存器、缓存、内存、磁盘等。
其中,缓存又是整个存储体系结构的灵魂,它让内存访问的速度接近于寄存器的访问速度。所以,要想深入理解存储体系结构,我们就要围绕“缓存”这个核心来学习。
在过去的几十年,处理器速度的增长远远超过了内存速度的增长。尤其是在 2001~2005 年间,处理器的时钟频率在以 55% 的速度增长,而同期内存速度的增长仅为 7%。为了缩小处理器和内存之间的速度差距,缓存被设计出来。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入探讨了CPU缓存在计算机存储体系结构中的重要性以及对程序性能的影响。首先介绍了存储体系结构的分层设计,强调了程序的空间局部性和时间局部性原理对缓存命中率的影响。随后深入分析了缓存的物理架构和工作原理,包括缓存块的组织形式、映射方式和替换策略。文章还讨论了缓存对程序性能的影响,指出了缓存命中和缺失对数据访问速度的影响,以及容易造成缓存缺失的情况。此外,还介绍了程序局部性对缓存命中率的影响,并通过具体例子验证了程序局部性对性能的影响。最后,文章详细讨论了伪共享问题,提出了解决伪共享的方法。整体而言,本文通过深入浅出的方式,帮助读者理解了CPU缓存在提升访存速度和优化程序性能方面的重要作用。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《编程高手必学的内存知识》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(16)

  • 最新
  • 精选
  • ZR2021
    老师太棒了,这是我见过将缓存讲的最详细的文章,课买的真值!!! 不过有几个问题想请教下老师: 1. 文章中提到的根据32位地址确定缓存的组和路,这个地址是虚拟地址还是物理地址? 后面的案例里的数组的地址是虚拟的连续地址,映射到物理地址的话不一定连续,所以当第二层4096循环的时候不一定会落到同一组;如果是物理地址的话,那就是说也得经过页表转换,这个转换是不是先经过TLB的转换,如果TLB miss里再到内存里加载新的页表? 2. 缓存伪共享看样子只会出现在多线程的场景下,单进程的话每个进程内存映射后的物理地址的间隔远远大于一个cache line,所以不会出现多进程访问了同一个cache line的情况 3. 进程切换比线程切换的代价小是不是有一部分就是这个cache line 缺失导致的,因为切换到新的进程后,里面的数据要从内存重新加载到cache line中,频繁的进程切换导致的cache 缺失也挺严重的 希望得到老师的解答,万分感谢!!!

    作者回复: 第一个问题,是物理地址,其实你后面第二题的分析差不多就能推导出来这里必须用物理地址了。你的第二和第三问,猜想都是对的。你掌握得很好嘛!

    2021-12-18
    4
    4
  • 相逢是缘
    老师,我可能陷入思维误区了,有几个问题请教一下 1、CPU如何把数据读取到cache的呢? 某个时刻一个CPU指令访问数据地址0,一个cache line 64个字节,CPU会把0~63这64个字节全部读取到cache line,假如数据线是64位,一次能读取8个字节,也需要读取8次,如果读取一次需要100个CPU时钟周期,那读取一个cache line需要800个时钟周期。但是下条指令访问的数据地址可能是0x100000,这时CPU是插入NOP操作,等待800个时钟周期等着cache line填充完吗?还是怎么操作的呢? 2、缓存做成多级,每一级电路上有什么不同吗(都是SRAM?),主要是因为硬件集成电路价格的原因去分为这么多级缓存吗? 3、了解到L1级缓存一般都分为指令Icache和数据Dcache,而到L2、L3就不分了Icache和Dcache了呢?

    作者回复: 1. 你的猜想是对的。如果读取的时候缓存不命中,这一次读数据往往都要上百年时钟周期。但是访存却不必要等cache line全部填完,它只要拿到自己想要的数据就可以了,cache line可以交给其他模块继续填充。CPU的模块之间是并行的。还有一点,如果是连续的内存读取的话,内存控制器这个模块是可以做加速的,这种优化就可以让访存和总线传输足够快。 2. 一般来说,L1/L2是SRAM,L3常见的是STT-MRAM或者是eDRAM。价格是一方面吧,关键是CPU的面积,就算你不计成本的话,功耗,散热都会受面积的影响,我们不可能无限制地增加电路面积。制程的缩小有利于在同样面积的芯片上刻录更多的电路。 3. 确实,你学习得很深入。我们课里没有提icache,是觉得概念比较多,我希望尽量简化。没有更多的icache缓存是因为没有必要,因为指令毕竟还是顺序执行的最多。不像数据cache,访问哪个内存块随机性大一些。

    2021-11-29
    3
  • aikeke
    老师,一个cache line里,V(valid)、M(modified)以及tag这几个字段是保存在哪里呢?"假设要寻址一个 32 位的地址,缓存块的大小是 64 字节,缓存组织方式是 4 路组相连,缓存大小是 8K。经过计算我们得到缓存一共有 32 个组(8×1024÷64÷4=32)"

    作者回复: 有专门的电路呀。它不占据缓存块的空间哈。你后面引用的那个公式里是不包含这几个字段的。

    2021-12-12
    2
    1
  • 🐮
    老师,你好,平台我们为提升读取数据性能,会把所需要的数据尽量放在同一个cache line中,但如果存在多个进程会对相临数据写时又要尽量不要把数据放在同一个cache line中,这块是否是从读和写来理解比较好啊,如果是读,就放一起,多进程写就不要放一起;

    作者回复: 其实核心点不在于读和写,而在于是否在多线程之间共享。单线程的话,读写都可以加速。多线程就要小心了,如果都有写操作的话,要注意伪共享的情况。

    2021-11-30
  • 那时刻
    从文件角度理解,buffer可以理解为是一类特殊文件的cache,这类特殊文件就是设备文件,比如/dev/sda1, 这类设备文件的内容被读到内存后就是buffer。而cache则是普通文件的内容被读到了内存。

    作者回复: 谢谢~其实我们第15节课就已经解释了,你可以对照一下~

    2021-11-30
  • linker
    LEVEL1_ICACHE_SIZE 32768 LEVEL1_ICACHE_ASSOC 8 LEVEL1_ICACHE_LINESIZE 64 LEVEL1_DCACHE_SIZE 32768 LEVEL1_DCACHE_ASSOC 8 LEVEL1_DCACHE_LINESIZE 64 一个cacheline == 64bytes, 总共有8路,64组,64*64*8=32768bytes是这样吗? 如果是这样的话,每个路就相当于一个cacheline

    作者回复: 对的,是啊:)

    2021-11-29
  • linker
    大佬,L1 cache,一路等于64个cacheline, 这个是怎么计算出来的,有点懵?

    作者回复: 不是吧。我的原文里是写cache的大小是组数,路数和cache line size的乘积。这句话你明白了吗?那么一个cache line就是64字节,我们看到总共有8路,所以算的是64组呀。我觉得这里写得还算清楚,你再看一下原文?

    2021-11-29
  • shenglin
    cache的物理介质是SRAM,存储的是主存里某些地址上的数据,buffer是主存的一部分,物理介质是DRAM,存储的是业务的缓冲数据。

    作者回复: OK。我们第15节课也有解释,可以对照着理解一下。

    2021-11-29
  • 满分💯
    看完收获很多,最近看了一票文章 ,结合这看,效果更加 https://coolshell.cn/articles/20793.html
    2021-12-16
    3
  • 张Dave
    第二层循环是以 512 为间隔访问元素,即每次访问都会落在同一个组内的不同 cache line ,因为一组有 8 路。 有点疑问: 一个组内有8路,8条cacheline,可容纳64元素。为什么不是按照64元素间隔遍历,这样就可以把一个组内的cacheline都替换完啊,为什么要按照512元素遍历?
    2022-02-08
    1
    2
收起评论
显示
设置
留言
16
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部