欢迎您访问第A百科网

Linux中CPU亲和性(affinity)

47次浏览     发布时间:2024-01-25 09:07:36     编辑: 布道师Peter

1、Perface

今天来聊聊亲和力,在这之前我们想比都听说过超线程。

超线程技术(Hyper-Threading): 就是利用特殊的硬件指令,把两个逻辑内核(CPU core)模拟成两个物理芯片,(一个核模拟出两个核?)

尽管提高CPU的时钟频率和增加缓存容量后的确可以改善CPU性能,但这样的CPU性能提高在技术上存在较大的难度。实际上在应用中基于很多原因,CPU的执行单元都没有被充分使用。如果CPU不能正常读取数据(总线/内存的瓶颈),其执行单元利用率会明显下降。另外就是目前大多数执行线程缺乏ILP(Instruction-Level Parallelism,多种指令同时执行)支持。这些都造成了目前CPU的性能没有得到全部的发挥。

因此,Intel则采用另一个思路去提高CPU的性能,让CPU可以同时执行多重线程,就能够让CPU发挥更大效率,即所谓“超线程(Hyper-Threading,简称“HT”)”技术。超线程技术就是利用特殊的硬件指令,把两个逻辑内核模拟成两个物理芯片,让单个处理器都能使用线程级并行计算,进而兼容多线程操作系统和软件,减少了CPU的闲置时间,提高的CPU的运行效率。

  • • CPU:主板插槽上 cpu芯片的个数

  • • 物理内核:嵌在cpu芯片上的处理器,一个cpu可以有多个内核,其id都不一样

  • • 逻辑内核:通过超线程技术,能将一个物理核分成多个逻辑核,也就是代码层面的多线程技术

单个处理器都能使用线程级并行计算,进而兼容多线程操作系统和软件,减少了CPU的闲置时间,提高的CPU的运行效率。

我们常听到的双核四线程/四核八线程指的就是支持超线程技术的CPU.

物理CPU: 机器上安装的实际CPU, 比如说你的主板上安装了一个8核CPU,那么物理CPU个数就是1个,所以物理CPU个数就是主板上安装的CPU个数。

逻辑CPU: 一般情况,我们认为一颗CPU可以有多核,加上intel的超线程技术(HT), 可以在逻辑上再分一倍数量的CPU core出来;

逻辑CPU数量 = 物理CPU数量 x CPU cores x 2(如果支持并开启HT)

前提是CPU的型号一致,如果不一致只能一个一个的加起来,不用直接乘以物理CPU数量

比如你的电脑安装了一块4核CPU,并且支持且开启了超线程(HT)技术,那么逻辑CPU数量 = 1 × 4 × 2 = 8

  • • Linux下查看CPU相关信息, CPU的信息主要都在/proc/cupinfo中,

# 查看物理CPU个数
cat /proc/cpuinfo|grep "physical id"|sort -u|wc -l

# 查看每个物理CPU中core的个数(即核数)
cat /proc/cpuinfo|grep "cpu cores"|uniq

# 查看逻辑CPU的个数
cat /proc/cpuinfo|grep "processor"|wc -l

# 查看CPU的名称型号
cat /proc/cpuinfo|grep "name"|cut -f2 -d:|uniq
  • • Linux查看某个进程运行在哪个逻辑CPU上ps -eo pid,args,psr#参数的含义:
    pid - 进程ID
    args - 该进程执行时传入的命令行参数
    psr - 分配给进程的逻辑CPU例子:[~]# ps -eo pid,args,psr | grep nginx9073 nginx: master process /usr/ 19074 nginx: worker process 09075 nginx: worker process 19076 nginx: worker process 29077 nginx: worker process 313857 grep nginx 3

  • • Linux查看线程的TID

    • • TID就是Thread ID,他和POSIX中pthread_t表示的线程ID完全不是同一个东西.

    • • Linux中的POSIX线程库实现的线程其实也是一个轻量级进程(LWP),这个TID就是这个线程的真实PID.

    • • 但是又不能通过getpid()函数获取,Linux中定义了gettid()这个接口,但是通常都是未实现的,所以需要使用下面的方式获取TID。


//program
#include <sys/syscall.h>
pid_t tid;
tid = syscall(__NR_gettid);// or syscall(SYS_gettid)

//command-line 3种方法(推荐第三种方法)
(1)ps -efL | grep prog_name
(2)ls /proc/pid/task //文件夹名即TID(3)ps -To 'pid,lwp,psr,cmd' -p PID

基于上述背景之下,我们来学习一下什么是CPU亲和力

CPU亲和性(亲和力)

概念

CPU affinity 是一种调度属性(scheduler property), 它可以将一个进程"绑定" 到一个或一组CPU上.

