高级操作系统

2020-12-20  本文已影响0人  somedays

随着硬件的发展,过去的OS并不能很好的适应新硬件的速度,必须修改内核,以充分发挥硬件的性能。

硬件的改变

aos-history-hardware

OS的实现依赖于

设计目标

OS

基础:

挑战:

内存管理

基础:

挑战:

进程管理

基础:

挑战:

同步互斥

基础:

挑战:

文件系统

基础:

挑战:

IO

基础:

挑战:

挑战

性能

aos-multiCore

随着CPU技术的高速发展,目前已经有在单台机器上,运行1k+多的cores了。

然而对于现有的操作系统,例如Linux/FreeBSD等,在处理多核时,并不如人意。并且随着核数的增加,性能出现不升反降的现象。

aos-multi-core-perf
aos-multi-core-speed

原因

在现有的内核中,对共享资源会使用锁操作,来完成并发。这在核数比较少的情况下,可以很好的工作,但是当核数多起来,会导致CPU大部分时间都在抢占锁的session中,导致性能不升反降。

OS架构

单体结构

aos-single

特点

设计

aos-linux

微内核结构

aos-extra-os

特点

例子

aos-microkernel

外核结构

aos-extro-os

特点

设计

aos-extro-os-modul

挑战

比较

aos-extro-basic-syscall aos-extro-exception aos-extro-network aos-extro-memory

虚拟机

aos-virsh-os

特点

设计

aos-virsh-machines
aos-vm-types

VM的种类有,系统级别的VM,也有进程级别的VM,而它们又分VM的指令是否与host指令一致。

aos-vm-level

虚拟VM可以在不同层面作出虚拟,例如进程级别的VM是通过DLL来抽象出来的;

kvm是通过OS层面抽象出来的;

还可以直接通过抽象hardware来直接提供虚拟化技术

要素

OS的运行原理

aos-os

下图为系统调用的过程

aos-vmm

VMM工作原理

aos-vmm-overvie
CPU
aos-vmm-systmecall
内存
aos-vmm-memory
aos-vmm-page aos-os-tlb aos-vmm-tlb
IO

OS运行原理

aos-os-io

VMM工作原理

aos-vmm-io aos-vmm-shareio

虚拟化优化

问题:

使用更小体积的VM

研究发现linux一般的体积有1G。vm在启动一个1G的Linux的时候,非常慢。使用lightVm(8M)一个体积非常小的os,可以大大加速vmm的处理时间。

减少不必要的系统调用

可以看出,VM的性能下降,更多是因为系统调用发生的双倍上下文切换引起的。那么如果通过设计vmm把硬件的特权指令直接交给进程去执行,就可以减少系统调用,进而实现优化的目的

OS API设计

随着新应用和新场景的出现,会导致某些api变得不常用。新的需求,又会引发需要增加api接口来实现新功能的支持。

对多核的支持,现存的linux api支持的并不好。

例如fd总是返回最小的一个,会导致在分配fd时必须加自旋锁,来保证分配fd的唯一性

OS开发语言

C的缺陷

由于C的这些特点,使得Linux内核的bug数量一直维持在高水平

当然C可以作为内核语言,它的优势是足够灵活和高效,几乎可以使用所有场景

Go语言

作为高级语言,它可以有效的解决C带来的缺陷,但同时,为了解决这些缺陷,也带来了性能的开销。

它的垃圾回收机制,也同时引起了性能的问题。

但是bug的数量会大大减少。

因此在考虑linux内核的语言时,看性能和安全的取舍。

Rust语言

它同时具备高性能和高安全的特点。但是学习曲线比较高

小结

在现有几乎所有的linux都是使用C来编写,即使高级语言有很多好处,但是替换C不是一朝一夕的事情,很多问题有待实现和观察。

内存模型

多核处理器

aos-mult-core

由于单核CPU受限于功耗和设计复杂度等因素,导致很难再在单核上优化CPU,因此多核成为了加快CPU的一种途径。

处理器缓存结构

aos-single-core-cache

对于单个CPU,内部会有多个核组成。每个核拥有自己的L1 cache。而对于L2 cache,可以是共享和单独占有两种类型。对于共享cache的好处是数据一致性处理更简单,但是会有空间冲突的不好;对于独占cache的好处是不会有冲突,但是在保证一致性方面需要进一步的处理。

