首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

Linux内核空间用来设置内存映射区域的缓存属性的pgprot_* 系列函数的详细介绍【CPU核心、Cache(高速缓存)、写缓冲器、主存之间的关系;Cache和写缓冲器的详细介绍】

  • 25-03-05 05:22
  • 3175
  • 6843
blog.csdn.net

目录

  • 原理示意图
  • Cache(高速缓存)的详细介绍
    • Cache(高速缓存)的概要介绍
    • Cache(高速缓存)的读操作原理和流程
    • Cache(高速缓存)的写操作原理和流程
      • 1. **Write-Through(写直达)**
      • 2. **Write-Back(写回)**
      • 3. **Write Combining(写合并)**
      • **写数据的典型流程(以 Write-Back 为例)**
      • **数据一致性问题**
      • **总结**
  • 写缓冲器的介绍
  • 重要概念:主存(内存)中的数据除了可以被 CPU 修改,也可能被其他硬件或设备修改
  • pgprot_* 系列函数的详细介绍
    • **1. `pgprot_cached`**
    • **2. `pgprot_noncached`**
    • **3. `pgprot_writecombine`**
    • **4. `pgprot_device`**
    • **5. `pgprot_writethrough`**
    • **6. `pgprot_writeback`**
    • **7. `pgprot_none`**
    • **8. `pgprot_exec`**
    • **9. `pgprot_user`**
    • **10. `pgprot_kernel`**
    • **11. `pgprot_modify`**
    • **12. `pgprot_val` 和 `__pgprot`**
    • **总结:缓存模式与实时性对比**
  • 非缓存模式和设备内存模式的区别
    • **1. 定义和用途**
      • **设备内存模式(Device Memory)**
      • **非缓存模式(Non-cached Memory)**
    • **2. 缓存行为**
      • **设备内存模式**
      • **非缓存模式**
    • **3. 写入行为**
      • **设备内存模式**
      • **非缓存模式**
    • **4. 内存屏障的使用**
      • **设备内存模式**
      • **非缓存模式**
    • **5. 典型应用场景**
      • **设备内存模式**
      • **非缓存模式**
    • **6. 总结对比**
    • **具体区别分析**
    • **总结**

原理示意图

Cache 和 写缓冲器 是 CPU 的核心组成部分,属于 CPU 微架构设计的一部分。

下图是CPU核心、Cache(高速缓存)、写缓冲器、主存之间的关系。

Cache(高速缓存) 相当于是一块高速内存;写缓冲器相当于一个 FIFO,可以把多个写操作集合起来一次写入内存。
在这里插入图片描述

Cache(高速缓存)的详细介绍

Cache(高速缓存)的概要介绍

Cache 是 CPU 内部(或者在某些情况下,靠近 CPU 的芯片上)的一种高速存储器,用来存储近期访问的数据或指令的副本。

  • 特性:
    • Cache 通常分为多级(L1、L2、L3),L1 最靠近 CPU,速度最快,但容量最小。
    • Cache 数据通常以缓存行(Cache Line)为单位存储和管理。
    • 通过保持数据的局部性(时间局部性和空间局部性)来提高性能。

Cache(高速缓存)的读操作原理和流程

  • 当 CPU 需要访问内存中的某块数据时,会首先检查 Cache 中是否有该数据(称为 Cache 命中)。
  • 如果数据命中,则直接从 Cache 中读取,速度远高于从主内存读取。
  • 如果数据未命中(Cache Miss),则需要从主存(RAM)中加载数据,同时可能更新 Cache。

Cache(高速缓存)的写操作原理和流程

在启用了 Cache 的情况下,写数据通常会遵循以下流程:数据优先写入 Cache,然后根据 Cache 的策略再写入主存(内存)。以下是主要的写策略策的工作原理。