在SMP(Symmetric Multi-Processing对称多处理)架构下,Linux调度器(scheduler)会根据CPU affinity的设置让指定的进程运行在"绑定"的CPU上,而不会在别的CPU上运行.

Linux调度器同样支持自然CPU亲和性(natural CPU affinity): 调度器会试图保持进程在相同的CPU上运行, 这意味着进程通常不会在处理器之间频繁迁移,进程迁移的频率小就意味着产生的负载小。

因为程序的作者比调度器更了解程序,所以我们可以手动地为其分配CPU核,而不会过多地占用CPU0,或是让我们关键进程和一堆别的进程挤在一起,所有设置CPU亲和性可以使某些程序提高性能。

表示方法

CPU affinity 使用位掩码(bitmask)表示, 每一位都表示一个CPU, 置1表示"绑定".

最低位表示第一个逻辑CPU, 最高位表示最后一个逻辑CPU.

CPU affinity典型的表示方法是使用16进制,具体如下.

0x00000001
is processor #0

0x00000003
is processors #0 and #1

0xFFFFFFFF
is all processors (#0 through #31)

taskset命令

taskset命名用于获取或者设定CPU亲和性.

# 命令行形式
taskset [options] mask command [arg]...taskset [options] -p [mask] pidPARAMETER mask : cpu亲和性,当没有-c选项时, 其值前无论有没有0x标记都是16进制的, 当有-c选项时,其值是十进制的. command : 命令或者可执行程序 arg : command的参数 pid : 进程ID,可以通过ps/top/pidof等命令获取

OPTIONS -a, --all-tasks (旧版本中没有这个选项) 这个选项涉及到了linuxTID的概念,他会将一个进程中所有的TID都执行一次CPU亲和性设置. TID就是Thread ID,他和POSIXpthread_t表示的线程ID完全不是同一个东西. Linux中的POSIX线程库实现的线程其实也是一个进程(LWP),这个TID就是这个线程的真实PID.
-p, --pid
操作已存在的PID,而不是加载一个新的程序
-c, --cpu-list
声明CPU的亲和力使用数字表示而不是用位掩码表示. 例如 0,5,7,9-11.
-h, --help
display usage information and exit
-V, --version
output version information and exit
USAGE
1) 使用指定的CPU亲和性运行一个新程序
taskset [-c] mask command [arg]...
举例:使用CPU0运行ls命令显示/etc/init.d下的所有内容
taskset -c 0 ls -al /etc/init.d/
2) 显示已经运行的进程的CPU亲和性
taskset -p pid
举例:查看init进程(PID=1)的CPU亲和性
taskset -p 1
3) 改变已经运行进程的CPU亲和力
taskset -p[c] mask pid
举例:打开2个终端,在第一个终端运行top命令,第二个终端中
首先运行:[~]# ps -eo pid,args,psr | grep top #获取top命令的pid和其所运行的CPU
其次运行:[~]# taskset -cp 新的CPUpid #更改top命令运行的CPU
最后运行:[~]# ps -eo pid,args,psr | grep top #查看是否更改成功
PERMISSIONS 一个用户要设定一个进程的CPU亲和性,如果目标进程是该用户的,则可以设置,如果是其他用户的,则会设置失败,提示 Operation not permitted.当然root用户没有任何限制.
任何用户都可以获取任意一个进程的CPU亲和性.

taskset命令其实就是使用sched_getaffinity()和sched_setaffinity()接口实现的,相信看完了第3节你也能自己实现一个taskset命令.

有兴趣的可以看一下其源代码:ftp://ftp.kernel.org/pub/linux/utils/util-linux/vX.YZ/util-linux-X.YZ-xxx.tar.gz /schedutils/taskset.c

编程API

下面是用用于设置和获取CPU亲和性相关的API.

#define _GNU_SOURCE
#include <sched.h>
#include <pthread.h> //for pthread functions(last 4) 注意<pthread.h>包含<sched.h>

/* MACRO */
/* The following macros are provided to operate on the CPU set set */
/* Clears set, so that it contains no CPUs */
void CPU_ZERO(cpu_set_t *set);
void CPU_ZERO_S(size_t setsize, cpu_set_t *set);

/* Add CPU cpu to set */
void CPU_SET(int cpu, cpu_set_t *set);
void CPU_SET_S(int cpu, size_t setsize, cpu_set_t *set);

/* Remove CPU cpu from set */
void CPU_CLR(int cpu, cpu_set_t *set);
void CPU_CLR_S(int cpu, size_t setsize, cpu_set_t *set);

/* Test to see if CPU cpu is a member of set */
int CPU_ISSET(int cpu, cpu_set_t *set);
int CPU_ISSET_S(int cpu, size_t setsize, cpu_set_t *set);

