下图展示了这些术语之间的逻辑关系:
一个NUMA node包括一个或者多个Socket,以及与之相连的local memory。一个多核的Socket有多个Core。如果CPU支持HT,OS还会把这个Core看成 2个Logical Processor。为了避免混淆,在下文中统一用socket指代Processor or Socket;为了偷懒,下文中用Processor指代Logical Processor,击键能省则省不是。
查看CPU Topology
本文以笔者能访问的某台Red Hat Enterprise Linux Server release 5.4为例介绍,其他系统请自行google。
NUMA Node
第一种方法使用numactl查看
numactl –hardware
1
2
3
4
5
6
7
8
9
|
available: 2 nodes (0-1) //当前机器有2个NUMA node,编号0&1
node 0 size: 12091 MB //node 0 物理内存大小
node 0 free : 988 MB //node 0 当前free内存大小
node 1 size: 12120 MB node 1 free : 1206 MB
node distances: //node 距离,可以简单认为是CPU本node内存访问和跨node内存访问的成本。从下表可知跨node的内存访问成本(20)是本地node内存(10)的2倍。
node 0 1 0: 10 20
1: 20 10
|
第二种方法是通过sysfs查看,这种方式可以查看到更多的信息
ls /sys/devices/system/node/
1
|
node0 node1 //两个目标表示本机有2个node,每个目录内部有多个文件和子目录描述node内cpu,内存等信息。比如说node0/meminfo描述了node0内存相关信息。
|
Socket
可以直接通过/proc/cpuinfo查看,cpuinfo里的physical id描述的就是Socket的编号,
cat /proc/cpuinfo|grep “physical id”
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
] physical id : 0 physical id : 0 physical id : 0 physical id : 0 physical id : 1 physical id : 1 physical id : 1 physical id : 1 physical id : 0 physical id : 0 physical id : 0 physical id : 0 physical id : 1 physical id : 1 physical id : 1 physical id : 1 |
由上可知本机有2个Socket,编号为0和1。
还可以简单的使用如下命令直接查看Socket个数
cat /proc/cpuinfo|grep “physical id”|sort -u|wc –l
1
|
2 //本机有2个物理CPU封装
|
Core
仍然是可以通过/proc/cpuinfo查看,cpuinfo中跟core相关的信息有2行。
cpu cores : 4 //一个socket有4个核,
core id : 1 //一个core在socket内的编号
通过如下命令可以直接查看core的数量
cat /proc/cpuinfo |grep “cpu cores”|uniq|cut -d: -f2
1
|
4 //1个socket有4个core
|
本机有2个socket,每个有4个core,所以一共有8个core
还可以查看core在Socket里的编号
cat /proc/cpuinfo|grep “core id”|sort -u
1
2
3
4
|
core id : 0 core id : 1 core id : 10 core id : 9 |
一个socket里面4个core的编号为0,1,9,10。是的,core id是不连续的。如果谁知道为啥麻烦通知我,先谢了。
Logical Processor
仍然是可以通过/proc/cpuinfo查看在OS的眼里有多少个Logical Processor
ls /sys/devices/system/cpu/cpu0/cache/
1
|
index0 index1 index2 index3 |
4个目录
index0:1级数据cache
index1:1级指令cache
index2:2级cache
index3:3级cache ,对应cpuinfo里的cache
目录里的文件是cache信息描述,以本机的cpu0/index0为例简单解释一下:
文件 | 内容 | 说明 |
type | Data | 数据cache,如果查看index1就是Instruction |
Level | 1 | L1 |
Size | 32K | 大小为32K |
coherency_line_size | 64 | 64*4*128=32K|
physical_line_partition | 1 | |
ways_of_associativity | 4 | |
number_of_sets | 128 | |
shared_cpu_map | 00000101 | 表示这个cache被CPU0和CPU8 share |
解释一下shared_cpu_map内容的格式:
表面上看是2进制,其实是16进制表示,每个bit表示一个cpu,1个数字可以表示4个cpu
截取00000101的后4位,转换为2进制表示
CPU id | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
0×0101的2进制表示 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
0101表示cpu8和cpu0,即cpu0的L1 data cache是和cpu8共享的。
验证一下?
cat /sys/devices/system/cpu/cpu8/cache/index0/shared_cpu_map
00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000101
再看一下index3 shared_cpu_map的例子
cat /sys/devices/system/cpu/cpu0/cache/index3/shared_cpu_map
00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000f0f
CPU id | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
0x0f0f的2进制表示 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 |
cpu0,1,2,3和cpu8,9,10,11共享L3 cache
小结
抱歉,图比较大,网页上看不清楚,下面放大单node图,另一个node基本上可以类推。
使用CPU Topology
好吧,现在我们知道了如何查看CPU topology。那么这与各位攻城狮的工作有什么关系呢?
以淘宝搜索常见的服务模型为例,服务端把离线处理的数据load到内存中,开始监听某个服务端口,接收到客户端请求后从线程池中分配一个工作线程,该线程解析请求,读取内存中对应的数据,进行一些计算,然后把结果返回给客户端。
把这个过程简化简化再简化,抽象抽象再抽象,可以得到一个简单的测试程序,程序流程为:
1. 主线程申请2块256M的内存,使用memset初始化这两块内存的每个byte
2. 启动2个子线程,每个线程内循环16M次,在每次循环中随机读取2块内存中的各1K数据,对每个byte进行简单加和,返回。
3. 主线程等待子线程结束,打印每个线程的结果,结束。
使用-O2编译出可执行文件test,分别使用下面2个命令运行该程序。运行时间和机器配置以及当前load有关,绝对值没有意义,这里仅比较相对值。
命令 | time ./test | time numactl -m 0 –physcpubind=2,3 ./test |
用时 |
real 0m38.678s user 1m6.270s sys 0m5.569s |
real 0m28.410s user 0m54.997s sys 0m0.961s |
发生了什么?为什么有这么大的差异?
第一个命令直观,那么我们看一下第二个命令具体做了什么:
numactl -m 0 –physcpubind=2,3 ./test
-m 0:在node 0上分配内存
–physcpubind=2,3:在cpu 2和3上运行程序,即一个线程运行在cpu2上,另一个运行在cpu3上。
参考上面的CPUtopology图就很容易理解了,由于线程绑定cpu2和3执行,共享了L3 cache,且全部内存都是本node访问,运行效率自然比随机选择cpu运行,运行中还有可能切换cpu,内存访问有可能跨node的第一种方式要快了。
接下来,让我们看看完整的表格,读者可以看看有没有惊喜:
情况 | 命令 | 用时 | 解释 |
完全由OS控制 | time ./test | real 0m38.678s user 1m6.270s sys 0m5.569s |
乐观主义者,甩手掌柜型 |
绑定跨node的Cpu执行 | time numactl –physcpubind=2,6 ./test | real 0m38.657s user 1m7.126s sys 0m5.045s |
Cpu 2和6不在同一个node,不能share L3 cache |
绑定单node的Cpu执行 | time numactl –physcpubind=2,3 ./test | real 0m28.605s user 0m55.161s sys 0m0.856s |
Cpu 2和3在同一个node,share L3 cache。内存使用由OS控制,一般来说node 0和1内存都会使用。 |
跨node内存访问+绑定单node CPU执行 | time numactl -m 1 –physcpubind=2,3 ./test | real 0m33.218s user 1m4.494s sys 0m0.911s |
内存全使用node1,2个cpu在node0,内存访问比较吃亏 |
单node内存访问+绑定本node CPU执行 | time numactl -m 0 –physcpubind=2,3 ./test | real 0m28.367s user 0m55.062s sys 0m0.825s |
内存&cpu都使用node0 |
单node内存访问+绑定本node 单core执行 | time numactl -m 0 –physcpubind=2,10 ./test | real 0m58.062s user 1m55.520s sys 0m0.270s |
CPU2和10不但在同一个node,且在同一个core,本意是希望共享L1,L2cache,提升性能。但是不要忘了,CPU2和10是HT出来的logical Processor,在本例cpu密集型的线程中硬件争用严重,效率急剧下降。有没有发现和上一个case的时间比率很有意思? |
现在谁还能说了解点cpu topology没用呢?☺
Tips
补充几个小tips,方便有兴趣的同学分析上面表格的各个case
1.查看进程的内存numa node分布
简单的说可以查看进程的numa_maps文件
cat /proc//numa_maps
文件格式可以直接:man numa_maps
为了避免输入数字pid,我使用如下命令查看:
cat /proc/$(pidof test|cut –d” ” -f1)/numa_maps
2.查看线程run在哪个processor
可以使用top命令查看一个进程的各个线程分别run在哪个processor上
同样,为了避免输入数字pid,我使用如下命令启动top:
top -p$(pidof test |sed -e ‘s/ /,/g’)
在默认配置下不显示线程信息,需要进入Top后按“shift+H”,打开线程显示。
另外,如果没有P列,还需要按“f”,按“j”,添加,这一列显示的数字就是这个线程上次run的processor id。
关于top的使用,请读者自行man top
3.另一种绑定cpu执行的方法
如果读者的程序不涉及大量内存的访问,可以通过taskset绑定cpu执行。别怪我没提醒你,仔细判断是否应该绑定到同一个core的processor上哦。
关于命令的使用,请读者自行Man taskset
相关推荐
《对称多处理器系统CPU转换机制研究》这篇文章探讨了在对称多处理器系统(Symmetrical Multiprocessing, SMP)中的CPU转换机制,这是提高计算机性能的关键技术之一。文章着重研究了如何在多处理器环境下,通过CPU的...
最近将Pytorch程序迁移到GPU上去的一些工作和思考 环境:Ubuntu 16.04.3 Python版本:3.5.2 Pytorch版本:0.4.0 0. 序言 大家知道,在深度学习中使用GPU来对模型进行训练是可以通过并行化其计算来提高运行效率,这里...
计算机组成原理是理解计算机系统内部工作机制的关键领域,它涵盖了数据表示、运算器设计、存储系统、指令系统、中央处理器(CPU)结构等核心概念。本主题聚焦于将一个16位的CPU转换为8位的CPU,这是一个涉及到计算...
Figure out if your node process is blocked because the CPU is spinning and exit the program with a stack trace if that is the case
在计算机科学领域,CPU(中央处理器)的设计是至关重要的,因为它负责执行计算机程序中的指令。在本主题中,我们关注的是“16位流水式CPU设计”,这是一个涉及到计算机体系结构的高级话题。流水线技术是一种优化CPU...
对于Intel 7代CPU(例如i5-7500或i7-7700等)来说,安装适合的Win7系统集成显卡驱动是确保计算机性能和稳定性不可或缺的步骤。在Windows 7操作系统上,由于微软已经停止了对新硬件的官方支持,所以可能会遇到一些...
当一个进程在规定的时间片内未完成执行,它会被强制暂停,CPU转而分配给下一个等待的进程。这种策略避免了某个进程长时间独占CPU而导致其他进程无法运行的情况。 2. 时间片基本原理: 早期的时间片轮转法采用了先来...
标题“CPU 315T-2DP编程手册”指明了文档是针对特定型号的工业自动化控制器CPU 315T-2DP的编程指南。描述部分重复了标题内容,而标签“CPU 315T”进一步确认了文档的焦点是CPU 315T系列的技术细节。虽然提供了文档的...
【市场转移】全球半导体市场的焦点正逐渐从中央处理器(CPU)转向应用处理器(Application Processor,AP),这主要是由于智能设备的快速增长,尤其是智能手机和平板电脑的市场需求。智能设备的出货量预计将在2015年...
当时间片耗尽,进程返回到就绪队列的末尾,而CPU转给下一个进程。如果所有进程均已完成,调度结束。 设计原理: 时间片轮转算法的基本思想是,将所有就绪进程放入一个队列,每次调度时,分配给队首进程一定时间...
操作系统概论复习大纲,每个章节的重点知识以及各种例题
该CPU采用8位地址总线,每个进程拥有128K地址空间,其中包括32个2K的数据页和32个2K的代码页,这些地址影射到22位的物理地址空间中,如果算上外部设备的地址空间就是23位物理地址空间。 怎么样?够强的吧?这还...
《CpuUsage:掌握CPU利用率动态曲线图》 在计算机性能监控中,了解CPU的利用率是至关重要的。CpuUsage工具就是为此目的而设计的,它能够实时地展示CPU利用率的动态曲线图,类似于Windows的任务管理器。这篇文章将...
《FRABA绝对旋转式编码器在CPU 315中的应用示例》 在工业自动化领域,编码器是至关重要的传感器设备,它们用于检测机械位置、速度和角速度等参数。FRABA公司作为编码器技术的领先者,其绝对旋转式编码器在业界享有...
在计算机科学领域,CPU(中央处理器)是计算机系统的核心组件,负责执行指令和处理数据。本次我们探讨的主题是“16位CPU到8位CPU的改造”,这是一个涉及到计算机组成原理和技术转换的实践性项目。从16位系统转向8位...
在电子工程领域,CPU(中央处理器)是计算机系统的核心组件,负责执行指令并控制硬件操作。本主题将深入探讨如何使用Altera公司的Quartus II软件进行CPU的设计。Quartus II是一款强大的FPGA(现场可编程门阵列)开发...
"Delphi CPU占用率"这个话题正是关注这样一个关键指标:一个由Delphi编写的程序在运行时如何影响系统的中央处理器(CPU)资源。Delphi是一种强大的对象 Pascal 编程语言和集成开发环境(IDE),用于构建高性能的...