Linux性能 - 硬件

一、提高访存速度(CPU 与主存)

高速芯片、Cache、多体并行

二、提高 I/O 和主机之间的传送速度

中断、DMA、通道、I/O处理机、多总线

三、提高运算器速度

高速芯片、改进算法、快速进位链

总结

因此,提高整机处理能力,主要从两个角度入手。

  1. 高速器件
  2. 改进系统结构,挖掘系统的并行性

序言

从硬件和软件角度介绍了CPU 架构和实现。

硬件

CPU 硬件包括了处理器和它的子系统,以及多处理器之间的CPU 互联。

处理器

一颗通用的双核处理器的组件构成如图所示。

控制器(上图中标为控制逻辑)是CPU 的心脏,运行指令预取、解码、管理执行以及存储结果。

上图所示的处理器包括了一个共享的浮点单元和(可选的)共享三级缓存。你自己处理器的上述组件因类型和型号而会有所不同。其他性能与相关的组件还包括以下内容。

  • P-cache:预取缓存(每CPU 一个)。
  • W-cache:写缓存(每CPU 一个)。
  • 时钟:CPU 时钟信号生成器(或者外部提供)。
  • 时间戳计数器:为了高精度时间,由时钟递增。
  • 微代码ROM:快速把指令转化成电路信号。
  • 温度传感器:温度监控。
  • 网络接口:如果集成在芯片里(为了高性能)。
  • DMA:数据预先获取

CPU 缓存

多种硬件缓存往往包含在(包括了片上、晶粒内置、嵌入或者集成)处理器内或者与处理器放在一起(外置)。这样通过更快类型的内存缓存了读并缓冲了写,提高了内存性能。

  • 一级指令缓存(I$)
  • 一级数据缓存(D$)
  • 转译后备缓冲器(TLB)
  • 二级缓存(E$)
  • 三级缓存(可选)

E$中的E 原来指代外部(external)缓存,但是随着二级缓存的集成,这个名称被聪明地换成了嵌入(embedded)缓存。为了避免混淆,术语“级”现在已经取代了“E$”风格表示法。

通过cat /sys/devices/system/cpu/文件下查看缓存大小

由于具有8个核,所以/sys/devices/system/cpu/目录下会存在8个cpu子目录,每个cpu核一个cpu子目录。

# ls /sys/devices/system/cpu/                                                                                                                                                                                                                       
cpu0 cpu1 cpu2 cpu3 cpu4 cpu5 cpu6 cpu7

假如每个cpu都具有L1-L3级缓存,所以/sys/devices/system/cpu/cpu0/cache/目录下会有4个index子目录,每一级缓存一个子目录。

一般index0为L1数据缓存,index1为L1指令缓存,index2为L2缓存,index3为L3缓存:

# ls /sys/devices/system/cpu/cpu0/cache/
index0 index1 index2

我们以cpu核0为例,查看cpu核的缓存情况:

whyred:/ # cat /sys/devices/system/cpu/cpu0/cache/index0/level                                                                                                                                                                                               
1
whyred:/ # cat /sys/devices/system/cpu/cpu0/cache/index0/type                                                                                                                                                                                                
Data
whyred:/ # cat /sys/devices/system/cpu/cpu0/cache/index0/size                                                                                                                                                                                                
32K
whyred:/ # cat /sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size                                                                                                                                                                                 
64

可以看到cpu核0,L1数据缓存32K,cache line大小为64B

whyred:/ # cat /sys/devices/system/cpu/cpu1/cache/index1/level                                                                                                                                                                                               
1
whyred:/ # cat /sys/devices/system/cpu/cpu1/cache/index1/type                                                                                                                                                                                                
Instruction
whyred:/ # cat /sys/devices/system/cpu/cpu1/cache/index1/size                                                                                                                                                                                                
32K
whyred:/ # cat /sys/devices/system/cpu/cpu1/cache/index1/coherency_line_size                                                                                                                                                                                 
64

可以看到cpu核0,L1指令缓存32K,cache line大小为64B

