最近需要用ejtag调试CRIU程序中遇到的BUSERROR的问题,环境准备的第一件事就是要让被调试的程序独占一个处理器(核)。 怎么做呢? 方法如下:

一、准备工作:隔离出cpu某核(此核不再参与进程调度)

此步操作需要root权限才可以完成。
具体修改在/ boot/boot.cf的kernel列最末尾加上isolcpus=x,y,… (代表将CPUx CPUy隔离)

title 'Loongnix 1.0 (Loongson)'
	...
	args  root=/dev/sda3 console=tty console=ttyS0,115200 rw isolcpus=0

  这里,我设置了把cpu0隔离出去,然后重启电脑后配置即可生效。
这里isolcpus是传给内核的参数,意为通知内核进程调度模块处理器0不参与进程调度(就算是其他处理器已经负载100%)。如果你要隔离多个处理器可以使用逗号分割,例如我要隔离0号和3号处理器,那么可以写成 isolcpus=0,3

/boot/EFI/BOOT/grub.cfg

那么如何验证此修改起效了呢?

验证隔离的方式
1、 编写用cpu烤鸡蛋的程序
/**demo.c**/
#include <pthread.h>

void* thread_f(void * i){      
//为了能让cpu可以把鸡蛋烤熟,必须确保你的程序是cpu密集型,不要有任何io操作
//我这里可是连printf语句都没有的。
    while(1){}    
    return NULL;
}

int main(int argc,char* argv[]){
    double count = 0;
    pthread_t t0;
    pthread_t t1;
    pthread_t t2;
    pthread_t t3;

    if(pthread_create(&t0, NULL, thread_f, NULL) == -1){
        puts("fail to create pthread t0");
        return 0;
    }

    if(pthread_create(&t1, NULL, thread_f, NULL) == -1){
        puts("fail to create pthread t1");
        return 0;
    }
  if(pthread_create(&t2, NULL, thread_f, NULL) == -1){
        puts("fail to create pthread t2");
        return 0;
    }

    if(pthread_create(&t3, NULL, thread_f, NULL) == -1){
        puts("fail to create pthread t3");
        return 0;
    }
    int ret = pthread_join(t0, NULL);
	return 0;
}

我当前主机是4核4线程的处理器,所以这里我是启动了4个线程去执行一段cpu密集型操作。如果没有isolcpus=0的限制,这个程序可以把4个核全部跑满。接下来编译demo.c

$ gcc demo.c -pthread -o demo
2、 运行用cpu烤鸡蛋的程序并验证结果
$ ./demo &
[1] 10451

然后使用mpstat命令查看所有cpu使用情况

$ mpstat -P ALL 4
Linux 3.10.0+ (localhost) 	2019年09月26日 	_mips64_	(4 CPU)

17时45分57秒  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
17时46分01秒  all   74.56    0.00    0.44    0.00    0.00    0.06    0.00    0.00    0.00   24.94
17时46分01秒    0    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00  100.00
17时46分01秒    1   98.75    0.00    1.25    0.00    0.00    0.00    0.00    0.00    0.00    0.00
17时46分01秒    2   99.75    0.00    0.25    0.00    0.00    0.00    0.00    0.00    0.00    0.00
17时46分01秒    3   99.75    0.00    0.25    0.00    0.00    0.00    0.00    0.00    0.00    0.00

  可以看到,当期主机是4个处理器。上面的demo程序启动4个cpu密集型线程,理论上可以把4个处理器全部跑满,当是看上面的idle列,cpu1、cpu2和cpu3都已经为0,说明已经满负荷工作,而cpu0却还是idle 100,它已经被内核处理器调度策略排除运算了。也就说明上面的isolcpus=0设置成功。

注意.:如果你的机器没有mpstat工具,需要执行如下命令即可

$ yum install -y sysstat

二、设置程序demo独占处理器CPU0

  如何把一个进程或线程绑定(亲和)到固定的处理器,方法很多,可以在代码里设定,可以在程序启动时或启动后设定。

代码里设置的方法:
int sched_setaffinity(pid_t pid, size_t cpusetsize, const cpu_set_t *mask); //设定某个进程的CPU亲和度
	int pthread_setaffinity_np(pthread_t thread, size_t cpusetsize, const cpu_set_t *cpuset);//设定某个线程的CPU亲和度
命令行的设置方法有两种(使用taskset):

方法1、运行时指定:
     taskset < cpu列表 > [命令]
     例如:我想把demo应用运行在cpu0核上,那么命令是
             taskset -c cpu0 demo

方法2、运行后指定:
     taskset < cpu列表 > [PID]
    例如:demo程序已经在运行且pid为7013。那么我要设置此进程只能运行在cpu0核上。命令如下
             taskset -c cpu0 7013
注意.:在龙芯平台上,运行后的taskset无效。

我们使用运行时指定方式

$ taskset -c 0 ./demo &
[2] 11863

然后再次使用mpstat查看cpu占用率

]$  mpstat -P ALL 4
Linux 3.10.0+ (localhost) 	2019年09月26日 	_mips64_	(4 CPU)

18时04分47秒  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
18时04分51秒  all   29.12    0.00    0.38    0.00    0.00    0.00    0.00    0.00    0.00   70.51
18时04分51秒    0  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
18时04分51秒    1    0.50    0.00    0.50    0.00    0.00    0.00    0.00    0.00    0.00   99.00
18时04分51秒    2    9.05    0.00    0.75    0.00    0.00    0.00    0.00    0.00    0.00   90.20
18时04分51秒    3    6.28    0.00    0.50    0.00    0.00    0.00    0.00    0.00    0.00   93.22

  看到没?此时cpu0已经满负荷工作了(demo进程里的4个线程都运行在了cpu0上)。其他cpu1-cpu3却悠闲的很呢。