Linux绑核效率优化

11 篇文章 8 订阅

Linux绑核效率优化

原理概述:

cpu一般有多个物理核心,但在运行进程和线程时候,可以将其绑定或者指定到某一个或者多个核心上运行。这样做的好处是:一般在核数比较多的机器上,会有多个CPU共享三级缓存cache的情况。当出现跨cache数据通信时,效率会比同一个cache内通信慢上一些。默认情况下程序运行时不会考虑cache的分组,哪个核空闲就会用哪一个。

在Linux上一般会用0-n给cpu进行编号,在目录/sys/devices/system/cpu/下不同的目录存放不同cpu的信息。

假如一个cpu有8个核,0-3共享一个cache,4-7共享一个cache,经测试程序运行时绑核在0,1,2,3会比由系统自行调度效率高出10-14%

在核数低于4核的CPU上,一般都只有一组缓存,这种情况下绑核不会有效率上的提升。

哪几个CPU在同一组并不是固定的,需要查看系统的配置信息,一般/sys/devices/system/cpu/cpu0/cache/index3/shared_cpu_map文件里以16进制数的形式记录了与cpu0共享三级缓存的cpu,比如00ff,其实就是00001111,就代表0-3号cpu与cpu0共享了同一块三级缓存,一般编程获取的方式使用此文件。

人为观察一般查看/sys/devices/system/cpu/cpu0/cache/index3/shared_cpu_list文件,一般的写法诸如0-5,12-17则代表0-5,12-17号cpu共享同一块三级缓存。

绑核方式

命令绑核:taskset

# 平时启动wps
./wps
# 绑核启动WPS
taskset -c 0,1,2,3 ./wps
# 代表将使用cpu0-cpu3执行wps进程

线程绑核

#include <stdio.h>
#include <stdlib.h>
#define __USE_GNU
#include <sched.h>
#include <pthread.h>

#define NUM_OF_TASKS 5

long shared_cache_cpus;
cpu_set_t cpu_set;

int get_cpu_topo()
{
    int last_cache;
    char cache_info_path[100];
    char str[100];
    FILE *fp;

    //获取cpu有最后一级cache
    int i;
    for (i = 0;i < 5;++i) {
        sprintf(cache_info_path, "/sys/devices/system/cpu/cpu0/cache/index%d/shared_cpu_map", i);
        fp = fopen(cache_info_path, "r");
        if (fp == NULL)
            break;
        fclose(fp);
    }
    last_cache = i -1;

    //读取LLC中shared cache信息
    sprintf(cache_info_path, "/sys/devices/system/cpu/cpu0/cache/index%d/shared_cpu_map", last_cache);
    fp = fopen(cache_info_path, "r");
    if (fp == NULL) {
        perror("open file failed!!!");
        return -1;
    }
    fgets(str, 100, fp);
    shared_cache_cpus = strtol(str, NULL, 16);

    fclose(fp);

    return 0;
}

int bind_thread()
{
    long cpus;

    CPU_ZERO(&cpu_set);
    cpus = shared_cache_cpus;
    for (int i = 0;i < 64; ++i) {
        printf("cpu %d:: ", cpus);
        if (cpus&1) {
            CPU_SET(i, &cpu_set);
            printf("bind to cpu: %d\n", i);
        }

        cpus = cpus >> 1;
    }

    return 0;
}

void WasteTime(void)
{
    int abc = 1000;
    int temp = 0;

    while(abc--)
        temp = 10000*10000;

    sleep(1);
}
 
void *thread_func(void *param)
{
    while(1)
    {
        if (pthread_setaffinity_np(pthread_self(), sizeof(cpu_set), &cpu_set) < 0)
            perror("pthread_setaffinity_np");
        WasteTime();
    }
}

int main()
{
    pthread_t my_thread[NUM_OF_TASKS];

    if (get_cpu_topo() == 0) {
        bind_thread();
    }

    for (int t = 0;t < NUM_OF_TASKS; ++t) {
        if (pthread_create(&my_thread[t], NULL, thread_func, NULL) != 0) {
            perror("pthread_create ERROR!!!");
            return -1;
        }
    }

    for (int t = 0;t < NUM_OF_TASKS; ++t) {
        pthread_join(my_thread[t], NULL);
    }

    pthread_exit(NULL);

    return 0;
}

进程绑核

#include <unistd.h>
#include <sched.h>
#include <sys/sysinfo.h>
#define MAX_CPU_CACHE_LEVEL 5  // cpu最高三级缓存,从0开始循环,取到4确保能拿到最高值

int bindProcess()
{
    //根据cpu共享cache的情况进行绑核,提升运行效率。
    if (get_nprocs() <= 4)
        return 0;

    char cache_info_path[100] = {'\0'};
    char str[100] = {'\0'};

    //获取cpu有最后一级cache
    int i;
    for (i = 0; i < MAX_CPU_CACHE_LEVEL; ++i) 
    {
        sprintf(cache_info_path, "/sys/devices/system/cpu/cpu0/cache/index%d/shared_cpu_map", i);

        if (0 != access(cache_info_path, R_OK))
            break;
    }

    int last_cache = i - 1;

    //读取LLC中shared cache信息
    sprintf(cache_info_path, "/sys/devices/system/cpu/cpu0/cache/index%d/shared_cpu_map", last_cache);
    FILE *fp = fopen(cache_info_path, "r");
    if (fp == NULL) 
    {
        perror("open file failed!!!");
        return -1;
    }
    fgets(str, 100, fp);
    //移除str中的',',否则在有些多核系统上转long会失败
    int j = 0, k = 0;
    while(str[j] != '\0')
    {
        if (str[j] != ',')
        {
            str[k++] = str[j];
        }
        j++;
    }
    str[k] = str[j];
    long shared_cache_cpus = strtol(str, NULL, 16);

    fclose(fp);

    cpu_set_t cpu_set;
    CPU_ZERO(&cpu_set);
    for (int i = 0; i < 64; ++i) 
    {
        if (shared_cache_cpus & 1) 
        {
            CPU_SET(i, &cpu_set);
        }
        shared_cache_cpus = shared_cache_cpus >> 1;
    }
    
    sched_setaffinity(getpid(), sizeof(cpu_set), &cpu_set);
    return 0;
}

在自己的项目代码中嵌入

只需要在main函数执行Exec前,调用上述bindProcess函数即可

参考资料

• https://en.wikipedia.org/wiki/CPU_cache#Cache_miss
• https://blog.csdn.net/fanyun_01/article/details/102788269
• https://blog.csdn.net/ethercat_i7/article/details/105717152

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值