本网站相关文章:

物理, 逻辑, lcores

物理 CPU

物理封装: 每一个 CPU 都有单一的 physical id 值, 其数量表示实际主机上 socket(插槽)中的 CPU 个数, 一个物理封装使用独立的 CPU 物理插槽, 多个物理封装共享电源和风扇.
查询 linux 中物理 CPU 命令: cat /proc/cpuinfo | grep "physical id" |sort |uniq

cores

物理核心, CPU 核数

  • 一个物理封装中包含了几个独立的 CPU 核心(或者芯片组数量)
  • 一个 CPU 核心都包含有自己独立的完整硬件单元

逻辑 CPU

  • 逻辑 CPU = physical cpu _ cpu cores _ 2(HT 超线程)
  • 一个 CPU 核心对外表现为多个独立的外部 CPU 接口(逻辑 CPU)

如果有多个物理封装, 逻辑 CPU 的数量成正比, 每一个 CPU 核心(cores)共享执行单元和缓存, 上述几个术语在 linux 中的查询命令:

1
2
3
4
5
6
7
8
# 1. CPU cores: 开启了超线程, 则理论上cpu核心数需要乘2.
cat /proc/cpuinfo | grep "cpu cores" | uniq
# 2. 查询逻辑CPU数量
cat /proc/cpuinfo | grep "processor" | wc -l
# 3. 查询是否开启超线程
cat /proc/cpuinfo | grep -e "cpu cores" -e "siblings" | sort | uniq
# 4. 查询是否为虚拟机
dmidecode -s system-product-name

超线程技术

功能

在了解hyper threading之前, 先让我们了解一下multiple threading技术, 线程是进程最小的调度单位, 一个进程至少包含一个线程, 利用多线程进行并行开发, 已达到利用多核的目的. 那么超线程技术和多线程技术有什么关联呢? 两者都是虚拟化技术吗?

Hyper-Threading利用特殊的硬件指令, 将两个逻辑内核模拟成两个物理芯片, 让单个处理器能使用线程级别并行计算, 进而兼容多线程操作系统和软件, 减少了 CPU 闲置时间, 提高 CPU 的运行速率, 这实际上也是一种虚拟化思想-增加资源利用率.
Hyper-Threading就是同时多线程运行技术, 允许一个 CPU 执行多个控制流的技术, 将一个物理 CPU 模拟成两个逻辑 CPU, 从而达到对 CPU 虚拟化的目的.

目的

在 CPU 和内存速度差异较大的情况下产生的技术, 系统瓶颈不在 CPU 执行单元, 而在外部存储器, 通过 CPU HT 技术, 提高 CPU 的使用效率:

  • 让计算机做的更多
  • 让计算机跑的更快

不让 CPU 闲置着, 以达到资源的最大化利用.

CPU 亲和力

CPU 亲和力指定某一个进程在指定的 CPU 上长时间运行而不被迁移到其他 CPU, 其中 CPU 之间的均衡处理由 SMP 来完成. affinity 作用对象: SMP 架构以及其他

  • 基于进程数来调整 CPU 使用
  • 每一个 CPU 都有一个可执行进程队列
  • 当且某一个 CPU 的可执行队列中的进程数比其他最小进程数 CPU 高 25%时, 才会进行分流操作

原理:

  • 提高 CPU 中的 cache 缓存命中率
  • 将不同等级的业务隔离开来, 例如实时进程和其他业务进程, 见 DPDK

手动调整 affinity: 因为考虑到进程数来调度 CPU 的缺陷(一大群懒鬼占用着大量的机器, 一两个雷锋公用一台设备), 从而造成资源的极大浪费, 可以使用手动方式来调整 CPU affinity 的设置.
DPDK 中的应用: DPDK 利用 CPU affinity, 将 MP 和 DP 分别绑定到不同的 CPU 上, 避免无意义的进程切换工作.

单 CPU

术语

  • User Time: CPU 执行用户进程的时间, 包括 nices, 通常该值占比越大越好
  • System Time: CPU 在内核运行时间, 包括 IRQ 和 softirq, 通常该值占比越低越好
  • Waiting Time: CPU 等待 I/O 操作完成的时间, 该值过高表明系统存在 IO 瓶颈
  • Idle Time: CPU 空闲时间
  • Nice Time: CPU 调整进程优先级的时间, 见下面说明
  • Hard IRQ Time: CPU 硬中断时间
  • Soft IRQ Time: CPU 软中断时间, 关于中断见下面说明
  • Steal Time: CPU 丢失或者强制虚拟 CPU 的时间, 此时 hypervisor 为另外一个虚拟 CPU 服务.

PRI/NI/Nice

  • PRI: 进程优先权, 值越高, 越早被执行
  • NI: 进程 nice 值, 用于控制和影响进程优先级
  • %nice: CPU 调整进程优先级的时间占比