whyred:/ # cat /sys/devices/system/cpu/cpu1/cache/index2/level                                                                                                                                                                                               
2
whyred:/ # cat /sys/devices/system/cpu/cpu1/cache/index2/type                                                                                                                                                                                                
Unified
whyred:/ # cat /sys/devices/system/cpu/cpu1/cache/index2/size                                                                                                                                                                                                
1024K
whyred:/ # cat /sys/devices/system/cpu/cpu1/cache/index2/coherency_line_size                                                                                                                                                                                 
64

可以看到cpu核0,L2缓存位1024K,cpu0~cpu7共享L2缓存。

缓存行:CPU 缓存的另一个特征是缓存行大小。这是一个存储和传输的字节数量单位,提高了内存吞吐量。处理器典型的缓存行大小是64 字节。

延时

多级缓存是用来取得大小和延时平衡的最佳配置。一级缓存的访问时间一般是几个CPU 时钟周期,而更大的二级缓存大约是几十个时钟周期。主存大概会花上60ns(对于4GHz 处理器大约是240 个周期),而MMU 的地址转译又会增加延时。

相联性

相联性是定位缓存新条目范围的一种缓存特性。类型如下。

  • 全关联:缓存可以在任意地方放置新条目。例如,一个LRU 算法可以剔除整个缓存里最老的条目。
  • 直接映射:每个条目在缓存里只有一个有效的地方,例如,对内存地址使用一组地址位进行哈希,得出缓存中的地址。
  • 组关联:首先通过映射(例如哈希)定位出缓存中一组地址,然后再对这些使用另一个算法(例如LRU)。这个方法通过组大小描述。例如,四路组关联把一个地址映射到四个可能的地方,然后在这四个地方中挑选最合适的一个。

CPU 缓存经常使用组关联方法,这是在全关联(开销过大)与直接映射(命中过低)中间找一个平衡点。

whyred:/ # cat /sys/devices/system/cpu/cpu0/cache/index0/ways_of_associativity                                                                                                                                                                               
4
whyred:/ # cat /sys/devices/system/cpu/cpu0/cache/index1/ways_of_associativity                                                                                                                                                                               
2
whyred:/ # cat /sys/devices/system/cpu/cpu0/cache/index2/ways_of_associativity                                                                                                                                                                               
16

可以看到cpu核0,L1 D-cache与L1 I-cache 分别为4路,2路组关联缓存。L2为16路组关联缓存。

L2缓存1024K,有16384个Cache line(256K/64B),每个组需要16路Cache line,我们将获得1024个集。这样一来,块属于哪个组取决于块索引的低10位bit(2^10=1024)。因此Cache line对应的物理地址凡是以65536字节(1024*64)的倍数区分的,将竞争同一个Cache line槽。

缓存一致性

内存可能会同时被缓存在不同处理器的多个CPU 里。当一个CPU 修改了内存,所有的缓存需要知道它们的缓存拷贝已经失效,应该被丢弃,这样后续所有的读才会取到新修改的拷贝。这个过程叫做缓存一致性,确保了CPU 永远访问正确的内存状态。这也是设计可扩展多处理器系统里最大的挑战之一,因为内存会被频繁修改。

MMU

MMU 负责虚拟地址到物理地址的转换。下图展示了一个普通的MMU,附有CPU 缓存类型。这个MMU 通过一个芯片上的TLB 缓存地址转换。主存(DRAM)里的转换表,又叫页表,处理缓存未命中情况。页表由MMU(硬件)直接读取。

CPU 性能计数器

CPU 性能计数器(CPU P erformance co unter,CPC)有许多别名,包括性能测量点计数器(PIC)、性能监控单元(PMU)、硬件事件和性能监控事件。它们是可以计数低级CPU 活动的处理器寄存器。它们通常包括下列计数器。

  • CPU 周期:包括停滞周期和停滞周期类型。
  • CPU 指令:引退的(执行过的)。
  • 一级、二级、三级缓存访问:命中,未命中。
  • 浮点单元:操作。
  • 内存I/O:读、写、停滞周期。
  • 资源I/O:读、写、停滞周期。

每个CPU 有少量,通常是2~8个,可编程记录类似事件的寄存器。哪些寄存器可用取决于处理器的类型和型号,在处理器手册中有记录。