1. Write-Through(写直达)

  • 工作原理:
    • 数据被写入 Cache 的同时,立即写入主存(内存)。
    • Cache 和主存始终保持同步。
  • 优点:
    • 数据一致性较高,主存始终是最新的数据。
    • 如果发生 Cache Miss,主存的数据仍然是有效的。
  • 缺点:
    • 写操作速度较慢,因为每次写入都需要同时更新主存,无法充分利用 Cache 的性能。
  • 适用场景:
    • 对数据一致性要求较高的场景。

2. Write-Back(写回)

  • 工作原理:
    • 数据只写入 Cache,并标记该 Cache Line 为“已修改”(Dirty)。
    • 数据不会立即写入主存,只有在以下情况之一时才会写回主存:
      1. 该 Cache Line 被替换(即被新的数据占用时)。
      2. 主动使用指令或操作(如 flush)将数据刷新到主存。
  • 优点:
    • 写操作效率更高,因为减少了对主存的直接写入次数。
    • 对多个连续写操作,可以在 Cache 中合并,从而提高性能。
  • 缺点:
    • 数据一致性较难维护,主存中的数据可能是旧的。
    • 如果系统崩溃或电源中断,可能会导致 Cache 中的数据丢失。
  • 适用场景:
    • 对性能要求高且能容忍一定数据一致性延迟的场景。

3. Write Combining(写合并)

  • 工作原理:
    • 对多个连续的写操作进行合并,在写缓冲器中批量写入主存。
    • 通常用于图像处理、DMA 传输等场景。
  • 优点:
    • 减少主存写操作次数,提高总的写性能。
  • 缺点:
    • 数据一致性依赖于合并策略,可能会引入延迟。
  • 适用场景:
    • 高吞吐量、低数据一致性要求的场景,如硬件设备缓冲区。

写数据的典型流程(以 Write-Back 为例)

  1. 写入 Cache:

    • CPU 通过 Cache Controller 将数据存储到 Cache 中。
    • 如果目标地址的 Cache Line 已存在(命中),更新对应的数据。
    • 如果未命中,先从主存加载目标地址的 Cache Line,再写入新的数据。
  2. 标记 Dirty:

    • 更新 Cache Line 的标志位,标记为“已修改”(Dirty)。
  3. 延迟写回:

    • 数据不会立即写入主存。
    • 当 Cache Line 被替换或需要刷新的时候,Cache Controller 会将 Dirty 数据写回主存。

数据一致性问题

由于数据在 Cache 和主存之间可能存在延迟写入,所以可能会导致以下问题:

  • 数据一致性问题:

    • 如果 CPU 或设备访问的是主存而不是 Cache,可能读取到旧数据。
    • 多核 CPU 或其他硬件设备共享同一内存区域时,需要特别处理一致性。
  • 解决方法:

    1. 内存屏障(Memory Barrier):
      • 强制确保在屏障之前的所有操作完成后,才执行屏障之后的操作。
    2. Cache 刷新(Cache Flush):
      • 使用指令(如 clflush)将 Cache 数据强制写回主存。
    3. 禁止 Cache:
      • 对某些关键内存区域(如设备寄存器),可以禁用 Cache 或使用 Non-Cached 模式。

总结

启用 Cache 后,写数据是先写入 Cache,然后再根据策略写入主存。具体的写行为取决于 Cache 策略(Write-Through、Write-Back 或 Write Combining):

  • Write-Through:实时同步到主存,数据一致性高,但效率较低。
  • Write-Back:延迟写回主存,性能更高,但需要注意一致性问题。
  • Write Combining:合并写入,适用于连续写操作,但一致性较弱。

写缓冲器的介绍

其实在看了上面的关于Cache(高速缓存)“写合并”策略,就知道了写缓冲器是怎么回事儿了。

重要概念:主存(内存)中的数据除了可以被 CPU 修改,也可能被其他硬件或设备修改

主存中的数据不仅可以被 CPU 修改,还可能通过以下途径被其他设备修改:

  1. DMA 设备(如硬盘、网卡、GPU 等)。
  2. 外设映射内存(Memory-Mapped I/O)。
  3. 多核 CPU。
  4. GPU。
  5. 硬件调试工具。
  6. 虚拟内存系统。
  7. 网络设备(如 RDMA)。