PIR 表示进程的优先级, 其中 PRI 和 nice 的关系: PRI(new)=PRI(old)+nice, 其中 nice 的占比从-20~+19, 如果 nice 为+19, 其优先级是最低, 这是一个高尚, 无私的进程, 这就是 nice 的起源. 进程的 nice 可以通过命令nice, renice来进行调整, 前者在运行进程时设置, 后者对已启动的进程进行设置.

中断

硬中断–由硬件产生, 例如磁盘, 网卡, 键盘, 时钟, 所有的硬件都会将相应的 IRQ(中断请求)发送到对应硬件驱动上. 其中时钟中断会将当前运行的进程挂起, 从而运行其他代码, 常常用于 scheduler 调度器中. 整个硬中断过程: 硬件->CPU->内核驱动.
软中断–正在运行的程序发生的中断, 例如 IO 请求, Yield 请求, 软中断不会停止 CPU 运行, 但是会对当前进程或者代码产生一种逻辑中断. 整个软中断过程: 进程->内核驱动.

计算

top 命令简要信息输出:

1
2
3
4
5
top - 09:14:56 up 264 days, 20:56,  1 user,  load average: 0.02, 0.04, 0.00
Tasks: 87 total, 1 running, 86 sleeping, 0 stopped, 0 zombie
Cpu(s): 0.0%us, 0.2%sy, 0.0%ni, 99.7%id, 0.0%wa, 0.0%hi, 0.0%si, 0.2%st
Mem: 377672k total, 322332k used, 55340k free, 32592k buffers
Swap: 397308k total, 67192k used, 330116k free, 71900k cached

其中关于 CPU 命令字段的计算公式如下:

  • %us: (User Time + Nice Time) / CPU Time * 100%
  • %sy(内核): (System Time + Hard IRQ Time + Soft IRQ Time) / CPU Time * 100%
  • %id(空闲): (Idle Time) / CPU Time * 100%
  • %ni: (Nice Time) / CPU Time * 100%
  • %wa(IO): (Waiting Time) / CPU Time * 100%
  • %hi(硬中断): (Hard IRQ Time) / CPU Time * 100%
  • %si(软中断): (Soft IRQ Time) / CPU Time * 100%
  • %st: (Steal Time) / CPU Time * 100%

对于 CPU 占用率的计算公式, 不同于上面的计算公式, 一般会取一个时间跨度, 并读取/proc/stat中的数据, 最后取一个平均值, 其中 CPU 的更新频率:1/HZ秒更新一次. 时钟中断时会获取当前正在运行的进程信息, 所以, 如果在一个时钟周期内, 发生进程调度, 则 CPU 使用率可能不准确.

cpu 信息

taskset

用于设置或检索一个进程的 CPU 亲和性(affinity)的工具。其中 CPU 亲和率表示: 在 CMP 架构下, 能够将一个或多个进程绑定到一个或多个处理器上运行. taskset 的
基本语法如下:

1
2
3
4
5
# mask: 16进制,指定了进程可以运行的CPU核心。每个核心用一个位表示,1表示允许在该核心上运行,0表示不允许
taskset [options] mask command [argument...]

# -p表示设置或查询已经运行的进程的CPU亲和性
taskset [options] -p [mask] pid

例如:

1
2
3
4
5
6
7
8
# a. 启动新进程并在指定的cpu上运行
taskset 0x1 cmd

# b. 查看cpu的亲和度
taskset -p pid1

# c. 修改已运行进程的亲合度
taskset -p 0x1 pid

cpuinfo

/proc/cpuinfo存储 logical cpu 信息,注意这是一个虚拟文件,它在运行时由内核动态生成的,通过该文件可以查询到各种 CPU 信息。通过该文件可以获取硬件信息,例如制造商(vendor)、型号(model name)、核心数(cores)、处理器速度(CPU MHz)、缓存大小(cache size)等,下面是一些常用的 cpuinfo 信息查看命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 1. 查看物理CPU的个数, 虚拟机vmware中的processors值
cat /proc/cpuinfo |grep "physical id"|sort |uniq | wc -l
# 2. 查看逻辑CPU的个数, 此时可以查看cpuinfo文件, 看到某些processor可能有用相同的physical id
cat /proc/cpuinfo | grep "processor" | wc -l
# 3. 查看物理CPU是几核的, 如果有两个逻辑CPU具有相同的core id, 则表示当前CPU已经开启超线程技术, 此时cores一般为2
cat /proc/cpuinfo | grep "cores" | uniq
# 4. 查看CPU的主频
cat /proc/cpuinfo | grep MHz | uniq

# 5. 查看CPU型号
# 罗列所有的逻辑CPU:
cat /proc/cpuinfo | grep name
# 统计相同的CPU:
cat /proc/cpuinfo | grep name | cut -f2 -d: |uniq -c

# 6. 查看CPU位数
# 位数查看
getconf LONG_BT
# 判断32位即是否支持64:
cat /proc/cpuinfo | grep flags | grep "lm" | wc -l

lscpu