软件

支撑CPU 的内核软件包括了调度器、调度器类和空闲线程。

调度器

内核CPU 调度器的主要功能如图所示。

功能如下。

  • 分时:可运行线程之间的多任务,优先执行最高优先级任务。
  • 抢占:一旦有高优先级线程变为可运行状态,调度器能够抢占当前运行的线程,这样较高优先级的线程可以马上开始运行。
  • 负载均衡:把可运行的线程移到空闲或者较不繁忙的CPU 队列中。

图中展示了一个CPU 的运行队列。另外,每个优先级也有自己的运行队列,这样调度器可以容易地管理同一优先级下哪个线程应该运行。

在Linux 上,分时通过系统时钟中断调用scheduler_tick()实现。这个函数调用调度器类函数管理优先级和称为时间片的CPU 时间单位的到期事件。当线程状态变成可运行后,就触发了抢占,调度类函数check_preempt_curr()被调用。线程的切换由__schedule()管理,后者通过 pick_next_task()选择最高优先级的线程运行。负载均衡由load_balance()函数负责执行。

调度类

调度类管理了可运行线程的行为,特别是它们的优先级,还有CPU 时间是否分片,以及这些时间片的长度(又称为时间量子)。通过调度策略还可以施加其他的控制,在一个调度器内进行选择,控制同一个优先级线程间的调度。

下图演示了这些内容以及线程优先级范围。用户线程的优先级受一个用户定义的一个nice 值影响。可以对不重要的工作设置这个值以降低其优先级。在Linux 上,nice 值设置了线程的静态优先级,与调度器计算的动态优先级有所区别。

Linux

NI 是优先值,是用户层面的概念, PR是进程的实际优先级, 是给内核(kernel)看(用)的。
一般情况下,PR=NI+20, 如果一个进程的优先级PR是20, 那么它的NI(nice)值就是20-20=0。

什么是NICE值?

  • NICE值应该是熟悉Linux/UNIX的人很了解的概念了,它是反应一个进程“优先级”状态的值,其取值范围是-20至19,一共40个级别。
  • 这个值越小,表示进程”优先级”越高,而值越大“优先级”越低。

对于Linux 内核,调度器类如下。

RT:为实时类负载提供固定的高优先级。内核支持用户和内核级别的抢占,允许RT任务以短延时分发。优先级范围为0~99(MAX_RT_PRIO-1)。

O(1):O(1)调度器在Linux 2.6 作为默认用户进程分时调度器引入。先前的调度器包含了一个遍历所有任务的函数,算法复杂度为O(n),这样扩展性就成了问题。相对于CPU 消耗型线程,O(1)调度器动态地提高I/O 消耗型线程的优先级,以降低交互和I/O 负载的延时。

CFS:Linux 2.6.23 引入了完全公平调度作为默认用户进程分时调度器。这个调度器使用红黑树取代了传统运行队列来管理任务,以任务的CPU 时间作为键值。这样使得CPU 的少量消费者相对于CPU 消耗型负载更容易被找到,提高了交互和I/O 消耗型负载的性能。

用户级进程可以通过调用sched_setscheduler()设置调度器策略以调整调度类的行为。RT 类支持SCHED_RR 和SCHED_FIFO 策略,而CFS 类支持SCHED_NORMAL 和SCHED_BATCH。

调度器策略如下:

RR:SCHED_RR 是轮转调度。一旦一个线程用完了它的时间片,它就被挪到自己优先级运行队列的尾部,这样同等优先级的其他线程可以运行。

FIFO:SCHED_FIFO 是一种先进先出调度,一直运行队列头的线程直到它自愿退出,或者一个更高优先级的线程抵达。线程会一直运行,即便在运行队列当中存在相同优先级的其他线程。

NORMAL:SCHED_NORMAL(以前称为SCHED_OTHER)是一种分时调度,是用户进程的默认策略。调度器根据调度类动态调整优先级。对于O(1),时间片长度根据静态优先级设置,即更高优先级的工作分配到更长的时间。对于CFS,时间片是动态的。

