美文网首页c++
Linux如何将进程绑定CPU核心以提高性能

Linux如何将进程绑定CPU核心以提高性能

作者: 切糕糕 | 来源:发表于2019-02-26 23:42 被阅读29次

在Linux系统中,进程的调度切换是由内核自动完成的,在多核CPU上,进程有可能在不同的CPU核上来回切换执行,这对CPU的缓存不是很有利。为什么呢?先看一张 Intel i5 CPU 的缓存简单示意图:

CPU cache简单示意图

在多核CPU结构中,每个核心有各自的L1、L2缓存,而L3缓存是共用的。如果一个进程在核心间来回切换,各个核心的缓存命中率就会受到影响。相反如果进程不管如何调度,都始终可以在一个核心上执行,那么其数据的L1、L2 缓存的命中率可以显著提高。

1. 如何设置进程与CPU核心绑定

在 Linux 系统里,可以使用 CPU_* 系列函数和 sched_setaffinity() 可以实现绑定,具体步骤如下:

  1. 使用 CPU_系列函数,必须定义 _GNU_SOURCE 宏,告诉编译器启用这些函数:
#define _GNU_SOURCE
  1. 首先声明一个 cpu_set_t,然后用 CPU_ZERO()初始化bit数据:
cpu_set_t mask;
CPU_ZERO(&mask);

cpu_set_t其实是一个bit串,每个bit表示进程是否要与某个CPU核绑定。

  1. 接下来把进程绑定到某几个CPU核心,这要用CPU_SET()来设置cpu_set_t中相应的bit位,比如想让进程只在核心1或核心5上执行:
CPU_SET(1, &mask);
CPU_SET(5, &mask);
  1. 最后用sched_setaffinity完成实际的绑定:
sched_setaffinity(0, sizeof(cpu_set_t), &mask);

设置起来并不难。那怎么验证我们的绑定真的起作用了呢?我们来做个实验:

假定有一台双核机器,这段程序我们起了20个进程,从0开始每个进程分配一个进程号(注意是这里值我们自己起的进程号,不是进程pid),奇数进程号绑定绑定在 Core 0上执行,偶数号的进程绑定在 Core 1上执行。

我们用for让进程循环,用 sched_getcpu() 函数获得当前进程运行在哪个CPU核心上,每次for循环检查下进程是否真的在分配的核心执行。

#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void run(int c, int n) {

    cpu_set_t mask;
    CPU_ZERO(&mask);
    CPU_SET(n, &mask);
    sched_setaffinity(0, sizeof(cpu_set_t), &mask);

    int i;
    for (i = 0; i != 10000; i++) {
        printf("%d-%d\n", c, sched_getcpu());
    }
}

int main()
{
    int i;
    for (i = 0; i != 20; i++) {
        int pid = fork();
        if (pid == 0) {
            run(i, i % 2);
            exit(0);
        }
    }
}

执行上面的程序,就会打印每个进程绑定的CPU核号,进程与核号的关系肯定不会变。如果把 sched_setaffinity() 注释掉,CPU进程就失去绑定。

2. 设置亲和性后的性能测试

设置了进程与CPU绑定后,我们来看看是否能真的带来性能的提升。修改上面的run()函数,每个进程创建一个数组,然后计算数组中值的累加,创建数组的意图是保证进程用到了CPU核心的L1、L2缓存:

void run(int c, int n) {

    cpu_set_t mask;
    CPU_ZERO(&mask);
    CPU_SET(n, &mask);
    sched_setaffinity(0, sizeof(cpu_set_t), &mask);

    struct timeval tv;
    gettimeofday(&tv, NULL);
    long begin = tv.tv_sec * 1000 + tv.tv_usec / 1000;

    int i;
    int arr[N];
    for (i = 0; i != N; i++) {
        arr[i] = i;
    }
    long sum = 0;
    for (i = 0; i != N; i++) {
        sum += arr[i];
    }
    gettimeofday(&tv, NULL);
    long end = tv.tv_sec * 1000 + tv.tv_usec / 1000;
    printf("%ld\n", end - begin);
}

然后执行20次程序,10次没有CPU绑定,10次有CPU绑定,记录每个进程的耗时毫秒数,就有下面的结果:

CPU绑定测试

P1~P20是进程号,A1~A10列是没有CPU绑定的情况,B1~B10列是有CPU绑定的情况,耗时越久单元格越红。可见绑定了CPU的情况下性能有近10%的提升。

相关文章

  • Linux如何将进程绑定CPU核心以提高性能

    在Linux系统中,进程的调度切换是由内核自动完成的,在多核CPU上,进程有可能在不同的CPU核上来回切换执行,这...

  • 12月10日 Linux系统调优

    1、cpu亲缘性绑定 就是将进程绑定在固定的cpu上,提高cpu缓存命中率。 2、修改进程的nice优先级 3、隔...

  • Linux CPU性能分析与监控——vmstat、top

    Linux性能监控工具汇总: iostat 磁盘性能监控 vmstat 虚拟内存性能监控、CPU监控(进程上...

  • nginx性能优化

    nginx性能优化 1、Nginx运行工作进程数量 Nginx运行工作进程个数一般设置CPU的核心或者核心数x2。...

  • 亲和性和隔离CPU

    一 亲和性 高性能的应用有个技巧就是做任务和cpu核心的绑定, 即设置CPU亲和性,绑定之后就可以让这个任务尽可...

  • 内核参数:ulimit详解

    Linux对于每个用户,系统限制其最大进程数。为提高性能,可以根据设备资源情况,设置各linux 用户的最大进程数...

  • Redis变慢了,你会怎么排查(六)

    绑定CPU 很多时候,我们在部署服务时,为了提高性能,降低程序在使用多个CPU时上下文切换的性能损耗,一般会采用进...

  • nginx多进程如何绑定多核心

    nginx进程启动后如果要进行CPU核心绑定,首先配置文件设置: 然后看代码如何处理://todo

  • 爬虫笔记(4)并发多进程

    在python中,多线程并不能利用CPU的多核性能。为进一步提高爬虫性能,使用多进程是有必要的。多进程要比多线程要...

  • 2018-06-04

    Linux进程的睡眠和唤醒 1 Linux进程的睡眠和唤醒 在Linux中,仅等待CPU时间的进程称为就绪进程,它...

网友评论

    本文标题:Linux如何将进程绑定CPU核心以提高性能

    本文链接:https://www.haomeiwen.com/subject/mwbzyqtx.html