CPU独占内核运行方式实现,并指定线程到特定CPU上执行

CPU独占内核运行方式实现,并指定线程到特定CPU上执行

1. 隔离指定的CPU,避免其余线程run在被隔离的CPU上

隔离CPU的方法:修改Linux内核的启动参数isolcpus

直接更改GRUB配置文件:

# 打开GRUB配置文件 /etc/default/grub
sudo vim /etc/default/grub

# 找到名为 GRUB_CMDLINE_LINUX 的行。该行包含了内核启动参数。
#在双引号中的参数列表中添加 isolcpus 参数,并指定要隔离的CPU核心。例如,如果要隔离核心1,可以这样设置:
GRUB_CMDLINE_LINUX="isolcpus=1"

#还可以在GRUB中设置 'nohz_full=1' 减少系统定时器中断,以提高系统的性能和能效。
#在启用 nohz_full=1 后,需要注意一些时序相关的问题,例如定时器相关的系统调用的行为可能会受到影响。此外,一些应用程序可能依赖于系统定时器的正常工作,可能需要进行适当的测试和调整。
GRUB_CMDLINE_LINUX="isolcpus=1 nohz_full=1"

# 保存文件并退出编辑器。更新GRUB配置,以使更改生效。
sudo update-grub

# 在Centos下上面的更新GRUB配置是无效的
# 需要更新 GRUB 配置,按照以下步骤操作:
# 修改 /etc/default/grub 文件,添加或修改相应的内核参数。
# 运行以下命令以重新生成 GRUB 配置文件:
grub2-mkconfig -o /boot/grub2/grub.cfg

# 重新启动系统,使得修改生效。
sudo reboot

2. 绑定所有的interrupts(中断)到非隔离的CPU上,避免被隔离的CPU收到interrupt.

因为被隔离的CPU虽然没有线程run在上面,但是仍会收到interrupt,绑定所有的interrupts(中断)到非隔离的CPU上

特定IRQ的亲和度值储存在 ‘/proc/irq/IRP_NUMBER/smp_affinity’ 文件中。此文件仅ROOT用户可见。储存的值是一个十六进制位掩码(hexadecimal bit-mask),代表着系统的所有CPU核心.

实际上,在我们将isolcpus参数写入GRUB配置文件后,用户空间完全不会占用这个被隔离的CPU,内核空间Linux会将某些中断IRQ的smp_affinity都会避开所要隔离的CPU号,但是仍有一部分中断没有被绑定,例如: Single function call interrupts, Local timer interrupts等

​ 只要有了一个线程在所隔离的CPU上run,那么timer tick就会开始跑,这个timer tick也会频繁打断这一个线程,从而造成大量的上 下文切换,所以我们可以优化一下这种情况,也就是在GRUB配置中增加:(一个线程独占CPU时优化)

GRUB_CMDLINE_LINUX="nohz_full=2"

添加与不添加区别:

在这里插入图片描述

nohz_full=1nohz_full=2 之间的区别在于如何处理中断。在 nohz_full=1 模式下,中断仍然会在每个处理器的计时器到期时被触发。而在 nohz_full=2 模式下,Linux 内核会尝试将中断委托给少数几个特定的处理器,从而减少了中断的数量,提高了系统的性能。

3. C++绑定线程运行在指定CPU

设定某个线程的CPU亲和性

//POSIX 线程库提供的函数,设置线程的 CPU 亲和性
int pthread_setaffinity_np(pthread_t thread, size_t cpusetsize, const cpu_set_t *cpuset);
//获取线程的 CPU 亲和性
int pthread_getaffinity_np(pthread_t thread, size_t cpusetsize, cpu_set_t *cpuset);
#include <pthread.h>
#include <iostream>

int main() {
    pthread_t thread;
    cpu_set_t cpuset;
    int cpu_core = 1; // 绑定隔离的1号CPU

    // 获取当前线程的标识符
    thread = pthread_self();

    // 初始化 CPU 集合
    CPU_ZERO(&cpuset);

    // 设置要绑定的 CPU 核心
    CPU_SET(cpu_core, &cpuset);

    // 设置线程的 CPU 亲和性
    int result = pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpuset);
    if (result != 0) {
        std::cerr << "Error setting thread CPU affinity" << std::endl;
        return 1;
    }

    std::cout << "Thread CPU affinity set successfully" << std::endl;

    // 这里可以放置线程的逻辑代码
	//TODO
    
    return 0;
}

也可以通过taskset来使线程/进程绑定到隔离的CPU上:

查看进程当前运行在哪个CPU上:

taskset -p [pid]

指定进程运行在第二个CPU(CPU1)上:

taskset -cp 1 进程号

测试结果:

隔离了CPU1,没有改之前,CPU0是满的

在这里插入图片描述

改了之后,CPU0与CPU1都满了

在这里插入图片描述

验证:版本:CentOS Linux release 7.9.2009 (Core)

'Test1.cc'

#include <iostream>
#include <unistd.h>

int main()
{
  fork();
  while(1);
  return 0;
}

默认状态执行Test1.cc

在这里插入图片描述

设置isolcpus=1后的cpu占用率

在这里插入图片描述

可以看出CPU1被隔离了

现在我们运行下面代码,设定创建的线程绑定所隔离的CPU1

在这里插入图片描述
可以看出来该线程在隔离的CPU1上运行

有些中断不能被更改,有些可以
在这里插入图片描述

验证 版本 Ubuntu 22.04.2 LTS

设置了isolcpus=1 nohz_full=1

在这里插入图片描述

已经将CPU1隔离,正常用户空间不会使用到CPU1

在这里插入图片描述

taskset能生效,将一个进程绑定进入CPU1

在这里插入图片描述

将两个进程都添加进入CPU1执行:

在这里插入图片描述

将线程绑定指定的CPU1执行(已经隔离了CPU1):

在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

侠客cheems

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值