BATCH:SCHED_BATCH 和SCHED_NORMAL 类似,但期望线程是CPU 消耗型的,这样就不会打断其他I/O 消耗型交互工作。

其他类和策略可能会不断加入。已研究过的调度算法包括感知超线程的[Bulpin 0 5]和感知温度的[Otto 06],通过考虑额外的处理器因素优化了性能。

当没有线程可以运行时,一个特殊的空闲任务(又称为空闲线程)作为替代者运行,直到有其他线程可运行。

我要理解的CPU、核心,进程、线程,串行、并发、并行

注意看修饰词。

1、计算机硬件基本组成
一个计算机(冯·诺依曼结构)【主要】硬件组成:

主板:是“交通枢纽”,各个部件工作的所在平台,它负责将各个部件紧密连接在一起,各部件通过主板进行数据传输
CPU:中央处理器(Central Processing Unit),决定电脑的性能等级。主要有3大组成部分
运算器:算术逻辑运算单元(ALU,Arithmetic Logic Unit),负责执行所有的数学和逻辑工作
控制器:控制单元(CU,Control Unit),控制计算机的所有其他部件,如输入输出设备以及存储器
寄存器:存储单元,包括CPU片内缓存和寄存器组,是CPU中暂时存放数据的地方
内存:将输入设备接收到的信息以二进制的数据形式存到存储器中
RAM
ROM
CMOS
外存:辅助存储器,像硬盘等,能长期保存信息
显卡、网卡、声卡、电源、键盘、鼠标、显示器等

win10下观察其内存动态使用图:

CPU是一块超大规模的集成电路,是一台计算机的运算核心(Core)和控制核心( Control Unit)。它的功能主要是解释计算机指令、处理计算机软件中的数据。

CPU工作原理图:


windows10下 CPU动态使用图:

上述这款CPU的 构造:

这就是我们购买电脑时,所看到的CPU参数:该电脑拥有1个CPU,它有4个内核(表示有4个相对独立的CPU核心单元组,这是物理概念)。

上述这个CPU可描述为:单CPU 4核心 4线程。4核 指的是物理核心(物理概念)。4线程(线程数是一个逻辑概念)。

上述这个CPU不支持 超线程技术。超线程技术、虚拟化技术 是两个不同的东西。

也可以通过cmd,wmic,cpu get查看:

NumberOfCores:表示CPU核心数
NumberOfLogicalProcessors:表示CPU线程数
多核 是指一个CPU有多个核心处理器,处理器之间通过CPU内部总线进行通讯。

多CPU是指简单的多个CPU工作在同一个系统上,多个CPU之间的通讯是通过主板上的总线进行的。

参考文章:
CPU个数,核心数,线程数

2、进程(process)、线程(thread)

注意下方语句中的 主体:操作系统、CPU

进程:是操作系统(OS)进行资源(CPU、内存、磁盘、IO、带宽等)分配的最小单位;

是OS对正在运行的程序的一种抽象,是应用程序的执行实例,每个进程是由私有的虚拟地址空间、代码、数据和其它各种系统资源组成。

打开一个浏览器、一个聊天窗口分别是一个进程。进程可以有多个子任务,如聊天工具接收消息、发送消息,这些子任务是线程。
资源分配给进程,线程共享进程资源。

线程:是CPU调度和分配的基本单位。
一个进程可由多个线程的执行单元组成,每个线程都运行在同一进程的上下文中,共享同样的代码和全局数据。
每个进程至少有一个主执行线程,它无需由用户主动创建,一般由系统自动创建。系统创建好进程后,实际上就启动了执行该进程的执行主线程,执行主线程以函数地址形式,即程序入口函数(如 main函数),将程序的启动点提供给操作系统。主执行线程终止了,进程也就随之终止。

线程数 是一种逻辑概念,是模拟出的CPU核心数。

进程和线程的关系:进程可以简单理解为一个容器,有自己独立的地址空间,其内部的各个线程共享该地址空间。
其实严格讲应该是线程能够获得CPU资源,进程对CPU资源的获取也是体现在线程上的。至于CPU内核数,和进程线程没直接关系。操作系统(OS)可以把某个进程部署在某个CPU核上,当然这要取决于系统设计。

