• ARM cache 分析


    为什么需要Cache?

    从程序运行这个示例来进行解释,程序在运行时,先将执行程序从flash 加载到main memory, 然后CPU 从main memory 加载指令/数据到进行执行和计算。在不考虑cache 的情况下,整体架构可以描述为 

     程序需要从低速设备加载到高速CPU中运行,其中速度之差如下图:

     

    CPU register的速度一般小于1ns,主存的速度一般是69ns左右。速度差异近百倍。当CPU试图从主存中load/store 操作时,由于主存的速度限制,CPU不得不等待这漫长的65ns时间。

    如何解决上述问题:

    1. 提升 main memory 的速度
    2. 降低 CPU 速度
    3. 增加小而高速缓存

    对于方法1当前 main memory 一般是 G 为单位,在提升速度的时候,又保持大容量,这将使得成本非常巨大;

    对于方法2,这是个谬论;

    增加小而高速的缓存,当前 sram 的速度基本可以和 CPU 一致,容量小的情况下成本是可以接受的。采用 cache 方案之后的程序加载流程如下:

     各级速度对比

    Cache 架构

     上图是典型的哈佛 cache 架构,描述了CPU,cache 和 memory 的位置关系。参考

    ARM cortex-A series programmer's guide》

    Cache 映射方式

    系统加入 cache 之后,如何将 main memory 和 cache 映射起来?

    cache 的映射方式

    直接映射

                     参考《ARM cortex-A series programmer's guide》

    加入 cache line 大小是 8bytes, cache 大小是 64 bytes,那么总共会有8个 cacheline. 对每个 cache 做标示,则 index 是从0 到 7.

    索引 cacheline 需要 3 bit,使用地址低 bit[2:0] 表示

    每个cacheline 的 index 使用 bit[5:3] 表示

    那么, 0x0000 0000 和 0x0000 0040 都指向了 cacheline 0 类似这种,地址和 cache line 是一一对应的。这种情况下,比如 先访问 0x00,cache 中内容不存在,需要重新加载,此时又访问了内存地址 0x40, 因为也是索引 cache line 0, 虽然cache hit, 此时内容是不同的,因此需要flush 之后重新加载。如果反复在 0x00 和 0x40 之间切换,实际上造成了cache 颠簸,cache 并没有提升性能。

    全相联

    每个内存对应的cache line的位置不固定,可以映射到不同cache line。这种情况下需要花费大量时间来查找可用的 cache,代价也十分大

    组相联

                            《ARM cortex-A series programmer's guide》 

    组相连是对直接映射和全相连的一个折衷,将cache划成几路(way)和组(Set)进行管理。

    先看几个cache 术语

    如上图,一个cache就是一个sram,

    Way(路):为了方便管理,我们将sram cache分成了若干个way(通常是4个),

    Set(组): 然后又将每个way分成若干个line;每个way中,都对line进行编号,有index=1,2,3..n(index=1表示cache line的编号即line1,index=2表示line2), 我们将在不同way中,index相同的叫成set。

    Tag: 所有的cacheline 都是唯一的,每一个都有一个tag

    在cache管理中,最小的处理单元是cacheline即:

    对于一个 大小为 16K, cacheline 是64bytes 的cache,假如

    way: 4个,每个 way 大小是 4K

    Set: 64个,需要 6bit 索引,使用对应地址的 bit[11:6] 来进行索引;

    Offset: 用于索引 cacheline,总共需要 6bit,使用对应地址的 bit[5:0]索引;

    假如某次操作检查cache 命中状态,会先根据bit[11:6]索引对应的Set,假设都是 cacheline N, 那么因为Way有4个,所以需要使用tag来比较落在哪个way中,如果tag 相同则认为命中,否则是miss。

    这个时候引出了使用什么地址来索引 cache。

     

    Cache 索引方式

    歧义:同一个虚拟地址指向不同的物理地址

    别名:不同虚拟地址指向同一个物理地址

    VIVT

     index 和 tag 都是使用虚拟地址查找,不需要经过MMU硬件,因此硬件成本是最低的。但是软件维护成本是个灾难,首先同一个地址指向的是不同物理地址,但是在cache 使用时,又使用相同cache,这会带来异常巨大维护。

    PIPT

    使用PIPT不会有别名问题,因为不同虚拟地址最终对应的都是同一个物理地址,这样cache的使用都是通过物理地址来比对的,不会有别名问题。 

    VIPT

     

    这里使用虚拟地址作为 index 索引 set, 物理地址作为tag, 那么这种情况有没有别名问题?

    如果 VI=PI, 那么是没有别名问题的。

    如果VI != PI ,是会有别名问题的。

    假如一个 page 是 4K, 那么在MMU映射时,低 12bit物理地址是和虚拟地址相同的,那么如果一个 cachesize/way 小于等于page, 那么 VI=PI,否则 VI != PI的。

    Cache Policy

    写操作时,

    1. 若 cache hit, 有两种方式:
    • write-back : 写入时写入 cache
    • write-through: 写入时同时写入 cache 和 main memory.
    1. 若 cache misses, 则:
    • write-allocate: 将data 写入 cache, 然后通过 flush 写入memory
    • 非 write-allocate: 直接写入 memory

    读操作:

    1. cache hit: 直接读取
    2. cache miss:
    • read-through: 直接从 memory 中读取数据
    • read-allocate: 先从memory 读取数据到cache, 然后从cache 读取数据。

    cache coherency:

    解决cache 一致性可以通过:

    1. 使用 non-cacheable 或者某些情况下使用 write-through 方式
    2. 将系统 cache 禁掉
    3. 多核上,硬件上 MESI 机制保证cache一致性

    Cache 问题处理思路

     

    Cache 问题主要是基于上图的一个示意图来分析,常见的问题主要是 Cache 和 DDR 内容不一致导致的。

    1. ARM Core 向DDR 写入内容,在Cache 中命中,先写入 Cache, 然后导致Peripheral 读取的对应内容不一致,出现异常,ARM Core 写入之后需要 clean 相关cache
    2. Peripheral 向 DDR写入内容,ARM Core 读取对应DDR 地址在Cache中命中,出现 Cache中内容和 DDR内容不一致,此时需要peripheral 写入之后 invalidate.

    注意: Cache 在 invalidate 时,如果对应 cacheline dirty, 是会先执行 clean之后再 invalidate.

  • 相关阅读:
    设计模式学习笔记 - 面向对象 - 1.面向对象到底讨论的是什么
    [AR Foundation] AR Foundation学习之路(持续记录)
    Era Network在web3行业的价值
    axios封装(例如:请求头、token、超时、BaseUrl、请求错误、请求重复)
    LeetCode - 160. 相交链表(C语言,配图)
    ELSEVIER期刊论文投稿全流程实例讲解
    将项目制作成Dcoker镜像并运行--DevOps学习第三章
    存储过程、函数与触发器
    【牛客-算法】NC61 两数之和(哈希表的运用,C++)
    练手必备!Python编程实战—23个有趣的实战项目带你快速进阶
  • 原文地址:https://blog.csdn.net/kakaBack/article/details/126537156