linux 内存一致性

news2024/11/28 20:36:28

linux 出现内存一致性的场景

1、编译器优化 ,代码上下没有关联的时候,因为编译优化,会有执行执行顺序不一致的问题(多核单核都会出现)
2、多核cpu乱序执行,cpu的乱序执行导致内存不一致(多核出现)
3、dma 操作,dma操作外设,或者内存数据,cpu无法感知,仍然使用cache 数据,导致内存不一致(多核单核都会出现)

内存屏障

cpu 乱序导致的问题

如果CPU需要读取的地址中的数据已经已经缓存在了cache line中,即使是cpu需要对这个地址重复进行读写,对CPU性能影响也不大,但是一旦发生了cache miss(对这个地址进行第一次写操作),如果是有序处理器,CPU在从其他CPU获取数据或者直接与主存进行数据交互的时候需要等待不可用的操作对象,这样就会非常慢,非常影响性能。举个例子:

如果CPU0发起一次对某个地址的写操作,但是其local cache中没有数据,这个数据存放在CPU1的local cache中。为了完成这次操作,CPU0会发出一个invalidate的信号,使其他CPU的cache数据无效(因为CPU0需要重新写这个地址中的值,说明这个地址中的值将被改变,如果不把其他CPU中存放的该地址的值无效,那么就有可能会出现数据不一致的问题)。只有当其他之前就已经存放了改地址数据的CPU中的值都无效了后,CPU0才能真正发起写操作。需要等待非常长的时间,这就导致了性能上的损耗。

但是乱序处理器山就不需要等待不可用的操作对象,直接把invalidate message放到invalidate queues中,然后继续干其他事情,提高了CPU的性能,但也带来了一个问题,就是程序执行过程中,可能会由于乱序处理器的处理方式导致内存乱序,程序运行结果不符合我们预期的问题。

解决的办法-内存屏障

CPU内存屏障,指令

1、通用barrier,保证读写操作有序, mb()和smp_mb()

2、写操作barrier,仅保证写操作有序,wmb()和smp_wmb()

3、读操作barrier,仅保证读操作有序,rmb()和smp_rmb()

编译器重排导致的问题

int flag, data;
 
void write_data(int value)
{
        data = value;
        flag = 1;
}
 
void read_data(void)
{
        int res;
 
        while (flag == 0);
        res = data;
        flag = 0;
        return res;
}

我们拥有2个线程,一个用来更新数据,也就是更新data的值。使用flag标志data数据已经准备就绪,其他线程可以读取。另一个线程一直调用read_data(),等待flag被置位,然后返回读取的数据data。

如果compiler产生的汇编代码是flag比data先写入内存。那么,即使是单核系统上,我们也会有问题。在flag置1之后,data写45之前,系统发生抢占。另一个进程发现flag已经置1,认为data的数据已经准别就绪。但是实际上读取data的值并不是45(可能是上次的历史数据或者非法数据)。为什么compiler还会这么操作呢?因为,compiler是不知道data和flag之间有严格的依赖关系。这种逻辑关系是我们人为强加的

解决的办法-显式编译屏障

#define barrier() __asm__ __volatile__("": : :"memory")
 
int a, b;
 
void foo(void)
{
        a = b + 1;
        barrier();
        b = 0;
}

barrier()就是compiler提供的屏障,作用是告诉compiler内存中的值已经改变,之前对内存的缓存(缓存到寄存器)都需要抛弃,barrier()之后的内存操作需要重新从内存load,而不能使用之前寄存器缓存的值。并且可以防止compiler优化barrier()前后的内存访问顺序。barrier()就像是代码中的一道不可逾越的屏障

对于单个变量可以使用 volatile 或者是指针变量

dma 内存不一致

那DMA为什么和CPU的cache会产生cache一致性的问题呢,基本的原因的什么呢?我这里总结了几个。
1、DMA直接操作系统总线来读写内存地址,而CPU并不感知。
2、如果DMA修改的内存地址,在CPU的cache中有缓存,那么CPU并不知道内存数据被修改了,CPU依然去访问cache的旧数据,导致Cache一致性问题。

dam cache 一致性解决方法

1、使用硬件cache一致性的方案,需要CCI这种IP的支持。这个需要去查看一下你用的soc是否支持CCI控制器。

2、使用non-cacheable的内存来进行DMA传输,这种方案最简单,但效率最低,严重降低性能,还增加功耗。

3、使用软件主动干预的方法来帮助cache一致性。这个是比较常规的方法,特别是在类似CCI这种缓存一致性控制器没有出来之前,都用这种方式。对于DMA的操作,我们需要考虑两种情况。

软件干预dma 操作