线程是CPU调度和分配的最小单位,操作系统会根据进程的优先级和线程的优先级去调度CPU。一个计算机可以并发(同时)的线程数,等于计算机上的逻辑处理器的个数(CPU个数 *每个CPU核心数 *每个内核线程数)。

进程、线程是操作系统调度的,进程本身不会负责调度线程。在操作系统看来,线程和进程其实差不多,不同点是线程是迷你的进程,并且进程可以包含多个线程。

对比    进程    线程
定义    进程是程序运行的一个实体的运行过程,是系统进行资源分配和调配的一个独立单位    线程是进程运行和执行的最小调度单位
系统开销    创建撤销切换开销大,资源要重新分配和收回    仅保存少量寄存器的内容,开销小,在进程的地址空间执行代码
拥有资产    资源拥有的基本单位    基本上不占资源,仅有不可少的资源(程序计数器,一组寄存器和栈)
调度    资源分配的基本单位    独立调度分配的单位
安全性    进程间相互独立,互不影响    线程共享一个进程下面的资源,可以互相通信和影响
地址空间    系统赋予的独立的内存地址空间    由相关堆栈寄存器和和线程控制表TCB组成,寄存器可被用来存储线程内的局部变量

线程切换

CPU给线程分配时间片(也就是分配给线程的时间),执行完时间片后会切换都另一个线程。

切换之前会保存线程的状态,下次时间片再给这个线程时才能知道当前状态。

从保存线程A的状态再到切换到线程B时,重新加载线程B的状态的这个过程就叫上下文切换。

而上下切换时会消耗大量的CPU时间。

线程开销

上下文切换消耗
线程创建和消亡的开销
线程需要保存维持线程本地栈,会消耗内存
程序与进程、线程的关系

程序 只是一组指令的有序集合,它本身没有任何运行的含义,只是一个静态的实体。
而进程则不同,它是程序在某个数据集上的执行(即 进程是程序的一次执行),是一个动态的实体,有自己的生命周期,因创建而产生、因调度而运行、因等待资源或事件而被处于等待状态、因任务完成而被撤销,反映的是一个程序在一定的数据集上运行的全部动态过程。

进程和程序并不是一一对应的:一个程序执行在不同的数据集上就成为不同的进程,可以用进程控制块来唯一地标识每个进程。这是程序无法做到的,因为程序没有和数据产生直接的联系,即使是执行不同的数据的程序,但它们的指令的集合依然是一样的,因此无法唯一地标识出这些运行在不同数据集上的程序。
一般来说,一个进程肯定有一个与之对应的程序,而且只有一个。而一个程序有可能没有与之对应的进程(因为它没有执行)、也可能有多个进程与之对应(运行在不同的数据集上)。

不同的进程可以执行同一段程序,比如读取同一个文件数据,它们的读取函数的代码是相同的,并被2个进程或线程运行了。

一般情况下,写一个程序,没有单独开线程,那么默认这个程序的一次运行就是一个单进程;而如果调用了fork,这时将会有2个进程,调用thread,则这个进程就会有2个线程。

进程是一个实体,每一个进程都有它自己的内存地址段(heap、stack等),进程是执行中的程序。

程序是一个没有生命的实体,只有处理器赋予程序生命时,才能成为一个活动的实体。

线程,程序执行的最小单元,每个程序都至少有一个线程,若程序只有一个线程,那就是它程序本身。单线程的进程可以简单地理解为只有一个线程的进程。一个进程在同一时间只做一件事,但有了多线程后,一个进程同一时间可以做多件事,每个线程可以处理不同的事务。无论系统有几个CPU,其实进程运行在单CPU上,多线程也可以是进程并发处理多个事务。一个线程阻塞不会影响另一个线程。

多线程的进程可以尽可能地利用系统CPU资源,但也不是线程越多越好,线程越多,CPU分配给每个线程的时间就越少。