/* Return the number of CPUs in set */
void CPU_COUNT(cpu_set_t *set);
void CPU_COUNT_S(size_t setsize, cpu_set_t *set);

/* The following macros perform logical operations on CPU sets */
/* Store the logical AND of the sets srcset1 and srcset2 in destset (which may be one of the source sets). */
void CPU_AND(cpu_set_t *destset, cpu_set_t *srcset1, cpu_set_t *srcset2);
void CPU_AND_S(size_t setsize, cpu_set_t *destset, cpu_set_t *srcset1, cpu_set_t *srcset2);

/* Store the logical OR of the sets srcset1 and srcset2 in destset (which may be one of the source sets). */
void CPU_OR(cpu_set_t *destset, cpu_set_t *srcset1, cpu_set_t *srcset2);
void CPU_OR_S(size_t setsize, cpu_set_t *destset, cpu_set_t *srcset1, cpu_set_t *srcset2);

/* Store the logical XOR of the sets srcset1 and srcset2 in destset (which may be one of the source sets). */
void CPU_XOR(cpu_set_t *destset, cpu_set_t *srcset1, cpu_set_t *srcset2);
void CPU_XOR_S(size_t setsize, cpu_set_t *destset, cpu_set_t *srcset1, cpu_set_t *srcset2);

/* Test whether two CPU set contain exactly the same CPUs. */
int CPU_EQUAL(cpu_set_t *set1, cpu_set_t *set2);
int CPU_EQUAL_S(size_t setsize, cpu_set_t *set1, cpu_set_t *set2);

/* The following macros are used to allocate and deallocate CPU sets: */
/* Allocate a CPU set large enough to hold CPUs in the range 0 to num_cpus-1 */
cpu_set_t *CPU_ALLOC(int num_cpus);

/* Return the size in bytes of the CPU set that would be needed to hold CPUs in the range 0 to num_cpus-1.
This macro provides the value that can be used for the setsize argument in the CPU_*_S() macros */
size_t CPU_ALLOC_SIZE(int num_cpus);

/* Free a CPU set previously allocated by CPU_ALLOC(). */
void CPU_FREE(cpu_set_t *set);

/* API */
/* Set the CPU affinity for a task */
int sched_setaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask);
/* Get the CPU affinity for a task */
int sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask);

/* set CPU affinity attribute in thread attributes object */
int pthread_attr_setaffinity_np(pthread_attr_t *attr, size_t cpusetsize, const cpu_set_t *cpuset);
/* get CPU affinity attribute in thread attributes object */
int pthread_attr_getaffinity_np(const pthread_attr_t *attr, size_t cpusetsize, cpu_set_t *cpuset);

/* set CPU affinity of a thread */
int pthread_setaffinity_np(pthread_t thread, size_t cpusetsize, const cpu_set_t *cpuset);
/* get CPU affinity of a thread */
int pthread_getaffinity_np(pthread_t thread, size_t cpusetsize, cpu_set_t *cpuset);

相关的宏通常都分为2种,一种是带_S后缀的,一种不是不带_S后缀的, 从声明上看带_S后缀的宏都多出一个参数 setsize.

从功能上看他们的区别是带_S后缀的宏是用于操作动态申请的CPU set(s),所谓的动态申请其实就是使用宏 CPU_ALLOC 申请,

参数setsize 可以是通过宏 CPU_ALLOC_SIZE 获得,两者的用法详见下面的例子.

相关的API只有6个, 前2个是用来设置进程的CPU亲和性,需要注意的一点是,当这2个API的第一个参数pid为0时,表示使用调用进程的进程ID;

后4个是用来设置线程的CPU亲和性。其实sched_setaffinity()也可以用来设置线程的CPU的亲和性,也就是taskset “-a”选项中提到的TID概念。


小结

上次看见这个亲和力的这个词语是在系统的日志信息,还挺纳闷的这个是什么?绑定确实是一个不错的解释。感谢前辈的文章,原文还有四个栗子,这里就不贴出来了。需要了可以点击原文查看。

相关文章

教你冰糖炖猪蹄正确做法,好吃到停不下筷子

用料猪蹄 一个生抽 3勺老抽 2勺料酒 3勺香叶 2片桂皮 1片盐 少许生姜 3片八角 2个干辣椒 3个冰糖 30g做法步骤1、准备所需食材调料~ 猪蹄洗净剁开,用开水焯一下,洗去浮沫备用~2、把所有调料放入锅内,倒入所需的生抽老抽料酒等~3、猪蹄放入,加入与猪蹄齐平的水~4、盖上锅盖~打开米家智能

