linux内存从0到1学习笔记(三,高速缓存)

高桐@BILL 高桐@BILL     2022-12-02     237

关键词:

写在前面

我们先来看一张图表,如下:

深入理解计算机系统一书将寄存器划分为L0级缓存,接着依次是L1,L2,L3,ARMv8最多可以支持7级的高速缓存,即L1级~L7级。接着是内存,本地磁盘。越往上的缓存存储空间越小,速度越快,成本也更高;越往下的存储空间越大,速度更慢,成本也更低。从上至下,每一层都可以看做是更下一层的缓存,即:L0寄存器是L1一级缓存的缓存,L1是L2的缓存,依次类推;每一层的数据都是来至它的下一层,所以每一层的数据是下一层的数据的子集。

一、高速缓存存在的意义

由于程序访问的局部性(包括时间局部性,某个内存单元在短时间内可能被再次访问;空间局部性,某个内存单元被访问后,相邻的内存单元在短时间内有可能被访问)。由于CPU和主存在性能上巨大的差异,我们在CPU和主存之间引入了高速缓存。在CPU访问数据时,如果缓存中存在该数据,则直接从缓存中读取,如果缓存中不存在,再从内存中读取数据。

二、高速缓存的原理

高速缓存Cache是非常小容量的存储器,它集成在CPU芯片内。为了便于CPU、高速缓存Cache、内存之间的信息交换,内存按块划分,高速缓存Cache按行或槽划分。

 

CPU根据查表得到的物理地址,先查询Cache中是否有数据,如果有,直接读取即可。如果Cache中没有,则从内存中读取数据,同时把数据放入Cache中,然后把数据返回给CPU。

2.1 Cache和主存的映射关系

所谓地址映射是指把主存地址空间映射到Cache地址空间,也即把存放在主存中的信息按照某种规则装入Cache。映射方式有三种,如下:

假设某个计算机的主存地址空间大小为256MB,按字节编址,Cache有8个Cache行(也即Cache块),行长(也即块大小)为64B。
这里,块大小为64B(2的6次方),主存为256MB(2的28次方), 那么主存块数=(2的28次方) / (2的6次方) = (2的22次方)。因此主存块号编号范围为从0到2的22次方,其中22位作为主存块号,6位作为块内地址,因此每个主存块的地址范围如下:

2.1.1 全相联映射

主存块可以放在Cache的任意位置,比如0号主存块,它就可以放置到Cache的3号位置,每行的标记号用于指出该行取自主存的哪一块,同时将对应的有效位置为1,后续主存块存放也是如此方式。

 

那么全相联映射下,以上图紫色主存块为例,其地址为1…1101001110。

首先会取上面的地址的前22位,也就是主存块号,来和Cache中每一行的标记进行对比

  • 若标记号=块号其有效位为1:说明Cache命中,也就是说此时访问的数据在Cache中是有副本的,因此接着只需访问后6位地址所定位的单元即可
  • 若标记号不匹配或匹配但是有效位为0:此时说明Cache未命中,则正常访问主存

全相联映射下,Cache存储空间利用充分,命中率高;但查找慢,有时可能要比对所有行的标记

2.1.2 直接映射

每个主存块只能放到一个特定的位置,其位置由主存块号%Cache总块数(取模)来确定。比如0号主存储块,由于0 % 8 = 0 ,因此它只能放到Cache的0号位置。

Cache块数=8=2的3次方,其指数部分为3,因此主存块号末尾的后3位就直接反映了它在Cache中的位置,比如上图中的0号和8号,其主存块号的后三位均为000,这也就正好对应了它们在Cache的第0行。 

那么直接映射下,以上图橙色主存块为例,其地址为0…01000001110,CPU首先会根据主存块号的后三位确定Cache行,接着会判断前19位和标记号是否匹配并同时判断有效位是否为1,如果是则Cache命中,接下来根据块内地址操作即可,反之会访问主存。