pgprot_* 系列函数的详细介绍

在搞清楚了Cache(高速缓存)的原理后,再来看pgprot_* 系列函数就要容易得多了。

pgprot_* 系列函数是用来设置内存映射区域的Cache(高速缓存)属性的函数。

以下是 pgprot_* 系列函数的完整介绍,包括每种模式对 数据实时性 的影响:


1. pgprot_cached

  • 功能:将内存设置为 缓存模式(Cacheable)。
  • 特性:
    • 数据会存储在 CPU 缓存中,读取数据和写入数据都通过Cache进行,所以速度较快。
    • 存在数据一致性问题,即Cache中的数据和主存中的数据可能不一致。
  • 数据实时性:较差,可能存在缓存延迟,不适合实时性要求高的场景。
  • 应用场景:普通内存区域,非实时性要求场景。
  • 用法:
    vma->vm_page_prot = pgprot_cached(vma->vm_page_prot);
    
    • 1

2. pgprot_noncached

  • 功能:将内存设置为 非缓存模式(Uncacheable)。
  • 特性:
    • 禁用缓存,每次读取都直接访问物理内存。
    • 保证数据的实时一致性。
  • 数据实时性:非常高,适合需要确保数据最新的场景。
  • 应用场景:设备寄存器映射、DMA 缓冲区等。
  • 用法:
    vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
    
    • 1
    注意: 非缓存模式(Uncacheable)和 设备内存模式(Device Memory)很相似,但是还是有差别的,详情见本博文后面的内容。

3. pgprot_writecombine

  • 功能:将内存设置为 写合并模式(Write Combine)。
  • 特性:
    • 写入数据时,CPU 会暂时存储在写缓冲区中,允许合并多次写入以减少内存交互。
    • 提高写入效率,但读数据仍直接访问内存。
    • 读数据的时候是直接从主存中读取,而不是从Cache中读取。
  • 数据实时性:
    • 写入:较差,写缓冲区可能导致写入延迟。
    • 读取:较高,因为是直接访问主存,而不是从Cache中读取数据,所以读取到值为主存中的最新值,当主存中的值被别的因素更新时,它读取到的值是最新值。
  • 应用场景:显存、帧缓冲区等需要高效写入的场景。
  • 用法:
    vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
    
    • 1

4. pgprot_device

  • 功能:将内存设置为 设备内存模式(Device Memory)。
  • 特性:
    • 禁用缓存,确保所有读写操作按顺序执行(强序访问)。
    • 适用于设备寄存器或 I/O 操作。
  • 数据实时性:非常高,完全禁用缓存,保证操作顺序和实时性。
  • 应用场景:设备寄存器、外设的强序访问。
  • 用法:
    vma->vm_page_prot = pgprot_device(vma->vm_page_prot);
    
    • 1
    注意: 非缓存模式(Uncacheable)和 设备内存模式(Device Memory)很相似,但是还是有差别的,详情见本博文后面的内容。

5. pgprot_writethrough

  • 功能:将内存设置为 写透缓存模式(Write-Through Cacheable)。
  • 特性:
    • 写入数据时,会同时更新 CPU 缓存和物理内存。
    • 读取操作优先从缓存中获取,提高读取效率。
  • 数据实时性:较高,写入实时同步到内存,数据一致性较好。
  • 应用场景:需要缓存性能且写入实时性要求高的场景。
  • 用法:
    vma->vm_page_prot = pgprot_writethrough(vma->vm_page_prot);
    
    • 1

6. pgprot_writeback

  • 功能:将内存设置为 写回缓存模式(Write-Back Cacheable)。
  • 特性:
    • 写入数据时,仅更新 CPU 缓存,必要时才将数据写回到内存。
    • 最大化写入性能,但数据可能会滞留在缓存中。
  • 数据实时性:较差,写回机制可能导致数据更新延迟。
  • 应用场景:高性能内存访问,不关心实时性的场景。
  • 用法:
    vma->vm_page_prot = pgprot_writeback(vma->vm_page_prot);
    
    • 1