2024-11-23 09:30

羊血怎么做好吃? 别直接下锅,经验诀窍教给你,羊血滑嫩入味,不腥不膻

前几天带孩子去医院体检,最后结果是缺铁又缺钙,难怪平时孩子脸色发黄,医生说是缺铁性贫血,尤其是长期缺铁要让我们重视,因为日积月累下去会影响孩子智力发展。除了开了补铁剂之外,还让孩子多吃动物肝脏、血以及红肉(猪瘦肉、牛肉等)即可,动物血补血气最好了,但是不能天天吃,今天就把一道葱烧羊血分享给大家。至于

2024-11-23 09:15

怎么撩女生撩到脸红?方法在这里!

自古深情留不住,没有套路难能得人心。开玩笑,真诚还是要的,套路也不能滥用,但是想撩到女生,会几句撩妹技巧还是很加分的。第一句,要是看到喜欢的女生在一条很干净平坦的路上走,你就一本正经地说:小心滑倒,这时她应该会纳闷地看着你,接着你就说:因为我的心已经为你融化了,怕你滑倒。第二句,“遇到你之后我就变得

2024-11-23 09:01

金鱼吊兰花的寓意是什么?你养过吗?

金鱼吊兰是一种很喜庆的植物,它的花语和寓意,一个是做事情不放弃,坚持到底,生生不息;另一个是相亲相爱,相互扶持。美丽的金鱼吊兰代表着美好的祝福,它可以用来送家人、朋友、来表示对方生活能够更美好的诚挚祝福,含有一种浓烈的感情色彩。花语和寓意做事情不放弃,坚持到底:金鱼吊兰的花朵是金黄色的,在开花的时候

2024-11-23 08:46

香辣羊蹄的做法和配方分享给你,速来围观!

羊蹄100个香料包,香叶10克,桂皮10克,花椒5克,肉蔻5克,白豆蔻三克。调料,葱段220克,姜块50克(葱段200克,姜块50克为卤羊蹄用),麻辣火锅底料10克,蒜泥10克,胡麻油30克,干辣椒5克,辣椒面5克,鸡精5克,酱油50克,醋20克,红椒块20克,盐5克,葱花5克(5根羊蹄用料)羊蹄洗

2024-11-23 08:31

柠檬水应该怎么做? 教你5分钟get一杯好喝的柠檬水

教你在家轻松制作一杯好喝的柠檬水:柠檬切片去籽,倒入温水,加点盐和冰糖即可。这么简单,赶紧做起来吧!

2024-11-23 08:16

广西玉林属于什么地方 国家为什么要大力发展?

玉林,广西地级市。玉林是广西壮族自治区东南部地区的政治、经济、文化中心。2020年5月,全国291个城市经济排名,玉林以383.50亿元排名第140位。玉林能有今天的发展离不开国家政策的支持,那么国家为什么要大力发展玉林呢?玉林目前属于四线城市,但是随着飞机场、高铁新城、铁山港码头的建成以及多条高速

2024-11-23 08:01

鱼怎么做才好吃?教你正确做法,不红烧,不水煮,年夜饭上桌就是一大硬菜

草鱼是一种比较好吃的鱼类,它的肉质比较鲜嫩,吃起来非常美味,而且营养价值也特别高,今天咱们跟大家分享一个草鱼非常美味的吃法,相信这个草鱼的吃法是很多朋友都没有尝试过的,这个草鱼的吃法就是腐竹鱼块,这样做出来的鱼块非常入味,肉质鲜嫩,非常下饭。那么接下来咱们就一块去看一下腐竹鱼块具体的烹饪步骤吧。【腐

2024-11-22 10:31

学不进去注意力不集中 怎么办?

如果孩子的性格较为拖沓,注意力不集中,可以采取以下措施来帮助他们改善:1.设定明确的目标和计划。让孩子知道自己要做什么,什么时候完成,以及如何完成。这样可以提高孩子的自我管理能力,增加他们的责任感和成就感。2.给孩子制定一个规律的生活作息表。帮助孩子建立健康的作息习惯,包括规律的起床和就寝时间、规律

2024-11-22 10:16

猪舌头的家常做法大全 ,爱吃猪舌的一定要收藏

说到猪舌头,不吃的可能会觉得非常的恶心,但是对于会吃的吃货来说,猪舌头是真真实实,而且价格实惠的食材!猪舌含有丰富的蛋白质、维生素A、烟酸、铁、硒等营养元素,有滋阴润燥的功效,猪舌性平味甘、咸,有滋阴润燥的功效,一般人都可食用。这期的美食教程,天健美食坊就准备拿猪舌头做食材,给大家分享几种猪舌头美味

2024-11-22 10:01