linux ARM64 处理器内存屏障

一、内存类型:

ARMv8架构将系统中所有的内存,按照它们的特性,划分成两种,即普通内存和设备内存。并且它们是互斥的,也就是说系统中的某段内存要么是普通内存,要么是设备内存,不能都是。

1)普通内存(Normal Memory)

普通内存的特性是,在没有别的写入的情况下,每次读取出来的值都是一样的。针对普通内存,Arm处理器会采用比较激进的优化方式,从而导致指令重排序的问题。

普通内存可以被指定为支持缓存(Cached)或不支持缓存(Non-Cached)。如果两个模块之间不支持数据一致性协议,那么它们之间的共享内存一定是不支持缓存的。

2)设备内存(Device Memory)

设备内存一般是对外部设备的一段内存映射,在没有写入的情况下,可能每次读取出来的值都不一样。也有可能写入这段内存会产生别的边际效应,如触发一个中断。

二、共享域

为了支持数据一致性协议,需要增加硬件很多开销,会降低系统的性能,同时也会增加系统的功耗。但是,很多时候并不需要系统中的所有模块之间都保持数据一致性,而只需要在系统中的某些模块之间保证数据一致性就行了。因此,需要对系统中的所有模块,根据数据一致性的要求,做出更细粒度的划分。

ARMv8架构将这种划分称作为域(Domain),并且一共划分成了四类:

1)非共享(Non-shareable)域

处于这个域中的内存只由当前CPU核访问,既然只能自己访问,那当然不用考虑跟系统中的其它模块,如其它CPU核或其它设备之间的数据同步问题。所以,如果一个内存区域是非共享的,系统中没有任何硬件会保证其缓存一致性。如果一不小心共享出去了,别的CPU核可以访问了,那必须由软件自己来保证其一致性。

2)内部共享(Inner Shareable)域

处于这个域中的内存可以由系统中的多个模块同时访问,并且系统硬件保证对于这段内存,对于处于同一个内部共享域中的所有模块,保证缓存一致性。

一个系统中可以同时存在多个内部共享域,对一个内部共享域做出的操作不会影响另外一个内部共享域。

3)外部共享(Outer Shareable)域

处于这个域中的内存也可以由系统中的多个模块同时访问,并且系统硬件保证对于这段内存,对于处于同一个外部共享域中的所有模块,保证缓存一致性。外部共享域可以包含一个或多个内部共享域,但是一个内部共享域只能属于一个外部共享域,不能被多个外部共享域共享。

对一个外部共享域做出的操作会影响到其包含的所有的内部共享域。

4)全系统共享(Full System)域

这个很好理解,表示对内存的修改可以被系统中的所有模块都感知到。

在一个具体的系统中,不同域的划分是由硬件平台设计者决定的,不由软件控制。并且,Arm的文档中也没有提及具体要怎么划分。但有一些指导原则,一般在一个操作系统中可以看到的所有CPU核要分配在一个内部域里面,如下图所示:

这些域的划分只是为了更细粒度的管理内存的缓存一致性,理论上所有内存都放到全系统共享域中,从功能上说也可以,但会影响性能。

可缓存性和共享性一定是对普通内存才有的概念。设备内存一定是不支持缓存的,且是外部共享的。

三、屏障

不同处理器提供的内存屏障指令不同, ARM64 处理器提供了 3 种内存屏障。

(1)指令同步屏障( Instruction Synchronization Barrier, ISB),指令是 isb。

(2)数据内存屏障( Data Memory Barrier, DMB),指令是 dmb。

(3)数据同步屏障( Data Synchronization Barrier, DSB),指令是 dsb。

指令同步屏障指令冲刷流水线,在屏障指令执行完毕后重新取程序中屏障指令后面的所有指令,以便使用最新的内存管理单元配置检查权限和访问。屏障指令确保以前执行的改变上下文的操作(包括缓存维护指令、页表缓存维护指令或修改系统控制寄存器)在屏障指令执行完的时候已经完成。

数据内存屏障保证屏障前面的内存访问和屏障后面的内存访问的相对顺序,屏障前面的内存访问必须在屏障后面的内存访问之前被观察到,但是不保证屏障前面的内存访问完成。

数据同步屏障保证屏障前面的内存访问、缓存维护指令和页表缓存维护指令在屏障完成之前已经完成,屏障后面的任何指令在屏障完成之后才能开始执行,是比数据内存屏障更强的屏障。