7. pgprot_none

  • 功能:设置内存区域为 无访问权限。
  • 特性:
    • 禁止对该内存区域的访问(读取、写入或执行)。
  • 数据实时性:不适用,因为完全禁止访问。
  • 应用场景:保护内存区域、防止非法访问。
  • 用法:
    vma->vm_page_prot = pgprot_none(vma->vm_page_prot);
    
    • 1

8. pgprot_exec

  • 功能:设置内存区域为 可执行。
  • 特性:
    • 允许在该内存区域运行代码。
    • 主要用于代码段内存或动态分配的可执行区域。
  • 数据实时性:无直接影响,与缓存属性无关。
  • 应用场景:执行代码段内存。
  • 用法:
    vma->vm_page_prot = pgprot_exec(vma->vm_page_prot);
    
    • 1

9. pgprot_user

  • 功能:设置内存区域为 用户态访问权限。
  • 特性:
    • 用户态进程可以访问该内存区域。
  • 数据实时性:与具体缓存模式相关,无直接影响。
  • 应用场景:分配给用户态的内存。
  • 用法:
    vma->vm_page_prot = pgprot_user(vma->vm_page_prot);
    
    • 1

10. pgprot_kernel

  • 功能:设置内存区域为 仅内核态访问权限。
  • 特性:
    • 只有内核态代码可以访问该内存区域。
  • 数据实时性:与具体缓存模式相关,无直接影响。
  • 应用场景:内核专用的内存区域。
  • 用法:
    vma->vm_page_prot = pgprot_kernel(vma->vm_page_prot);
    
    • 1

11. pgprot_modify

  • 功能:修改现有 pgprot_t 的缓存属性或权限。
  • 特性:
    • 动态调整页面的缓存模式或访问权限。
  • 数据实时性:取决于修改后的缓存模式。
  • 应用场景:需要动态调整内存区域属性时。
  • 用法:
    vma->vm_page_prot = pgprot_modify(vma->vm_page_prot, new_pgprot);
    
    • 1

12. pgprot_val 和 __pgprot

  • 功能:
    • pgprot_val:从 pgprot_t 获取底层属性值。
    • __pgprot:将属性值转换回 pgprot_t。
  • 特性:主要用于自定义或调试内存页面属性。
  • 数据实时性:与具体的缓存属性无关。
  • 应用场景:自定义页面保护或调试。
  • 用法:
    unsigned long val = pgprot_val(vma->vm_page_prot);
    vma->vm_page_prot = __pgprot(val | custom_flags);
    
    • 1
    • 2

总结:缓存模式与实时性对比

函数缓存属性数据实时性应用场景
pgprot_cached缓存模式较差普通内存访问,高效读取。
pgprot_noncached非缓存模式非常高设备寄存器或 DMA。
pgprot_writecombine写合并模式写:较差
读:高
显存或帧缓冲区高频写入。
pgprot_device设备内存模式非常高外设寄存器、I/O 操作。
pgprot_writethrough写透缓存模式较高实时性较高且需要缓存的场景。
pgprot_writeback写回缓存模式较差高性能访问,但不关注实时性。
pgprot_none无访问权限不适用禁止访问的内存区域。
pgprot_exec可执行权限无直接影响动态分配的代码段或执行内存。
pgprot_user用户态访问权限无直接影响用户态进程分配的内存。
pgprot_kernel内核态访问权限无直接影响内核专用内存区域。

非缓存模式和设备内存模式的区别

设备内存模式(Device Memory)和非缓存模式(Non-cached Memory)在行为和使用场景上有一定区别,虽然两者都禁止普通缓存行为,但它们的设计目标和底层机制是不同的。以下是两者的区别及特点:


1. 定义和用途

