-
CPU
的三大组件:- 运算器:主要用于算术运算和逻辑运算;
- 控制器:主要用于控制指令的存取过程的;
- 寄存器:数据暂存较短的时间,但是这个结构比
RAM
更加复杂,允许数据较长时间的存储在寄存器中; RAM
的数据是按照一定的地址进行编址排列的,所以CPU
需要具备一定的按照地址进行编址和寻址的能力;North Bridge
负责建立CPU
和RAM
之间的联系;CPU
的总线采用的是复用的方式;
-
PAE
:Physical Address Extension
:表示物理地址扩展,添加了4 bit
最多可以用于寻址2^36
个寻址空间,操作系统内核需要支持PAE
技术,用于实现32
位的机器可以使用64G
的地址空间,如果CPU
只支持32 bit
的体系结构,那么这个技术可以扩展性能,但是即使完成了PAE
扩展,单个进程使用内存地址空间任然不能够超过3G
,例如Mysql
就是单进程多线程模型,32 bit
系统上面最多支持2.7G
内存;
-
缓存的原理:
- 缓存来源于程序数据的局部性,缓存器需要比原始数据存储设备快,但是需要比原始数据存储设备小; 将存储设备热区中的数据保存在缓存设备中,用于弥补存取设备之间的速度差异;缓存设备需要按照一定的置换策略来完成数据热区的交换;常见的置换算法需要自行了解;
- 程序的局部性表现为:
- 空间局部性:如果一个数据被访问到,那么控件上面离他很近的数据,也会很快被访问到,大多数缓存算法在加载某个数据时,也会加载其附近的数据,用于提高缓存的命中率;
- 时间局部性:数据已经被访问一次,那么很短的时间内,存在较大的可能在被访问一次;
-
缓存设备通常具有多级缓存:
- 一级缓存:分为一级数据缓存,一级指令缓存,一级缓存通常是每个
CPU
独有的,如果是多核CPU
,那么就存在多个分开的一级缓存,通常设计在CPU
的内部;通常为KB
单位; - 二级缓存:不进行数据和指令的区分,二级缓存通常也是每个
CPU
独有的’,通常为M
; - 三级缓存:通常是各个
CPU
所共享的; - 通常来说
RAM
技术通过按照一定的频率进行刷写,来保证数据在被读取之后仍然是存在的;但是SRAM
技术是不需要按照进行刷写的,电路级别的设计要复杂;
- 一级缓存:分为一级数据缓存,一级指令缓存,一级缓存通常是每个
-
缓存的两种技术:
- 直接映射技术:表示
RAM
中的任何一段地址的数据都可以存储在缓存设备中的任何一段地址;缺点是如果单次缓存未命中,就需要执行置换策略,在这种情况下,缓存的命中效率依然低下;
N
路关联技术:缓存中是一个个单独的存储槽,需要记录缓存标记[用于记录缓存是否命中],缓存的索引,缓存的键值;
1
路关联技术:表示的是,内存区域中的某个段的某个热区的数据,都可以缓存在同一个区域,如果第一次没有命中,就需要执行缓存策略;
2
路关联:表示RAM
中的数据可以存储在两个缓存槽中;8
路关联又成为完全关联;
- 直接映射技术:表示
-
内存更新文件的策略:
Write Through
:表示的含义CPU
如果更新了一级缓存的数据,接下来逐级去更新二级缓存,三级缓存以及内存中的数据,这样导致的结果是效率低下,但是数据的安全性可以得到保证;Write Back
:如果CPU
更新了一级缓存里面的数据,不会立即更新二级缓存中的数据,而是当这个数据需要被丢弃时,才回去更新这个数据,直至更新到RAM
中,这种情况假设CPU
不会被立即断电,数据存在不安全的可能性;- 现在大多数支持的是
Write Back
策略,尽可能的保证性能;
-
桥接芯片就是用来汇总外部的
IO
芯片,最终完成和CPU
的交互; -
固态硬盘是接在北桥芯片上面
PCI-E
的支持并行读写的U
盘, 对于连接在南北桥芯片上面的各个设备,是通过IO Port
来进行区分的,任何一个硬件设备在连接进入系统时都需要申请一批连续的IO
端口号,通常还需要常见设备的控制器来完成对于总线发送的数据进行校验,翻译等功能,驱动通常是驱动设备控制器工作的; -
PCI
槽的作用就是用来扩展计算机的某些功能,为了给某些特殊的设备提供预留的空间,这些预留空间需要保留一定的IO
端口; -
内核中的两种机制:
poll
:就是轮询的机制,在一定的时间间隔,主动的询问IO
或者特定的事件是否发生;epoll
:硬件设备发生特殊的事件,或者CPU
要求的IO
已经完成,可以通过主动通知的方式来完成;- 中断控制器:各个硬件设备在发起中断通知之前,必须先注册中断向量,用于区分不同的硬件设备的中断信号,这些中断控制器是可编程的,又称为可编程中断控制器;
-
任何可能发生资源竞争的地方,都成为临界区;
-
DMA
:表示直接内存访问,如果硬件支持DMA
机制,那么内存[通常是16M,相邻的1M空间是BIOS使用的]划分出一段地址空间交给DMA
芯片使用,DMA
芯片在操作IO
,直到IO
就绪后,向CPU
发起中断请求,通知IO
已经完成, -
CPU
提供指令寄存器,用于保存下一条指令的位置,用于在进程切换回来,能够继续执行指令; -
内存
-
内存是按照空间机制进行划分的,通常是按照
4K
的大划分成为一个个存储槽,称之为page frame
,在数据需要进行存储的时候,通常是通过页目录来建立线性地址和逻辑地址之间的物理关系的,并且可以提供内存保护的功能; -
X86 CPU
的设计就不是用来运行虚拟机的,而是在支持了硬件虚拟化之后,支持了虚拟机的特性; -
CPU指令的环
-
CPU
的环通常表示的是CPU
指令的运行级别;Ring 0
:特权指令模式,也就是内核模式;Ring 1
:Linux
保留没有使用;Ring 2
:Linux
保留没有使用;Ring 3
:用户控件的指令,只能够运行在Ring 3
模式底下;
-
通常来说为了方便虚拟机的的
CPU
能够运行在Ring 0
上面,需要再次完成一个抽象,讲核心指令运行在Ring -1
[硬件虚拟化]上面,保留Ring 0
级别的一些非关键指令,让虚拟机的CPU
直接运行在Ring 0
上面,可以大幅度提升虚拟机的性能; -
操作系统架构图
-
在
Linux
中进程是通过双向链表结构
-
进程的管理依赖于
Task_structure
来进行管理,又称为进程描述符;销毁进程需要删除进程描述符表,内核就无法完成对于进程的追踪; -
进程描述符的结构
-
mm
:表示进程映射内存的信息; -
进程切换的信息
-
进程切换又称为上下文切换,假设进程
A
切换为进程B
:- 首先
A
的进程描述符被挂起;stack pointer, other register, EIP register
都需要被保存,写入进程的进程描述符中,这个成为保存现场的过程,这个过程是由内核维持的,对于进程描述符的大小都是类似的;
B
进程的回复现场的过程:stack pointer,other register,EIP register
都需要重新读入,并且完成现场的恢复过程;
*上下文 切换是内核完成的,每一次切换都存在内核的切换上下文切换是必须的,但是需要使用较好的算法来尽量减少上下文切换;
- 首先
-
Linux
允许进程抢占,进程存在优先级,但是不是随时都可以抢占的,必须在Ready
状态来进行抢占;每一次tick
就可以产生一次抢占; -
进程类别:
- 交互式进程:
IO
要求非常少,通常是等待进程; - 批处理进程:
CPU
密集型进程,通常需要大量的CPU
时间来完成进程数据的处理; - 实时进程:优先级最高的;
- 交互式进程:
-
PC
:交互式进程的优先级高; -
服务器:批处理进程优先级高;
-
通常的策略是:
CPU
密集型:时间片长,但是优先级低;IO
:通常是时间片长,优先级高;
-
**Linux进程优先级的概念 **
-
实时优先级:通常和内核级别相关,
1-->99
,数值越小,优先级越低; -
静态优先级:
100-->139
,通常是数值越小,优先级越高; -
实时优先级比静态优先级高;
-
上面的
RT
表示的含义是实时优先级否则就是静态优先级,20
表示含义不是优先级为20
而是用户空间的进程ID
为120
,默认启动的进程的NICE
值为0
,对应的进程优先级是120
, -
查看实时优先级,
Nice
-
上面显示信息的含义:
[cmd]
:表示是一个内核线程;- 对于
RT priority
为99
的,表示只要是这个线程或者级才能启动,就应该立即得到运行; - 对于上图,有些内核级别的线程的不具有
RT Prioty
,仅仅具有静态优先级别; - 对于第一列显示的是对于进程的调度器类型
TS
:表示SCHED_OTHER
;FF
:表示FIFO
;
-
Linux内核对于进程的调度类别
-
实时进程:
SCHED_FIFO
:表示先进先出队列,调度策略粗糙;SCHED_RR
:表示轮询调度级别;
-
100-->139
SCHED_Other
:是专门用来调度用户空间进程的100--->139
;SCHED_BATCH
:SCHED_IDLE
:
-
Rhel6.4
以后已经不使用tick
机制,也就是无tick
系统,进程之间的通过中断系统来进行交互, -
动态优先级:
- 为了防止某些优先级较低的进程长时间得到
CPU
资源,内核会临时的调整这些进程的优先级,让进程得到CPU
资源;,主要是针对于100-->139
的这些进程,并且监控这些进程是否长时间没有得到CPU
资源;当然也存在调低优先级的情况; - 动态优先级:
dynamicpriority = max(100,min(static priority - bonus[奖惩值] + 5, 139))
;对于bonus
的范围最多是0--->10
之间;
- 为了防止某些优先级较低的进程长时间得到
-
手动调整优先级:
100--->139
:Nice
:Nice N COMMAND
:表示使用N
作为其优先级;renice -n # PID
:表示手动调整其优先级,;
chrt
:-f -p [prio] PID
:set policy to SCHED_FIFO
;-r -p [prio] PID
:set policy to SCHED_RR (default)
;
-
Linux 2.6
以后的内核对于进程按照优先级划分为99-->1
,以及100--->139
一共是139*2
个队列,每一种类的优先级包括活动队列以及 过期队列,过期队列,里面是分配了CPU
时长,但是仍然需要多于的时间片的进程;这两个队列并不是固定的,当A1[活动队列]
为空,A1
变成非活动队列,A2
变成活动队列; -
通过上述算法保证进程调度的
o(1)
调度,调度算法是CFQ:Complete Fair Queue
,主要是用来调度SCHED_Other
,尽可能保证公平,这种算法不适合于服务器,而是适合于桌面系统; -
进程的地址空间
-
Text
:表示只读段,通常是代码的指令区域; -
data
:进行了初始化的数据区域; -
BSS
:表示初始化为0
的变量; -
Heap
:表示堆,包括打开的文件; -
stack
:表示栈,本地变量,函数的参数,函数的返回地址等; -
Linux
的第一个进程是Init
,所有的子进程的父进程最终都是Init
,进程创建使用Fork()
系统调用来完成,在一开始,子进程和父进程共享所有的地址空间,在子进程需要完成Copy On Write
时,子进程就存在自己的地址空间; -
CPU
完成对于内存的访问,至少需要三个时钟周期:- 第一个周期向内存控制器传输寻址要求,内存控制器取得对应的内存的地址;
- 第二个时钟周期,请求内存控制器返回的地址,并且施加一定的内存地址控制机制,一般来说是锁机制;
- 第三个是周期完成对于内存地址空间的读或者写操作,
SMP
的处理机制,对于关键资源的竞争是导致性能瓶颈的重要原因,在一定的范围内,性能是上升的,但是之后性能会下降;
-
对于关键资源的征用可以通过设置每个
CPU
专用的内存控制器来解决, 但是由于内存是共享的,可能CPU 0
使用的资源在CPU 1
的内存控制器可访问的地址空间中;
-
对于每个
CPU
都存在自己的内存控制器,并且在一定情况下,允许访问其他CPU
的内存控制器的处理器架构,称为NUMA
,也就是非一致性内存访问,在这种机制下,每一个CPU
都存在自己的内存以及内存控制器,通常来说内存控制器是集成在CPU
里面的,但是这些内存控制器以及内存区域是弱共享的,如果要去访问其他CPU
,需要跨越总线来访问,性能会下降; -
在上面这种架构下,为了保证性能,应该尽量访问自己内存控制器,但是内核需要对于进程进行
Re balance
,这种机制是导致访问其他内存控制器的主要原因; -
对于上面的这种机制需要使用
CPU
绑定的功能来完成CPU affinity
-
首先需要下载几个软件包:
root@westos:~# apt-get install numad -y
root@westos:~# apt-cache search numactl
-
查看提供的命令:
-
查看
node0
:如果存在多个Node
,后面会继续显示;numa_mit
:表示在当前内存控制器上面命中的次数;numa_miss
:表示在当前内存控制器上面没有命中的次数;numa_foreign
:表示分配给CPU 0
的内存再被CPU 1
或者其他的CPU
使用;
-
-p PID
:用于查看某一个特定进程的内存分配的;
-
-s
:用于显示哪一个node
或者是那些node
的内存命中情况的,由于这个处理器不是NUMA
架构的,所以只能够查看一个node
;
-
numactl
:用于控制CPU
共享内存的策略的; -
--cpunodebind=nodes, -N nodes
:Only execute command on the CPUs of nodes. Note that nodes may consist of multiple CPUs. nodes may be specified as noted above.
用于实现CPU
和某个COMMAND
的绑定; -
--physcpubind=cpus, -C cpus
:用于实现进程和CPU
的绑定; -
--show
:
-
numad
:对于上面的命令需要根据自己的观察,手动的绑定某个进程到某个CPU
上面,这个命令是用于自动的绑定某个进程到某个CPU
或者是节点上面,这个命令可以大幅度的系统性能 -
上面是通过命令的方式将
CPU Node
和process
进行绑定; -
上面的命令是对于
NUMA
架构的来实现绑定的,如果对于非NUMA
架构的可以使用命令taskset
; -
taskset
:用于将某个进程绑定在某个CPU
上面;- 使用
mask
的方式来引用CPU
,通常是:0x0000 0001
表示第0
颗CPU
; 0x 0101
:表示第0
号和第2
号CPU
;
- 使用
-
例如绑定第二号
CPU
到110
进程taskset -p 0x0000 0004 110
;
-
简单的表示:
taskset -p -c 3 101
:表示绑定第三号CPU
到101
进程上面;
-
对于上面绑定了进程的
CPU
仍然是可能发生进程调度的,可以通过想内核传递参数,来隔离CPU
,不再允许进程切换到这个CPU
上面,需要传递参数isolcpus=cpu number,cpu number
,执行了上述操作的CPU
仍然需要服务于中断,所以需要将中断绑定在那些非隔离的CPU
上面,从而避免那些非隔离的CPU
处理中断; -
中断绑定的方法:
root@westos:~# echo 'CPU MASK' > /proc/irq/0/smp_affinity
-
需要进行进程绑定是因为某个繁忙的进程经常被切换出去,或者上下文切换很频繁,尤其需要考虑
TASK_RUNNABLE
以及TASK_UNINTERRUPTABLE
状态的进程; -
查看
CPU
活动状况的命令 -
sar -q
:可能需要安装sysstat
这个软件包,这个命令相当强大;
-
sar -P 0 1
:用于显示某个CPU
的使用情况
-
top
:
-
w
: -
uptime
:Tell how long the system has been running
-
vmstat
:
-
模拟使用SAR来测试
HTTPD
服务器的压力测试
-
mpstat
:用于显示多个CPU
的使用状况的;-P
:用于显示指定的某个CPU
的,否则显示所有的
I CPU #
:用于显示某个CPU
对于中断的处理情况
iostat
:用来报告CPU
以及输入输出设备的统计数据的
- 还可以直接通过查看
/proc/stat
来查看CPU
的状况,其实上面的命令都是从这个文件读取的信息,并通过可读的方式来进行显示的
dstat
:这个命令同样是异常强大
- 查看上下文切换的次数
vmstat
显示的内容的cs
表示的就是上下文切换的次数
- 这个
deepin
的上下文切换次数有点高的可怕; - CPU的调度域:
- 将
CPU
组织成倒置的文件系统,所有的CPU
域都是根域的一部分;运行在根域上面表示运行在所有的CPU
上面; - 创建
CPU
域的过程:
root@westos:~# mkdir /cpusets
root@westos:~# vim /etc/fstab
cpuset /cpusets cpuset defaults 0 0
root@westos:~# ls /cpusets/
cgroup.clone_children cpuset.mem_exclusive cpuset.mems
cgroup.procs cpuset.mem_hardwall cpuset.sched_load_balance
cgroup.sane_behavior cpuset.memory_migrate cpuset.sched_relax_domain_level
cpuset.cpu_exclusive cpuset.memory_pressure notify_on_release
cpuset.cpus cpuset.memory_pressure_enabled release_agent
cpuset.effective_cpus cpuset.memory_spread_page tasks
cpuset.effective_mems cpuset.memory_spread_slab
- 一共是
4
个CPU
CPU
的架构不是NUMA
架构,所以内存都是属于根域的
- 表示运行的进程
ID
- 创建一个目录,会自动创建一些必要的文件
- 这里面的文件是没有多少内容的,可以进行绑定
root@westos:~# echo 0 > /cpusets/domain1/cpuset.cpus
root@westos:~# echo 0 > /cpusets/domain1/cpuset.mems
root@westos:~# echo 11261[这个进程号必须是存在的] > /cpusets/domain1/tasks
- 验证绑定的效果
11261
运行在0
号CPU
上面,如果进行测试,那么也是不会改变
- 通过命令的方式将某个进程绑定在
CPU
上面