DMB和DSB指令都需要带一个参数,这个参数指明了数据屏障指令的作用范围和针对的共享域。共享域前面说过了,一共有四种。作用范围表示数据屏障指令具体对哪些存储器访问操作起作用,ARMv8共定义了三种,分别是:

1.  Load - Load, Load - Store:表示内存屏障保证其之前的所有加载操作一定在其之前完成,其之后的所有加载和存储操作一定在其之后才开始,但是其之前的存储操作有可能会在其之后才执行。

2.  Store - Store:表示内存屏障保证其之前的所有存储操作一定在其之前完成,而其之后的存储操作一定在其之后才能开始,但是对于加载操作没有任何限制。

3.  Any - Any:表示内存屏障保证其之前的所有加载和存储操作一定在其之前完成,而其后的所有加载和存储操作一定在其之后才能开始。

注意,ARMv8不提供所谓的Store-Load型的顺序保证,如果真的需要这种保证,只能使用Any-Any型的。关于DMB和DSB指令的参数,可以总结为如下表格:

参数

作用范围

共享域

OSHLD

Load - Load, Load - Store

外部共享域

OSHST

Store - Store

外部共享域

OSH

Any - Any

外部共享域

NSHLD

Load - Load, Load - Store

非共享域

NSHST

Store - Store

非共享域

NSH

Any - Any

非共享域

ISHLD

Load - Load, Load - Store

内部共享域

ISHST

Store - Store

内部共享域

ISH

Any - Any

内部共享域

LD

Load - Load, Load - Store

全系统共享域

ST

Store - Store

全系统共享域

SY

Any - Any

全系统共享域

ARM64 架构定义的内存屏障宏如下。

(1) #define mb() asm volatile("dsb sy” : : : "memory")

使用数据同步屏障指令,保证屏障前面的读写操作在屏障完成之前已经完成,使整个系统看见。

(2) #define wmb() asm volatile("dsb st” : : : "memory")

使用数据同步屏障指令,保证屏障前面的写操作在屏障完成之前已经完成,使整个系统看见。

(3) #define rmb() asm volatile("dsb ld” : : : "memory")

使用数据同步屏障指令,保证屏障前面的读操作在屏障完成之前已经完成,使整个系统看见。

(4) #define read_barrier_depends() do { } while (0)

(5) #define smp_mb() asm volatile("dmb ish” : : : "memory")

使用数据内存屏障指令, 保证屏障前面的读写操作和屏障后面的读写操作的相对顺序,使内部共享域(包括所有处理器)看见。

(6) #define smp_wmb() asm volatile("dmb ishst” : : : "memory")

使用数据内存屏障指令,保证屏障前面的写操作和屏障后面的写操作的相对顺序,使内部共享域看见。

(7) #define smp_rmb() asm volatile("dmb ishld” : : : "memory")

使用数据内存屏障指令,保证屏障前面的读操作和屏障后面的读写操作的相对顺序,使内部共享域看见。

(8) #define smp_read_barrier_depends() do { } while (0)

(9) #define dma_wmb() asm volatile("dmb oshst” : : : "memory")

使用数据内存屏障指令,保证屏障前面的写操作和屏障后面的写操作的相对顺序,使外部共享域(包括所有处理器和外围设备)看见。

(10) #define dma_rmb() asm volatile("dmb oshld” : : : "memory")

使用数据内存屏障指令,保证屏障前面的读操作和屏障后面的读写操作的相对顺序,使外部共享域看见。

ARM64 还提供了带有隐含单向屏障的加载和存储指令。

(1)加载获取指令 ldar。

加载获取指令后面并且匹配目标地址的共享域的所有加载存储操作必须在加载获取指令之后被观察到。所以,可以看出来,这条指令是个单向屏障,只挡住了后面出现的所有内存操作指令,但是没有挡住这条指令之前的所有内存操作指令。

(2)存储释放指令 stlr。

存储释放指令前面并且匹配目标地址的共享域的所有加载存储操作必须在存储释放指令之前被观察到,并且存储释放指令生成的存储操作在该指令执行完之后可以被观察到。所以,这条指令也是一个单向屏障,只挡住了前面出现的所有内存操作指令,但是没有挡住这条指令之后的所有内存操作指令。

单向屏障的作用范围可以总结为下面这张图:

ARM64 还提供了上面两条指令的独占版本: ldaxr 和 stlxr。

