[转载] 玩转CPU Topology(NUMA、SMP、Socket、physical Processor、Core、Logical Processor、Cache)

本文详细介绍了CPU拓扑结构的概念,包括NUMA节点、Socket、Core及Logical Processor等,并提供了在Linux环境下查看这些信息的具体方法。同时,文章还通过一个具体的例子展示了如何利用CPU拓扑信息来优化程序性能。
摘要由CSDN通过智能技术生成

转载自:http://www.searchtb.com/2012/12/玩转cpu-topology.html

传世佳作,受益匪浅啊!

先温习几个概念

请原谅对部分术语笔者直接引用了wikipedia上的英文解释,因为哥实在做不到比wikipedia上更准确描述。我会试着解释部分的术语,并在本节的最后梳理一下这些术语之间的关系。注意,笔者对由于不准确的描述导致的性能下降,进程crash等任何问题不承担任何责任☺
NUMA:Non-Uniform Memory Access (NUMA) is a computer memory design used in multiprocessing, where the memory access time depends on the memory location relative to a processor. Under NUMA, a processor can access its own local memory faster than non-local memory, that is, memory local to another processor or memory shared between processors.NUMA architectures logically follow in scaling from symmetric multiprocessing (SMP) architectures.
提到NUMA就不能不对比SMP,
SMP:Symmetric multiprocessing (SMP) involves a multiprocessor computer hardware architecture where two or more identical processors are connected to a single shared main memory and are controlled by a single OS instance.
说了这么多其实都是为了介绍NUMA Node:
A fairly technically correct and also fairly ugly definition of a node is: a region of memory in which every byte has the same distance from each CPU.
A more common definition is: a block of memory and the CPUs, I/O, etc. physically on the same bus as the memory.
CPU:这个不解释,原因你懂得。
想当年CPU拼的是频率,频率越高越NB,但是提升频率和制程密切相关。
Intel cpu制程
但是制程这玩意有一个物理天花板,提升越来越难,有报道指出,现阶段普遍应用的硅晶体管在尺寸上有一个10nm的物理极限。为了提升性能cpu走上了多核的道路,即在一个封装(socket或者processor)里放多个core。这还不够,又发明了超线程技术Hyper-threading
HT:HT Technology is used to improve parallelization of computations (doing multiple tasks at once) performed on PC microprocessors. For each processor core that is physically present, the operating system addresses two virtual or logical cores, and shares the workload between them when possible. They appear to the OS as two processors, thus the OS can schedule two processes at once. 一个core 在HT之后OS看到的就是2个Logical Processor
下图展示了这些术语之间的逻辑关系:
cpu 概念逻辑关系
一个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
//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
cat /proc/cpuinfo |grep processor|wc –l

1
 

Ok,8个core变成了16个Logical Processor,所以本机开启了HT。
问题来了,cpuinfo里面16个Processor编号为0-15,Core的id为0,1,9,10,Socket的id为0,1。这些编号是如何对应的呢?
我们查看一个Processor完整的cpuinfo就比较清楚了,我剔除了不相关的行:

processor : 0processor : 5
physical id : 0
siblings : 8
core id : 0
cpu cores : 4
physical id : 1
siblings : 8
core id : 1
cpu cores : 4

明白了?
Processor 0:在socket 0的core 0 里。
Processor 5:在socket 1的core 1 里。

Cache

仍然可以通过/proc/cpuinfo查看,OMG, cpuinfo难道是万能的?

1
2
3
processor       : 0
cache size      : 12288 KB //cpu cache 大小
cache_alignment : 64 

问题又来了,我们知道CPU cache分为L1,L2,L3, L1一般还分为独立的指令cache和数据cache。Cpuinfo里这个cache size指的是?

好吧,cpuinfo也不是万能的。详细的cache信息可以通过sysfs查看
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为例简单解释一下:

文件内容说明
typeData数据cache,如果查看index1就是Instruction
Level1L1
Size32K大小为32K
coherency_line_size64 64*4*128=32K
physical_line_partition1
ways_of_associativity4
number_of_sets128
shared_cpu_map00000101表示这个cache被CPU0和CPU8 share

解释一下shared_cpu_map内容的格式:
表面上看是2进制,其实是16进制表示,每个bit表示一个cpu,1个数字可以表示4个cpu
截取00000101的后4位,转换为2进制表示

CPU id1514131211109876543210
0×0101的2进制表示0000000100000001

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 id1514131211109876543210
0x0f0f的2进制表示0000111100001111