在这里插入图片描述理解这里为什么要先做cache的clean或者flush操作的一个关键点是:比如这个图里,大家要想清楚,在DMA开始传输之前,最新的数据在哪里?很明显,在这个图里,在这个场景下的逻辑,最新数据有可能还在cache里,因为主机的软件产生数据,比如网卡发包,CPU的网络软件去组包,这个组包的过程,其实可以看成是CPU去create了新的数据,然后CPU把数据存在内存的DMA buffer里,这个过程中,有可能还有新的数据在CPU的cache里。所以,在启动DMA之前,我们需要调用cache的flush操作,把cache的数据回写到DMA buffer里。这个就是这个逻辑。

1、 在DMA拷贝前,进行一次CACHE CLEAN,将cache内容dirty回写,清除cache,保证在DMA传输时间内不会有回写动作,(也叫做写回(Writeback):DMA从内存中读取数据时,先强制将Cache中的内容写回到内存中)
2、 在DMA拷贝完成之后,进行一次CACHE FLUSH,保证CPU访问目的地址时cache会重新构建,目的地址的值一定是从DDR上读取最新数据。(也叫做写无效(Invalidate):DMA向内存中写入数据完成后,直接令Cache中的内容无效。这样CPU在读取Cache时必然要先从内存中读取数据到Cache)

一些嵌入式平台可能包括两级Cache,称为Inner Cache和Outer Cache。前者是内部Cache,位于CPU内部,也称为一级Cache或L1 Cache;后者是外部Cache,位于CPU外部,也称为二级Cache或L2 Cache。

几个常见的嵌入式平台如ARM、MIPS、PPC都采用软件管理Cache,提供相应的接口来管理Cache,但需要我们编写代码主动操作Cache。以ARM平台为例,Linux对DMA的数据一致性操作函数为dmac_flush_range()函数和outer_flush_range()函数,两个函数都同时进行了写无效操作和写回操作确保数据一致性。

1、针对Inner Cache。

extern void dmac_flush_range(const void *, const void *);

2、针对Outer Cache。

static inline void outer_flush_range(phys_addr_t start, phys_addr_t end)

参考网址:
https://blog.csdn.net/baidu_38797690/article/details/123234019
https://zhuanlan.zhihu.com/p/465411610
https://www.cnblogs.com/jerry116/articles/9206061.html
https://zhuanlan.zhihu.com/p/505956490?utm_id=0

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/968006.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[二分查找] 旋转数组

1. &#xff08;严格递增序列&#xff09;旋转数组的元素查找 简单来说分为三种情况进行分析 1. 整个旋转数组单调递增 根据x和A[mid]的大小关系&#xff0c;更迭范围。 // 1. 整个旋转数组单调递增if (A[left]<A[right]){if (A[mid] x)return mid;else if (x < A[mid]…

C语言枚举类型enum详解、枚举变量。枚举函数

文章目录 枚举定义枚举应用枚举函数枚举函数2 枚举定义 关键字&#xff1a;enum 用途&#xff1a;定义一个取值受限制的整型变量&#xff0c;用于限制变量取值范围&#xff1b;宏定义的集合 定义枚举变量&#xff1a; enum{FALSE 0, TRUE 1} EnumName; 因为枚举变量类型较长…

矢量图片转换 Vector Magic for mac

Vector Magic会帮你进行自动识别和分析&#xff0c;转换过程中用户可选择相应的转换级别&#xff0c;从而达到自已所需的效果。 只需上传即可在线自动将 JPG、PNG、BMP 和 GIF 位图图像转换为真正的 SVG、Eps 和 PDF 矢量图像。真正的全彩描摹&#xff0c;无需安装软件&#xf…

java 对IP地址进行排序,或类ip地址的字符串进行排序

java 对IP地址进行排序&#xff0c;或类ip地址的字符串进行排序 排序前先认识一下这个拆分字符串非常好用的类 1.StringTokenizer类 1.1 构造方法 StringTokenizer(String str) &#xff1a;构造一个用来解析 str 的 StringTokenizer 对象。java 默认的分隔符是空格(“”)、…

PHP NBA球迷俱乐部系统Dreamweaver开发mysql数据库web结构php编程计算机网页

一、源码特点 PHP NBA球迷俱乐部系统是一套完善的web设计系统&#xff0c;对理解php编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。 基于PHP的NBA球迷俱乐部 二、功能介绍 1、前台主要功能&#xff1a; 系统首页 网站介…

项目(补充2):智慧教室

一。emWin环境的搭建 1.codeBlock下载 开源免费。 2.使用stm的Cubemx提供的作图软件 &#xff08;1&#xff09;在C盘下找到第三方的固件库&#xff0c;旁边有个ST文件夹 注意&#xff1a;我在下载cubemx为默认的路径 &#xff08;2&#xff09;STemWin中的Soft提供了绘图…

【STM32】学习笔记(EXTI)

EXTI外部中断 中断&#xff1a;在主程序运行过程中&#xff0c;出现了特定的中断触发条件&#xff08;中断源&#xff09;&#xff0c;使得CPU暂停当前正在运行的程序&#xff0c;转而去处理中断程序&#xff0c;处理完成后又返回原来被暂停的位置继续运行 中断优先级&#x…