直接映射下,对于任意一个位置,只需对比一个标记,速度最快;但是Cache存储空间利用不充分,命中率低。

2.1.3 组内映射

将Cache块分为若干组,每个主存块可以放到特定分组中的任意一个位置,其中组号=主存块号%分组数。这里我们使用2路组相连映射(2块为一组,分为四组)。比如1号主存块,由于1% 4 = 1,因此它会被放入第一组的任意位置,接着(2的22次方-3)号主存块也会放入第一组,它会放到另一个空闲位置。

 

那么在组相连映射下,以上图橙色主存块为例,其地址为1…0100001110。CPU首先会根据主存块号的后两位确定所属分组号,若主存块号的前20位与分组内的某个标记号匹配同时判断有效位是否为1,如果是则Cache命中,接下来根据块内地址操作即可,反之会访问主存。

linux内存从0到1学习笔记(8.12dma-buf导出器和导入器使用示例三)

  前面解释了使用dma_buf所涉及的几个重要的结构体,今天我们来介绍下dma_buf使用的具体示例。mock_dmabuf_exp.c示例#include<linux/dma-buf.h>#include<linux/module.h>#include<linux/slab.h>structdma_buf*dmabuf_of_export 查看详情

linux内存从0到1学习笔记(五,内存分类)

一、内存类型ARMv8架构处理器定义了两种类型的内存类型,分别是普通内存(NormalMemory)和设备内存(DeviceMemory)。二、普通内存        普通内存对应MT_NORMAL属性;        普通内存由于其弱一致... 查看详情

linux内存从0到1学习笔记(8.7dma-buf代码解读)

一,基本操作与设备DMA访问drivers/dma-buf/dma-buf.c二,CPU访问DMA缓冲区对象drivers/dma-buf/dma-buf.c三,隐式Fence轮询支持drivers/dma-buf/dma-buf.c四,DMA-BUF统计drivers/dma-buf/dma-buf-sysfs-stats.c五,DMA缓冲区ioctls操作include/uapi/linux/ 查看详情

linux内存从0到1学习笔记(8.7dma-buf代码解读)

一,基本操作与设备DMA访问drivers/dma-buf/dma-buf.c二,CPU访问DMA缓冲区对象drivers/dma-buf/dma-buf.c三,隐式Fence轮询支持drivers/dma-buf/dma-buf.c四,DMA-BUF统计drivers/dma-buf/dma-buf-sysfs-stats.c五,DMA缓冲区ioctls操作include/uapi/linux/ 查看详情

linux内存从0到1学习笔记(四,tlb)

...、TLB简介        Kernel初始化的时候,会在初始化内存中创建页表;而处理器读取指令和数据的时候需要首先通过MMU查表得到物理地址,然后在访问物理地址读取指令或数据。MMU查表过程汇中需要4次访问内存,... 查看详情

linux内存从0到1学习笔记(七,用户空间虚拟内存之二-内存空间的建立)(代码片段)

在使用load_elf_binary装在一个ELF二进制文件时,将创建进程的地址空间。Linux下的exec系统调用该函数来加载ELF文件。linux_mainline-5.17.0/fs/binfmt_elf.c823staticintload_elf_binary(structlinux_binprm*bprm)824825 structfile*interpreter= 查看详情

linux内存从0到1学习笔记(二,arm64物理内存)

写在前面我们先通过一张图来里哦啊接下ARM处理器的内存管理架构;2.1ARM处理器的内存管理架构ARM处理器内核:是指ARM架构的CPU中间的核心芯片,由单晶硅制成,用来完成所有的计算、接受/存储命令、处理数据等... 查看详情

linux内存从0到1学习笔记(8.8无限dmafence)

在不同时间,结构体dma_fence具有无限期的时间,直到dma_fence_wait()执行完成。例如:FutureFence(未来围栏),在HWC1中使用的,用于在显示器不再使用缓冲区时发出信号,并在屏幕更新时创建,以使得缓冲区可见。此围栏完成的时... 查看详情