NUMA架构

aos-numa

NUMA是由多个CPU组成的,而每个CPU拥有多个核,每个CPU有自己的cache,不同的CPU拥有不同的时钟周期。

对于每个cache,是全局可见的,由于时钟周期不一样,这导致在跨CPU访问cache会有更大的开销

OS在NUMA上的表现

aos-amdahl-law

在实践测试的过程中发现,在核数增长到一定程度,机器的性能会出现不升反降的现象。原因是OS内部,对共享资源有大量的同步互斥原语的控制,这直接造成了OS无法做到水平扩展。

cache一致性

aos-cache-modul

每个CPU拥有自己的cache,这导致在多线程处理同一个变量的时候,这个变量同时位于不同的CPU的cache中,如果此时一个线程改变了这个共享变量的值,那么此时就必须通知另外一个cache,来更新这个值,来保证一致性。

aos-cache-no-cons

解决方法一

共用cache:可以解决数据同步的问题。但是这导致一个时钟周期只有一个CPU可以操作cache,这会带来严重的性能问题。

解决方法二

加入同步方案

同步准则

MSI一致性协议

I->S:CPU请求读,数据来源内存或者其他cache,占用总线

S->M:CPU请求写,发送数据失效Invalid到其他cache,令其他cache S->I,占用总线

M->S:CPU写完成

S->I:其他CPU请求写

MESI一致性协议

从MSI可以看到,如果一个cache从I->M(失效->修改)的转变需要占用总线两次,这在总线占用的开销来说比较昂贵。

MESI在MSI的基础上增加了E(独占)状态

I->E:数据总线发送invalid,占用总线

E->M:修改数据,不发送任何消息

来实现I->M只占用总线一次来加快效率

cache store buffer

由于CPU的速度远远高于cache,在CPU触发多次写的时候,cache可能来不及接收修改的内容

这是就引入了store buffer来解决这个问题。

aos-cache-store-buffer

但同时Store buffer也带来了不一致性,需要增加在同步数据的时候增加读Store buffer的步骤来解决数据一致性的问题。

Invalidate Queue
aos-cache-invalid-queue

由于当CPU需要修改cache,会发送Invalid消息到其他CPU,按照MSI协议,CPU需要等待其他CPU返回ACK才开始操作cache。但由于考虑到执行效率的情况,CPU并不会等待ACK,而是马上执行修改cache的操作。

这就导致CPU的执行有可能出现数据不一致的问题。

memory barrier

为了解决Invalid queue引发的不一致性问题,CPU引入barrier的操作,对于特殊变量,可以通过barrier执行清空queue和store buffer,来严格保证数据一致性。

但同时barrier会带来性能下降的问题。

因此只有在特殊情况下才使用barrier,来保证特殊变量的一致性

其他情况下CPU允许不一致和局部乱序的执行代码。

aos-fence

编译优化

aos-compiler

对于上述代码,即使在单核处理器上,assert也有可能是false。

这是由于在编译优化的过程中,编译器会判断程序的两条指令是否有数值关联,如果没有,就会根据运行效率,来调整两条语句的顺序,来达到优化的目的。

通过加入fence操作,解决了上述问题

aos-complier-sove

no fence共享变量

aos-unfence

对于两个线程的共享变量,如果没有加fence操作,有可能总线并不足够在一次传送可以送完整个变量的值,从而导致数据错乱的情况。

通过加入fence操作,保证了变量的一致性

aos-fence-sove

Release-Acquire

aos-release-acquire

通过加入原子操作,使得两个线程可以按顺序的执行

MCS lock

普通的spin lock,由于在多个CPU共享同一个atomit变量,造成,在fence同步时,开销非常大,MCS lock通过把atomit变量分散到不同cache里面,来解决这个问题。

aos-mcs

每个lock维持自己的一个自旋变量,当上一个自旋锁释放时,会更新链表的下一个元素的自旋变量,来把下一个锁打开。

aos-mcs-perf

RCU

OS内存在大量链表操作,在修改链表时,如果每次都把整个链表锁了,会引发非常大的开销。

通过RCU可以有效的解决这个问题。

上一篇 下一篇

猜你喜欢

热点阅读