线程 包含了表示进程内执行环节所必需的信息:标识线程的线程ID、一组寄存器值、栈、调度优先级和策略、信号屏蔽字、errno变量、线程私有数据。
对于内存而言,堆内存、代码区一般属于一个进程,但是栈却是属于一个线程的,且每个线程拥有一个独立的栈。
errno也是属于单个线程的,每个线程中的errno是独立的。
进程内所有信息对于线程是共享的,包括执行代码、全局变量、堆内存、栈、文件描述符。

总结:
进程和线程都是一个时间段的描述,是CPU工作时间段的描述:

进程就是上下文切换的程序执行时间总和 = CPU加载上下文+CPU执行+CPU保存上下文
线程是共享了进程的上下文环境,的更为细小的CPU时间段。
3、串行、并发、并行
这些概念对于进程、线程都适用。

3.1、串行

多个任务,执行时一个执行完再执行另一个。

3.2、并发(concurrency)

多个线程在单个核心运行,同一时间一个线程运行,系统不停切换线程,看起来像同时运行,实际上是线程不停切换。

即一个指令 和另一个指令交错执行,操作系统实现这种交错执行的机制称为:上下文切换。上下文是指操作系统保持跟踪进程或线程运行所需的所有状态信息,如寄存器文件的当前值、主存内容等

3.3、并行(parallelism)

每个线程分配给独立的核心,线程同时运行。

单核CPU多个进程或多个线程内能实现并发(微观上的串行,宏观上的并行);多核CPU线程间可以实现微观上并行。

总结:
1、单CPU中进程只能是并发,多CPU计算机中进程可以并行。
2、单CPU单核中线程只能并发,单CPU多核中线程可以并行。
3、无论是并发还是并行,使用者来看,看到的是多进程,多线程。

4、CPU处理程序
4.1、单核CPU处理程序

在单CPU计算机中,有一个资源是无法被多个程序并行使用的:CPU。

单进程多线程处理:

在一个程序里,有两个功能:听歌、发送消息,这就是单进程2线程。如果听歌线程获取了锁,那么这个线程将获取CPU的运行时间,其他线程将被阻塞。但CPU始终处于运行状态,影响计算时间的其实只是加锁、解锁的时间,并不会发生CPU空闲的现象,CPU利用率100%。

线程阻塞:一般是被动的,在抢占资源中得不到资源,被动的挂起在内存,等待某种资源或信号将它唤醒。(释放CPU,不释放内存)

多进程处理:
将听歌、发消息分别写出两个独立的程序,独立运行,与上面不同的是,如果进程间需要通信,比如交换数据,则会需要很多步骤,效率低。

4.2、多核CPU处理程序

单进程多线程处理:线程可以跨核处理,进程之间则不能,如同支付宝不能访问QQ一样(安全性)。
跟单核对比:如果A核处理听歌线程阻塞,B核空闲,则CPU工作效率下降一半;没有阻塞时,QQ的A线程听歌、B线程发消息,多核CPU效率比单核快很多。

多进程多线程处理:不同的程序,不可能一个进程融合QQ、支付宝、浏览器等

多核下线程数量选择

计算密集型
程序主要为复杂的逻辑判断和复杂的运算。
CPU的利用率高,不用开太多的线程,开太多线程反而会因为线程切换时切换上下文而浪费资源。

IO密集型
程序主要为IO操作,比如磁盘IO(读取文件)和网络IO(网络请求)。
因为IO操作会阻塞线程,CPU利用率不高,可以开多点线程,阻塞时可以切换到其他就绪线程,提高CPU利用率。

总结:

提高性能的一种方式:提高硬件水平,处理速度或核心数。
另一种方式:根据实际场景,合理设置线程数,软件上提高CPU利用率。
进程:处理任务多,每个进程都有独立的内存单元,占用CPU资源相对较少。缺点是 进程间切换开销大。进程之间通信就如同两个程序之间的通信。

线程:处理任务相对较少,同时为了处理【并发】,多个线程共享内存单元,占用资源少。线程之间的通信就如同一个程序里的两个函数间通信,在函数里定义一个全局变量,两个线程(两个函数)都能用,线程间共享内存。
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
                        
原文链接:https://blog.csdn.net/weixin_38256474/article/details/90347263

  • 18
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值