linux内存从0到1学习笔记(8.8无限dmafence)

在不同时间,结构体dma_fence具有无限期的时间,直到dma_fence_wait()执行完成。例如:FutureFence(未来围栏),在HWC1中使用的,用于在显示器不再使用缓冲区时发出信号,并在屏幕更新时创建,以使得缓冲区可见。此围栏完成的时... 查看详情

linux内存从0到1学习笔记(8.13dma内存调试一)

...常使用过程中常常会遇到哪些问题呢?当然,dma-buf也是内存使用大法的一部分,那就免不了遇到这几大件:1.dma不足(合理使用),这部分的优化慎之又慎,要么从系统内存的大锅里多盛一点,要么自己节衣缩食;2.dma-buf泄漏(... 查看详情

linux内存从0到1学习笔记(8.13dma内存调试一)

...常使用过程中常常会遇到哪些问题呢?当然,dma-buf也是内存使用大法的一部分,那就免不了遇到这几大件:1.dma不足(合理使用),这部分的优化慎之又慎,要么从系统内存的大锅里多盛一点,要么自己节衣缩食;2.dma-buf泄漏(... 查看详情

linux内存从0到1学习笔记(6.8,物理内存初始化之buddy伙伴系统)

写在前面在linux启动的那一刻,内存管理就已经开始了。在内核中,实现物理内存管理的allocator包括:初始化阶段物理内存管理memblock连续物理内存管理buddy非连续物理内存管理vmallocallocator小块物理内存管理slaballocator在系统初始... 查看详情

linux内存从0到1学习笔记(七,用户空间虚拟内存之三-内存映射)(代码片段)

...通常C标准库只提供了一个函数,由应用程序用来创建内存映射,接下来该函数调用在内部转换为适合于体系结构的系统调用mmap和mmap2。可使用munmap系统调用删除映射。一、内存映射简介        mmap完成的是将物理内... 查看详情

linux内存从0到1学习笔记(8.9可恢复硬件页面错误的含义)

...起的页面错误显然会阻碍加速器上运行的任务,通常需要内存分配来解决错误。但是,不允许内存分配来控制DMA围栏的完成,这意味着使用可恢复页面错误的任何工作负载都不能使用DMA围栏进行同步,而必须改用由用户空间控制... 查看详情

linux内存从0到1学习笔记(8.9可恢复硬件页面错误的含义)

...起的页面错误显然会阻碍加速器上运行的任务,通常需要内存分配来解决错误。但是,不允许内存分配来控制DMA围栏的完成,这意味着使用可恢复页面错误的任何工作负载都不能使用DMA围栏进行同步,而必须改用由用户空间控制... 查看详情

linux内存从0到1学习笔记(九,内存优化调试之三-内存拆解)---持续更新(代码片段)

写在前面我们在日常的工作当中需要各种手段来调试内存,尤其是在内存泄漏的情况下,我们需要一种手段来统计内存的使用去向,以确定内存使用不合理的方向。或者物理内存有限的情况下,需要对内存进行优... 查看详情

linux内存从0到1学习笔记(9.10内存优化调试之panic_on_oom介绍

通过配置/proc/sys/vm/panic_on_oom文件节点可以使能或禁用out-of-memory的panic。接下来我分享下在对该节点功能及代码架构的学习笔记;一,简介文件节点路径:/proc/sys/vm/panic_on_oom相关变量:vm.panic_on_oom该节点有三个值,分别是0,1,2... 查看详情

linux内存从0到1学习笔记(6.3,物理内存初始化之内存基本数据结构初始化)(代码片段)

写在前面这部分主要介绍,bootmem_init()内存基本数据结构初始化,如内存节点,内存域。linux_mainline-5.17.0/arch/arm64/mm/init.c321void__initbootmem_init(void)322323 unsignedlongmin,max;324//获取最大最小页号;325 min=PFN_UP(memblock_start_of_DRAM( 查看详情