ARM64 架构的内核使用加载获取指令实现了加载获取函数 smp_load_acquire(p)和 smp_cond_load_acquire(ptr, cond_expr),使用存储释放指令实现了存储释放函数 smp_store_release(p, v)。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

乐理基础-情绪与速度、具体的速度、BPM

首先音乐中的一拍并不是一个具体的时间(详情看这两个 认识音符、什么是一拍),一拍并不是1图6:秒、2秒、3秒这样一个具体的时间,只能说在同样一份乐谱和同样一个速度下,全音符、二分音符、四分音符等等会依次…

b站高可用架构 笔记

b站高可用架构 关键点:主机房,多活和多活机房 参考文章:bilibili技术总监毛剑:B站高可用架构实践 1. 前端和数据中心负载均衡 前端负载均衡(动态CDN):最近节点、带宽策略、可用服务容量 数据中心负载均衡:均衡流量、识别异常节…

jvm相关命令操作

查看jvm使用情况 jmap -heap PID 查看线程使用情况 jstack pid 查看当前线程数 jstack 21294 |grep -E (#[0-9]) -o -c 查看系统线程数 top -H top -Hp pid #查看具体的进程中的线程信息 使用 jps 命令查看配置了JVM的服务 查看某个进程JVM的GC使用情况 jstat -gc 进程…

独立搭建UI自动化测试框架分享

今天给大家分享一个seleniumtestngmavenant的UI自动化,可以用于功能测试,也可按复杂的业务流程编写测试用例,今天此篇文章不过多讲解如何实现CI/CD,只讲解自己能独立搭建UI框架,如果有其他好的框架也可以联系我&#x…

【Kafka每日一问】kafka中partition 的多个节点是分布在不同的broker上面吗

kafka中partition 的多个节点是分布在不同的broker上面吗 是的,Kafka中的partition(分区)会被复制到不同的broker上。每个partition都可以配置多个副本(replica),这些副本都保存着相同的消息。当一个producer往这个partition写入消息时,消息…

测试自动化平台 | 测试开发工程师的进阶之路

一、测试工程师的现状 很多测试小伙伴在工作中有时会比较迷茫,不知该怎样突破瓶颈,更好的发展。 那么测试人员究竟该如何打破瓶颈继续向上提升呢?如果你苦于不知所措,又满怀斗志向上的话,不妨一起聊聊。测试职业发展…

D : B DS二叉排序树_树中第k小的元素

Description 给定一个二叉排序树和一个整数k,要求输出树中第k个最小元素(k从1开始计数)。 Input 第一行输入t,表示有t个测试样例。 第二行起,首先输入n,接着输入n个整数表示一个二叉排序树,接着输入k。 以此类推共…

爱芯派pro通过无线网卡rtl8188eu连接热点

爱芯派pro通过无线网卡rtl8188eu连接热点 爱芯派pro目前的底板的pcie的复位有问题,所以pcie接口无法挂载上去,所以自己购买的rtl8822网卡也用不了,然后想起来自己还有正点原子的rtl8188eu网卡,但是没有和工作人员进行摸索后才知道…

0x26 广搜变形

0x26 广搜变形 1.双端队列BFS 在最基本的广度优先搜索中,每次沿着分支的扩展都记为“一步”,我们通过逐层搜索,解决了求从起始状态到每个状态的最少步数的问题。这其实等价于在一张边权均为1的图上执行广度优先遍历,求出每个点相…

idea 如何使用 JaCoCo 跑覆盖率

背景介绍 什么代码覆盖? 代码覆盖(Code coverage)是软件测试中的一种度量,描述程序中源代码被测试的比例和程度,所得比例称为代码覆盖率。简单来理解,就是单元测试中代码执行量与代码总量之间的比率。 Java常用的单元测试覆盖率…

为什么要用云渲染?3d Max云渲染怎么使用?

云计算技术的兴起让渲染任务的执行更加灵活和高效。借助于云计算服务,影视和动画制作公司能够将大型和资源密集型的渲染任务外包至远程服务器。这些任务在云渲染服务器上按块处理,而更小规模的渲染作业则可在本地工作站上完成。这种作业分配方法大幅优化…

MyBatis的配置文件!!!(properties标签 , typeAliases标签,Mappers标签)

一.将数据库配置信息定义在一个独立的配置文件里。 mybatis-config.xml: <?xml version"1.0" encoding"UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-co…