设备内存模式(Device Memory)

  • 定义:主要用于映射硬件设备寄存器或内存区域(如 MMIO,Memory-Mapped I/O)。
  • 用途:
    • 提供严格的访问顺序。
    • 确保对设备寄存器的读写操作按预期执行。
    • 适用于硬件设备的控制和数据访问。

非缓存模式(Non-cached Memory)

  • 定义:内存区域不经过 CPU 的缓存,所有的读写直接访问主存。
  • 用途:
    • 适合需要频繁与主存交互且对性能要求较低的场景。
    • 适用于需要与 DMA 或硬件设备共享内存的场景,确保数据一致性。

2. 缓存行为

设备内存模式

  • 无缓存:禁止普通的缓存行为,不能将数据暂存到 CPU 的数据缓存(如 L1、L2 Cache)。
  • 强序列化:对设备内存的读写严格按照程序顺序进行,不能被 CPU 或编译器重新排序。
    • 读取:每次读取操作都会直接访问设备内存,确保数据是实时的。
    • 写入:写入操作通常立即生效,不允许延迟。

非缓存模式

  • 无缓存:和设备内存一样,不使用普通的 CPU 数据缓存。
  • 弱序列化:允许一定程度的访问重排序(取决于架构和实现),但提供了一些保证:
    • 读取:直接从主存读取数据。
    • 写入:写入可能会被合并,但不会缓存。
    • 通过内存屏障可以强制保证顺序访问。

3. 写入行为

设备内存模式

  • 不可写合并(No Write Combining):
    • 每次写操作会立即发出到设备。
    • 写入行为对设备是完全可见的,每次写入设备都会实时处理。

非缓存模式

  • 可能支持写合并(Write Combining):
    • 在某些平台上,可以对多个写操作进行合并,提高写性能。
    • 需要注意的是,写合并可能导致设备看不到中间状态(即等待合并完成后才写入)。

4. 内存屏障的使用

设备内存模式

  • 通常不需要额外的内存屏障,因为设备内存本身已经强制了严格的访问顺序。

非缓存模式

  • 可能需要插入内存屏障(如 wmb() 和 rmb())来保证读写的顺序。
  • 例如,在与 DMA 设备交互时,内存屏障可以确保数据在主存中的可见性。

5. 典型应用场景

设备内存模式

  • 用于硬件设备寄存器或 MMIO 区域。
  • 适合对设备寄存器的严格控制,确保访问顺序和数据的实时性。
  • 例如:
    • 写入一个寄存器后,立即读取设备状态。
    • 网络适配器、GPU、音频控制器等设备的寄存器映射。

非缓存模式

  • 用于共享内存区域(例如,CPU 和 DMA 设备之间的内存)。
  • 适合对访问顺序要求不高的场景,但需要数据一致性。
  • 例如:
    • 大量数据传输区域(缓冲区)。
    • 视频或音频流的处理。

6. 总结对比

特性设备内存模式非缓存模式
缓存行为禁用普通缓存禁用普通缓存
读写顺序强序列化,严格按程序顺序访问弱序列化,需要屏障确保顺序
写合并不支持写合并可能支持写合并
应用场景设备寄存器映射,适合小范围的精确控制DMA 或共享内存区域,适合大块数据传输
内存屏障需求通常不需要需要明确使用内存屏障

具体区别分析

  • 实时性:设备内存模式优于非缓存模式,因为它确保写入立即生效,读取返回最新值。
  • 性能:非缓存模式可能通过写合并优化性能,但实时性较差。
  • 复杂性:非缓存模式需要更多手动控制(如屏障),设备内存模式使用更简单。

总结

两者的主要区别在于访问顺序控制和写合并支持。如果你的需求是严格控制硬件设备的行为,应该选择设备内存模式;如果你的需求是高效传输大量数据,同时允许一定程度的顺序优化,可以选择非缓存模式。

昊虹嵌入式技术交流群
QQ群名片
注:本文转载自blog.csdn.net的昊虹AI笔记的文章"https://blog.csdn.net/wenhao_ir/article/details/145354997"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top