如何在 Linux 中使用 C 或 C++ 为进程设置 CPU 亲和性?
- 2024-10-23 08:47:00
- admin 原创
- 83
问题描述:
是否有一种编程方法可以在 Linux 操作系统中使用 c/c++ 设置某个进程的 CPU 亲和性?
解决方案 1:
您需要使用sched_setaffinity(2)
。
例如,仅在 CPU 0 和 2 上运行:
#define _GNU_SOURCE
#include <sched.h>
cpu_set_t mask;
CPU_ZERO(&mask);
CPU_SET(0, &mask);
CPU_SET(2, &mask);
int result = sched_setaffinity(0, sizeof(mask), &mask);
(0
第一个参数表示当前进程,如果是您想要控制的其他进程,请提供 PID)。
另请参阅sched_getcpu(3)
。
解决方案 2:
在进程级别使用 sched_setaffinity,或对单个线程使用pthread_attr_setaffinity_np。
解决方案 3:
我已经做了很多努力来了解发生了什么,所以我添加了这个答案来帮助像我这样的人(我gcc
在 Linux Mint 中使用编译器)
#include <sched.h>
cpu_set_t mask;
inline void assignToThisCore(int core_id)
{
CPU_ZERO(&mask);
CPU_SET(core_id, &mask);
sched_setaffinity(0, sizeof(mask), &mask);
}
int main(){
//cal this:
assignToThisCore(2);//assign to core 0,1,2,...
return 0;
}
但不要忘记将此选项添加到编译器命令中:-D _GNU_SOURCE
因为操作系统可能会为特定核心分配一个进程,所以您可以将其添加GRUB_CMDLINE_LINUX_DEFAULT="quiet splash isolcpus=2,3"
到位于的 grub 文件中/etc/default
,并在终端中运行 sudo update-grub
以保留您想要的核心
更新:
如果您想分配更多核心,您可以按照以下代码操作:
inline void assignToThisCores(int core_id1, int core_id2)
{
CPU_ZERO(&mask1);
CPU_SET(core_id1, &mask1);
CPU_SET(core_id2, &mask1);
sched_setaffinity(0, sizeof(mask1), &mask1);
//__asm__ __volatile__ ( "vzeroupper" : : : ); // It is hear because of that bug which dirtied the AVX registers, so, if you rely on AVX uncomment it.
}
解决方案 4:
sched_setaffinity
+sched_getaffinity
最小 C 可运行示例
此示例摘自我的回答:如何在 Linux 中通过 C 使用 sched_getaffinity 和 sched_setaffinity?我相信这些问题不是重复的,因为那个问题是这个问题的子集,因为它只询问sched_getaffinity
,而没有提到 C++。
在这个例子中,我们获取亲和力,修改它,然后检查它是否生效sched_getcpu()
。
主程序
#define _GNU_SOURCE
#include <assert.h>
#include <sched.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void print_affinity() {
cpu_set_t mask;
long nproc, i;
if (sched_getaffinity(0, sizeof(cpu_set_t), &mask) == -1) {
perror("sched_getaffinity");
assert(false);
}
nproc = sysconf(_SC_NPROCESSORS_ONLN);
printf("sched_getaffinity = ");
for (i = 0; i < nproc; i++) {
printf("%d ", CPU_ISSET(i, &mask));
}
printf("
");
}
int main(void) {
cpu_set_t mask;
print_affinity();
printf("sched_getcpu = %d
", sched_getcpu());
CPU_ZERO(&mask);
CPU_SET(0, &mask);
if (sched_setaffinity(0, sizeof(cpu_set_t), &mask) == -1) {
perror("sched_setaffinity");
assert(false);
}
print_affinity();
/* TODO is it guaranteed to have taken effect already? Always worked on my tests. */
printf("sched_getcpu = %d
", sched_getcpu());
return EXIT_SUCCESS;
}
GitHub 上游。
编译并运行:
gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
./main.out
示例输出:
sched_getaffinity = 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
sched_getcpu = 9
sched_getaffinity = 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
sched_getcpu = 0
这意味着:
最初,我的所有 16 个核心都已启用,并且该进程在核心 9(第 10 个)上随机运行
在我们将亲和性设置为仅第一个核心后,该过程必然会移动到核心 0(第一个核心)
运行这个程序也很有趣taskset
:
taskset -c 1,3 ./a.out
给出以下形式的输出:
sched_getaffinity = 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0
sched_getcpu = 2
sched_getaffinity = 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
sched_getcpu = 0
所以我们看到它从一开始就限制了亲和力。
这是有效的,因为亲和力是由子进程继承的,这taskset
就是分叉:如何防止分叉子进程继承 CPU 亲和力?
os.sched_getaffinity
Python :os.sched_setaffinity
参见:如何使用 python 找出 CPU 的数量
在 Ubuntu 16.04 中测试。
解决方案 5:
简而言之
unsigned long mask = 7; /* processors 0, 1, and 2 */
unsigned int len = sizeof(mask);
if (sched_setaffinity(0, len, &mask) < 0) {
perror("sched_setaffinity");
}
查看CPU 亲和性以了解更多详细信息
解决方案 6:
也可以在不修改带有cgroups和cpuset子系统的程序的情况下通过 shell 完成此操作。cgroups(至少是 v1)通常安装在cpuset子系统所在的/sys/fs/cgroup上。例如:
$ ls -l /sys/fs/cgroup/
total 0
drwxr-xr-x 15 root root 380 nov. 22 20:00 ./
drwxr-xr-x 8 root root 0 nov. 22 20:00 ../
dr-xr-xr-x 2 root root 0 nov. 22 20:00 blkio/
[...]
lrwxrwxrwx 1 root root 11 nov. 22 20:00 cpuacct -> cpu,cpuacct/
dr-xr-xr-x 2 root root 0 nov. 22 20:00 cpuset/
dr-xr-xr-x 5 root root 0 nov. 22 20:00 devices/
dr-xr-xr-x 3 root root 0 nov. 22 20:00 freezer/
[...]
在cpuset下,cpuset.cpus定义了允许属于此 cgroup 的进程运行的 CPU 范围。在这里,在顶层,为系统的所有进程配置了所有 CPU。在这里,系统有 8 个 CPU:
$ cd /sys/fs/cgroup/cpuset
$ cat cpuset.cpus
0-7
属于此 cgroup 的进程列表在cgroup.procs文件中列出:
$ cat cgroup.procs
1
2
3
[...]
12364
12423
12424
12425
[...]
可以创建一个允许使用 CPU 子集的子 cgroup。例如,让我们定义一个具有 CPU 核心 1 和 3 的子 cgroup:
$ pwd
/sys/fs/cgroup/cpuset
$ sudo mkdir subset1
$ cd subset1
$ pwd
/sys/fs/cgroup/cpuset/subset1
$ ls -l
total 0
-rw-r--r-- 1 root root 0 nov. 22 23:28 cgroup.clone_children
-rw-r--r-- 1 root root 0 nov. 22 23:28 cgroup.procs
-rw-r--r-- 1 root root 0 nov. 22 23:28 cpuset.cpu_exclusive
-rw-r--r-- 1 root root 0 nov. 22 23:28 cpuset.cpus
-r--r--r-- 1 root root 0 nov. 22 23:28 cpuset.effective_cpus
-r--r--r-- 1 root root 0 nov. 22 23:28 cpuset.effective_mems
-rw-r--r-- 1 root root 0 nov. 22 23:28 cpuset.mem_exclusive
-rw-r--r-- 1 root root 0 nov. 22 23:28 cpuset.mem_hardwall
-rw-r--r-- 1 root root 0 nov. 22 23:28 cpuset.memory_migrate
-r--r--r-- 1 root root 0 nov. 22 23:28 cpuset.memory_pressure
-rw-r--r-- 1 root root 0 nov. 22 23:28 cpuset.memory_spread_page
-rw-r--r-- 1 root root 0 nov. 22 23:28 cpuset.memory_spread_slab
-rw-r--r-- 1 root root 0 nov. 22 23:28 cpuset.mems
-rw-r--r-- 1 root root 0 nov. 22 23:28 cpuset.sched_load_balance
-rw-r--r-- 1 root root 0 nov. 22 23:28 cpuset.sched_relax_domain_level
-rw-r--r-- 1 root root 0 nov. 22 23:28 notify_on_release
-rw-r--r-- 1 root root 0 nov. 22 23:28 tasks
$ cat cpuset.cpus
$ sudo sh -c "echo 1,3 > cpuset.cpus"
$ cat cpuset.cpus
1,3
在将任何进程移入此 cgroup 之前,必须填写cpuset.mems文件。这里我们将当前 shell 移入这个新的 cgroup(我们仅将要移动的进程的 pid 写入cgroup.procs文件):
$ cat cgroup.procs
$ echo $$
4753
$ sudo sh -c "echo 4753 > cgroup.procs"
sh: 1: echo: echo: I/O error
$ cat cpuset.mems
$ sudo sh -c "echo 0 > cpuset.mems"
$ cat cpuset.mems
0
$ sudo sh -c "echo 4753 > cgroup.procs"
$ cat cgroup.procs
4753
12569
后者显示当前 shell (pid#4753) 现在位于新创建的 cgroup 中(第二个 pid 12569 是cat的命令,因为它是当前 shell 的子命令,它继承了它的 cgroups)。使用格式化的ps命令,可以验证进程在哪个 CPU 上运行(PSR列):
$ ps -o pid,ppid,psr,command
PID PPID PSR COMMAND
4753 2372 3 bash
12672 4753 1 ps -o pid,ppid,psr,command
我们可以看到当前 shell 在 CPU#3 上运行,而继承了其 cgroups 的子命令(ps命令)在 CPU#1 上运行。
总之,不用使用sched_setaffinity()或任何pthread服务,而是可以在 cgroups 树中创建一个cpuset层次结构,并通过在相应的cgroup.procs文件中写入它们的 pid 将进程移动到其中。
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件