字符串颜色

字体颜色 30&#xff1a;黑 31&#xff1a;红 32&#xff1a;绿 33&#xff1a;黄 34&#xff1a;蓝色 35&#xff1a;紫色 36&#xff1a;深绿 37&#xff1a;白色 字体背景颜色 40&#xff1a;黑 41&#xff1a;深红 42&#xff1a;绿 43&#xff1a;黄色 44&#xff1a;蓝…

使用 Tkinter 在 Python 中构建井字游戏!

一、说明 做你还记得小时候玩井字游戏吗&#xff1f;这是一个简单的游戏&#xff0c;只需一支笔或铅笔就可以在一张纸上玩。但是你知道你也可以使用Python的Tkinter库创建一个井字游戏吗&#xff1f;在本文中&#xff0c;我们将介绍使用 Tkinter 创建井字游戏的过程。在本文结束…

vue的 ECMAScript 6的学习

一 ECMAScript 6 1.1 ECMAScript 6 ECMAScript 和 JavaScript 的关系是&#xff0c;前者是后者的规格&#xff0c;后者是前者的一种实现&#xff08;另外的 ECMAScript 方言还有 Jscript 和 ActionScript&#xff09;。 因此&#xff0c;ES6 既是一个历史名词&#xff0c;也…

word添加字体库

1001 Fonts ❤ Free Fonts Baby!51044 free fonts in 28637 families Free licenses for commercial use Direct font downloads Mac Windows Linuxhttps://www.1001fonts.com/ 下载字体后复制粘贴到下面的位置&#xff1a;

IDEA自定义模板

IDEA自定义模板 &#xff08;1&#xff09;定义sop模板 ①在Live Templates中增加模板 ②先定义一个模板的组 ③在模板组里新建模板 ④定义模板 Abbreviation:模板的缩略名称Description:模板的描述Template text:模板的代码片段应用范围。比如点击Define。选择如下&…

输出图元(四)8-1 图元、屏幕坐标、指定二维世界坐标系统

用于图形应用的通用软件包称为计算机图形应用编程接口(CCAPI)它提供可以在C等程序设计语言中用来创建图形的函数库。如第3 章所指出的&#xff0c;函数库可以分成几种类型。创建图形时最先要做的一件事就是要描述显示场景的组成部分。图形的组成部分可以是树木和地形家具和墙壁…

无涯教程-JavaScript - CUBEKPIMEMBER函数

描述 该函数返回关键绩效指标(KPI)属性,并在单元格中显示KPI名称。 语法 CUBEKPIMEMBER (connection, kpi_name, kpi_property, [caption])争论 Argument描述Required/OptionalconnectionName of the connection to the cube - A text stringRequiredkpi_nameName of the K…

13. 性能测试

目录 1. 什么是性能测试 1.1 常见的性能问题 1.2 性能测试的概念 1.3 性能测试和功能测试的区别 1.4 性能的好坏如何定义 1.5 影响性能的因素 2. 为什么进行性能测试 3. 性能测试常见专业术语以及衡量指标 4. 性能测试分类 4.1 基准测试 4.2 负载测试 4.3 压力测…

FC-CLIP-卷积永存:开放词汇分割与单一冻结卷积CLIP

论文链接&#xff1a;https://arxiv.org/abs/2308.02487 Github&#xff1a;GitHub - bytedance/fc-clip: This repo contains the code for our paper Convolutions Die Hard: Open-Vocabulary Segmentation with Single Frozen Convolutional CLIP 机构&#xff1a;约翰霍普…

PLL原语例化使用时常见问题

目录 一、前言 二、常见问题 问题一、综合阶段报错[Synth 8-439] 问题二、综合阶段报错[Synth 8-448] 问题三、在实现阶段DRC报错DRC PDRC-38 问题四、在实现阶段DRC报错DRC PDRC-43 一、前言 在设计中经常会使用PLL的原语进行例化使用&#xff0c;PLL如果直接例化使用将…

十二、MySQL(DQL)分组/排序/分页查询如何实现?

总括 select 字段列表 from 表名 [where 条件] (group by)/(order by)/(limit) 分组字段名 分组查询 1、分组查询 &#xff08;1&#xff09;基础语法&#xff1a; select 字段列表 from 表名 [where 条件] group by 分组字段名 [having 分组之后的过滤条件] &#xff08;…

【C++初阶】queue的常见操作和模拟实现以及deque的介绍

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前学习C和算法 ✈️专栏&#xff1a;C航路 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章对你有帮助的话 欢迎 评论&#x1f4ac; 点赞&#x1…

相交链表:k神题解的一点小感慨

题目&#xff1a; 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交&#xff1a; 题目数据 保证 整个链式结构中不存在环。 朴素解法 用…