首页
学习
活动
专区
圈层
工具
发布
50 篇文章
1
混部之殇-论云原生资源隔离技术之CPU隔离(一)
2
腾讯TencentOS 十年云原生的迭代演进之路
5
一次内核hung task分析
7
NFSv4客户端hung住的BUG,您解决了吗?
8
nfs不同版本的挂载与解析
9
(好文重发)朴英敏:用crash工具分析Linux内核死锁的一次实战
10
内核问题解决方法记录
11
blocked for more than 120 seconds
12
记一次Linux主机内存脏数据引发的NameNode故障
13
​[linux][memory]cgroup回收内存对虚拟机的影响分析
14
docker cgroup 技术之memory(首篇)
15
[linux][memory] 内存回收
16
Linux内核理解 Memory barrier(内存屏障)
17
Linux内核27-优化和内存屏障
18
谢宝友:深入理解 Linux RCU 从硬件说起之内存屏障
19
谢宝友:深入理解 RCU 之概念
20
聊聊 Linux 上软件实现的“交换机” - Bridge!
21
谈谈 Linux 假死现象
22
宋宝华: 数据库为什么有可能喜欢Linux AIO(异步I/O)?
23
深入理解Linux内核之脏页跟踪
24
Iowait的成因、对系统影响及对策
25
打通IO栈:一次编译服务器性能优化实战
26
浅谈Linux dirty data配置
27
write文件一个字节后何时发起写磁盘IO?
28
深入理解 Linux的 I/O 系统
29
深入理解Linux 的Page Cache
30
深入理解Linux文件系统之文件系统挂载(上)
31
深入理解Linux文件系统之文件系统挂载(下)
32
【线上故障】通过系统日志分析和定位
33
实战案例分享:根据 JVM crash 日志定位和分析问题
34
Linux系统安全 | Linux日志分析和管理
35
如何快速处理线上故障
36
面试-线上故障如何排查
37
Linux内核Crash分析
38
内核timer crash debug思路
39
一次解决Linux内核内存泄漏实战全过程
40
Linux Kernel模块内存泄露的一种查找思路
41
linux系统奔溃之vmcore:kdump 的亲密战友 crash
42
crash浅析tasklist_lock与进程释放
43
Linux OOM机制分析
44
cgroup oom引发Pod重建问题分析
45
workqueue相关数据结构在内核crash分析中的实战应用
46
Linux设备驱动workqueue(工作队列)案例实现
47
Linux内核中的软中断、tasklet和工作队列具体解释
48
扒开 Linux 中断的底裤之 workqueue
49
Linux系统驱动之GIC驱动程序对中断的处理流程
50
Linux系统驱动之链式中断控制器驱动程序编写

Linux内核27-优化和内存屏障

1. 引言

我们都知道,带有优化的编译器,会尝试重新排序汇编指令,以提高程序的执行速度。但是,当在处理同步问题的时候,重新排序的指令应该被避免。因为重新排序可能会打乱我们之前想要的同步效果。其实,所有的同步原语都可以充当优化和内存屏障。

优化屏障保证屏障原语前后的C语言转换成汇编语言之后,指令序列不会发生变化。比如说,对于Linux内核的barrier()宏,展开后就是asm volatile("":::"memory"),就是一个优化屏障。asm告知编译器插入一条汇编指令,volatile关键字禁止编译器用程序的其它指令重新洗牌asm指令。memory关键字强迫编译器假设RAM中所有的位置都被汇编指令更改了;因此,编译器不会使用CPU寄存器中的值优化asm指令之前的代码。我们需要注意的是优化屏障不能保证汇编指令的执行不会乱序,这是由内存屏障保障的。

内存屏障确保屏障原语前的指令完成后,才会启动原语之后的指令操作。

2. 架构相关的内存屏障实现

X86系统中,下面这些汇编指令都是串行的,可以充当内存屏障:

  • 所有操作I/O端口的指令;
  • 前缀lock的指令;
  • 所有写控制寄存器,系统寄存器或debug寄存器的指令(比如,clisti指令,可以改变eflags寄存器的IF标志);
  • lfencesfencemfence汇编指令,分别用来实现读内存屏障、写内存屏障和读/写内存屏障;
  • 特殊的汇编指令,比如iret指令,可以终止中断或异常处理程序。

ARM系统中,使用ldrexstrex汇编指令实现内存屏障。

3. Linux内核使用的内存屏障原语

Linux内核中使用的内存屏障原语如下,如表5-6所示。当然了,这些原语完全可以作为优化屏障,阻止编译器优化该屏障前后的汇编指令。读内存屏障只对内存的读操作指令有效;写内存屏障只对内存的写操作指令有效。smp_xxx()之类的内存屏障只对发生在多核系统里的竞态条件有效,单核系统中,什么也没有做。其它的内存屏障对多核系统和单核系统都有效。

表5-6 Linux内存屏障

macro

描述

mb()

MP和UP的内存屏障

rmb()

MP和UP的读内存屏障

wmb()

MP和UP的写内存屏障

smp_mb()

MP内存屏障

smp_rmb()

MP读内存屏障

smp_wmb()

MP写内存屏障

内存屏障的实现跟系统架构息息相关。在X86系统上,如果支持lfence汇编指令,则rmb()实现为:

代码语言:javascript
复制
asm volatile("lfence":::"memory")

如不支持lfence汇编指令,则rmb()实现为:

代码语言:javascript
复制
asm volatile("lock;addl $0,0(%%esp)":::"memory")

asm volatile的作用之前的文章已经介绍过,不再赘述。lock;addl $0,0(%%esp)":::"memory"的意思是,对栈顶保存的内存地址内的内容加上0,所以这条命令本身没有意义,主要还是lock前缀,对数据总线加锁,从而使该条指令对CPU而言,称为内存屏障。

wmb()的实现事实上非常简单,就是barrier()的宏声明。这是因为,现有的Intel处理器不会对写内存访问进行重新排序,所以无法插入特定的内存屏障指令。但是,该宏还是会禁止编译器打乱指令。

值得注意的是多核处理器中,所有的原子操作指令都会前缀lock,所以都可以充当内存屏障。

4. 总结

内存屏障主要解决的还是硬件数据总线上对于指令的读取可能会发生乱序问题。所以,内存屏障的使用场合就是对系统进行设置或者配置时,因为这些设置关系到后面的程序能否正确工作,所以需要内存屏障,保证程序运行之前,系统的配置已经生效。

下一篇
举报
领券