cpu0,1,2,3和cpu8,9,10,11共享L3 cache

小结

综合以上信息可以绘制出以下的cpu topology图:
cpu topology

抱歉,图比较大,网页上看不清楚,下面放大单node图,另一个node基本上可以类推。
cpu topology 1 node

使用CPU Topology

好吧,现在我们知道了如何查看CPU topology。那么这与各位攻城狮的工作有什么关系呢?

以淘宝搜索常见的服务模型为例,服务端把离线处理的数据load到内存中,开始监听某个服务端口,接收到客户端请求后从线程池中分配一个工作线程,该线程解析请求,读取内存中对应的数据,进行一些计算,然后把结果返回给客户端。
把这个过程简化简化再简化,抽象抽象再抽象,可以得到一个简单的测试程序,程序流程为:
1. 主线程申请2块256M的内存,使用memset初始化这两块内存的每个byte
2. 启动2个子线程,每个线程内循环16M次,在每次循环中随机读取2块内存中的各1K数据,对每个byte进行简单加和,返回。
3. 主线程等待子线程结束,打印每个线程的结果,结束。
使用-O2编译出可执行文件test,分别使用下面2个命令运行该程序。运行时间和机器配置以及当前load有关,绝对值没有意义,这里仅比较相对值。

命令time ./testtime 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 ./testreal 0m38.678s
user 1m6.270s
sys 0m5.569s
乐观主义者,甩手掌柜型
绑定跨node的Cpu执行time numactl –physcpubind=2,6 ./testreal 0m38.657s
user 1m7.126s
sys 0m5.045s
Cpu 2和6不在同一个node,不能share L3 cache
绑定单node的Cpu执行time numactl –physcpubind=2,3 ./testreal 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 ./testreal 0m33.218s
user 1m4.494s
sys 0m0.911s
内存全使用node1,2个cpu在node0,内存访问比较吃亏
单node内存访问+绑定本node CPU执行time numactl -m 0 –physcpubind=2,3 ./testreal 0m28.367s
user 0m55.062s
sys 0m0.825s
内存&cpu都使用node0
单node内存访问+绑定本node 单core执行time numactl -m 0 –physcpubind=2,10 ./testreal 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


以下为简单版

======================我是分割线===============================


转载自:http://blog.csdn.net/dba_waterbin/article/details/8644626


㈠ 概念
           
           ① 物理CPU
 
              
              实际Server中插槽上的CPU个数
              物理cpu数量,可以数不重复的 physical id 有几个
           
           ② 逻辑CPU 
              
              Linux用户对 /proc/cpuinfo 这个文件肯定不陌生. 它是用来存储cpu硬件信息的
              信息内容分别列出了processor 0 – n 的规格。这里需要注意,如果你认为n就是真实的cpu数的话, 就大错特错了
              一般情况,我们认为一颗cpu可以有多核,加上intel的超线程技术(HT), 可以在逻辑上再分一倍数量的cpu core出来
              逻辑CPU数量=物理cpu数量 x cpu cores 这个规格值 x 2(如果支持并开启ht)
              备注一下:Linux下top查看的CPU也是逻辑CPU个数
              
           ③ CPU核数
           
              一块CPU上面能处理数据的芯片组的数量、比如现在的i5 760,是双核心四线程的CPU、而 i5 2250 是四核心四线程的CPU
              
           一般来说,物理CPU个数×每颗核数就应该等于逻辑CPU的个数,如果不相等的话,则表示服务器的CPU支持超线程技术 
           
       ㈡ 查看CPU信息
          
          当我们 cat /proc/cpuinfo 时、
          具有相同core id的CPU是同一个core的超线程
          具有相同physical id的CPU是同一个CPU封装的线程或核心
              
        
       ㈢ 下面举例说明
     

        ① 查看物理CPU的个数

[plain]  view plain  copy
 print ?
  1. #cat /proc/cpuinfo |grep "physical id" | sort | uniq | wc -l  
  2. 2  

        ② 查看逻辑CPU的个数

[plain]  view plain  copy
 print ?
  1. #cat /proc/cpuinfo | grep "processor" | wc -l
  2. 24  

        ③ 查看每个CPU是几核

[plain]  view plain  copy
 print ?
  1. #cat /proc/cpuinfo | grep "cpu cores" | uniq
  2. 6   

       我这里应该是2个Cpu,每个Cpu有6个core,应该是Intel的U,支持超线程,所以显示24。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值