lscpu命令在 Linux 系统中用于显示有关 CPU 架构的详细信息,该命令从sysfs/proc/cpuinfo中读取并报告 CPU 相关的信息,包括 CPU 的数量、每个 CPU 的核心数、CPU 家族、型号、缓存大小等详细信息,相比 cpuinfo 使用更加方便。下面是 lscpu 命令的输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
[root@VM-16-12-opencloudos ~]# lscpu
架构: x86_64
CPU 运行模式: 32-bit, 64-bit
字节序: Little Endian
CPU: 2
在线 CPU 列表: 0,1
每个核的线程数: 1
每个座的核数: 2
座: 1
NUMA 节点: 1
厂商 ID: GenuineIntel
BIOS Vendor ID: Smdbmds
CPU 系列: 6
型号: 94
型号名称: Intel(R) Xeon(R) Gold 6133 CPU @ 2.50GHz
BIOS Model name: 3.0
步进: 3
CPU MHz: 2494.140
BogoMIPS: 4988.28
超管理器厂商: KVM
虚拟化类型: 完全
L1d 缓存: 32K
L1i 缓存: 32K
L2 缓存: 4096K
L3 缓存: 28160K
NUMA 节点0 CPU: 0,1
标记: ...

cpu 监控

CPU 的监控应用往往和 Memory 的监控关联, 具体的工具介绍, 见memory的说明. 在了解本篇文章之前, 需要先了解 CPU 中的一些术语, 以更好的关联整个 CPU 监控, 以及健康检查的标准。

另外,为了测试 CPU 的监控是否成功, 有时候需要手动将某一个 CPU 的使用率跑满(adjust cpu usage), 此时可以使用如下命令: dd if=/dev/zero of=/dev/null, 该情况对于单核机器可能会非常明显的效果, 多核机器会带来整体的 CPU 使用率一定的提升。

top

对 top 命令中关于 CPU 部分的字段说明, 其他信息见top中的说明, 其输出:

1
2
3
4
5
6
7
top - 09:14:56 up 264 days, 20:56,  1 user,  load average: 0.02, 0.04, 0.00
Tasks: 87 total, 1 running, 86 sleeping, 0 stopped, 0 zombie

Cpu(s): 0.0%us, 0.2%sy, 0.0%ni, 99.7%id, 0.0%wa, 0.0%hi, 0.0%si, 0.2%st

Mem: 377672k total, 322332k used, 55340k free, 32592k buffers
Swap: 397308k total, 67192k used, 330116k free, 71900k cached

其中 CPU 占比信息说明:

1
2
3
4
5
6
7
8
9
Cpu(s): 表示这一行显示CPU总体信息

0.0%us: 用户态进程占用CPU时间百分比, 不包含nice值为负的任务占用的CPU的时间.
0.7%sy: 内核占用CPU时间百分比
0.0%ni: 改变过优先级的进程占用CPU的百分比
99.3%id: 空闲CPU时间百分比
0.0%wa: 等待I/O的CPU时间百分比
0.0%hi: CPU硬中断时间百分比
0.0%si: CPU软中断时间百分比

这里显示数据是所有 cpu 的平均值, 如果想看每一个 cpu 的处理情况, 按 1 即可折叠, 再次按 1, 此时每一个进程输出的字段说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
PID: 进程的ID
PPID: 父进程的ID
USER: 进程所有者
UID: 进程所有者的用户ID
GROUP: 进程所有者的组名

PR: 进程的优先级别, 越小优先级越高
NI: nice
VIRT: 进程占用的虚拟内存
RES: 进程占用的物理内存
SHR: 进程使用的共享内存
S: 进程的状态. S表示休眠, R表示正在运行, Z表示僵死状态, N表示该进程优先值为负数

%CPU: 进程占用CPU的使用率
%MEM: 进程使用的物理内存和总内存的百分比
TIME+: 该进程启动后占用的总的CPU时间, 即占用CPU使用时间的累加值.
COMMAND: 进程启动命令名称

任务栏信息输出:

1
2
3
4
5
87 total: 很好理解, 就是当前有87个任务, 也就是87个进程.
1 running: 1个进程正在运行
86 sleeping: 86个进程睡眠
0 stopped: 停止的进程数
0 zombie: 僵死的进程数

python

  1. 获取 cpu precent
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class BasicMonitor(object):
def cpu(self):
"""cpu: 获取逻辑CPU数量, CPU使用率等"""
cpu_user = 0.0
cpu_system = 0.0
for _ in range(5):
p = psutil.cpu_times_percent()
if p.user > cpu_user:
cpu_user = p.user
if p.system > cpu_system:
cpu_system = p.system
time.sleep(0.5)
self.result['cpu'].update({
'cpu_count': psutil.cpu_count(),
'cpu_user': cpu_user,
'cpu_sys': cpu_system,
})

注意, psutil.cpu_times_percent中的 interval 为 0 或者 None 时, 其会对比上一次调用的 CPU 使用率或者导入 psutil 模块时的 CPU 使用率并立刻返回, 所以可能发生直接运行pstuil.cpu_time_percent为 0 的情况.