• linux下将不同线程绑定到不同core和cpu上——pthread_setaffinity_np


    ===============================================================

    linux下的单进程多线程的程序,要实现每个线程平均分配到多核cpu,主要有2个方法

    1:利用linux系统自己的线程切换机制,linux有一个服务叫做irqbalance,这个服务是linux系统自带的,默认会启动,这个服务的作用就是把多线程平均分配到CPU的每个核上面,只要这个服务不停止,多线程分配就可以自己实现。但是要注意,如果线程函数内部的有某个循环,且该循环内没有任何系统调用的话,可能会导致这个线程的CPU时间无法被切换出去。也就是占满CPU现象,此时加个系统调用,例如sleep,线程所占的CPU时间就可以切换出去了。

    2:利用pthread库自带的线程亲和性设置函数,来设置线程在某个CPU核心上跑,这个需要在程序内部实现。同时注意不要和进程亲和性设置搞混淆了

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    int pthread_setaffinity_np(pthread_t threadsize_t cpusetsize,
    const cpu_set_t *cpuset);
    int pthread_getaffinity_np(pthread_t threadsize_t cpusetsize, 
    cpu_set_t *cpuset);
    从函数名以及参数名都很明了,唯一需要点解释下的可能就是cpu_set_t这个结构体了。这个结构体的理解类似于select中的fd_set,可以理解为cpu集,也是通过约定好的宏来进行清除、设置以及判断:
    //初始化,设为空
    void CPU_ZERO (cpu_set_t *set); 
    //将某个cpu加入cpu集中 
    void CPU_SET (int cpu, cpu_set_t *set); 
    //将某个cpu从cpu集中移出 
    void CPU_CLR (int cpu, cpu_set_t *set); 
    //判断某个cpu是否已在cpu集中设置了 
    int CPU_ISSET (int cpu, const cpu_set_t *set);

    =================================================================

    转自:http://blog.csdn.net/sprintfwater/article/details/39203049

    将线程绑定到不同的processor上:

    这里加入有两个cpu,一个cpu五个核

    [html] view plain copy
     
     print?在CODE上查看代码片派生到我的代码片
    1. #define _GNU_SOURCE                                                                                                                                              
    2. #include <stdio.h>  
    3. #include <string.h>  
    4. #include <stdlib.h>  
    5. #include <stdint.h>  
    6. #include <sched.h>  
    7.   
    8. inline int set_cpu(int i)  
    9. {  
    10.     cpu_set_t mask;  
    11.     CPU_ZERO(&mask);  
    12.   
    13.     CPU_SET(i,&mask);  
    14.   
    15.     printf("thread %u, i = %d ", pthread_self(), i);  
    16.     if(-1 == pthread_setaffinity_np(pthread_self() ,sizeof(mask),&mask))  
    17.     {  
    18.         fprintf(stderr, "pthread_setaffinity_np erro ");  
    19.         return -1;  
    20.     }  
    21.     return 0;  
    22. }  
    23. void *thread_ip_bitmap_set(void *p)  
    24. {  
    25.     uint32_t i, ip;  
    26.     struct id_ipmap *entry;  
    27.     thread_info_t *info = (thread_info_t *)p;  
    28.   
    29.     if(set_cpu(info->id))  
    30.     {  
    31.         return NULL;  
    32.     }  
    33.    
    34.     printf("info->id = %d; info->start = %d;  info->end = %d, sub = %d ", info->id, info->start, info->end, info->start - info->end);  
    35.     for (i = info->start; i info->end; ++i) {  
    36.         entry = &ipmap_queue[i];  
    37.         for (ip = entry->ip_start; ip entry->ip_end; ip++) {  
    38.             ip_bitmap_set(adns_htobe32(ip), entry->id);  
    39.         }  
    40.     }  
    41.     printf("info->id = %d finished ", info->id);  
    42.     return NULL;  
    43. }  
    44.   
    45.   
    46.   
    47. int main()  
    48. {  
    49. for(thread_index=0; thread_index 10; thread_index++)  
    50.         pthread_create(&thread_id[thread_index],NULL, thread_ip_bitmap_set, &thread_info[thread_index]);  
    51. }  
    [cpp] view plain copy
     
     print?在CODE上查看代码片派生到我的代码片
    1. #define _GNU_SOURCE  
    2. #include <sched.h>  
    3. #include <unistd.h>  
    4. #include <sys/types.h>  
    5. #include<string.h>  
    6. #include <stdio.h>  
    7. #include <errno.h>  
    8. #include <pthread.h>  
    9.   
    10.   
    11. inline int set_cpu(int i)  
    12. {  
    13.     cpu_set_t mask;  
    14.     CPU_ZERO(&mask);  
    15.   
    16.     CPU_SET(i,&mask);  
    17.   
    18.     printf("thread %u, i = %d ", pthread_self(), i);  
    19.     if(-1 == pthread_setaffinity_np(pthread_self() ,sizeof(mask),&mask))  
    20.     {  
    21.         return -1;  
    22.     }  
    23.     return 0;  
    24. }  
    25. void *fun(void *i)  
    26. {  
    27.     if(set_cpu(*(int *)i))  
    28.     {  
    29.         printf("set cpu erro ");  
    30.     }  
    31.     long long a = 0;  
    32.     while(1)  
    33.     {  
    34.         a += rand();  
    35.     }  
    36.     return NULL;  
    37. }  
    38.   
    39. int main (int argc, const char * argv[]) {  
    40.     int i;  
    41.     int cpu_nums = sysconf(_SC_NPROCESSORS_CONF);  
    42.   
    43.     printf("cpu_numbs = %d ", cpu_nums);  
    44.     pthread_t Thread[10];  
    45.     int tmp[10];  
    46.   
    47.     for(i = 0; i < 10; ++i)  
    48.     {  
    49.         tmp[i] = i;  
    50.         pthread_create(&Thread[i],NULL,fun, &tmp[i]);  
    51.     }  
    52.   
    53.   
    54.     for(i = 0; i < 10; ++i)  
    55.     {  
    56.         pthread_join(Thread[i],NULL);  
    57.     }  
    58.   
    59.     return 0;  
    60. }  

    转载:http://blog.csdn.net/xluren/article/details/43202201

    coolshell最新的文章《性能调优攻略》在“多核CPU调优”章节,提到“我们不能任由操作系统负载均衡,因为我们自己更了解自己的程序,所以,我们可以手动地为其分配CPU核,而不会过多地占用CPU0,或是让我们关键进程和一堆别的进程挤在一起。”。在文章中提到了Linux下的一个工具,taskset,可以设定单个进程运行的CPU。

    同时,因为最近在看redis的相关资料,redis作为单进程模型的程序,为了充分利用多核CPU,常常在一台server上会启动多个实例。而为了减少切换的开销,有必要为每个实例指定其所运行的CPU。

    下文,将会介绍taskset命令,以及sched_setaffinity系统调用,两者均可以指定进程运行的CPU实例。

    1.taskset

    taskset是LINUX提供的一个命令(ubuntu系统可能需要自行安装,schedutils package)。他可以让某个程序运行在某个(或)某些CPU上。

    以下均以redis-server举例。

    1)显示进程运行的CPU

    命令taskset -p 21184

    显示结果:

    pid 21184's current affinity mask: ffffff

    注:21184是redis-server运行的pid

          显示结果的ffffff实际上是二进制24个低位均为1的bitmask,每一个1对应于1个CPU,表示该进程在24个CPU上运行

    2)指定进程运行在某个特定的CPU上

    命令taskset -pc 3 21184

    显示结果:

    pid 21184's current affinity list: 0-23
    pid 21184's new affinity list: 3

    注:3表示CPU将只会运行在第4个CPU上(从0开始计数)。

    3)进程启动时指定CPU

    命令taskset -c 1 ./redis-server ../redis.conf

    结合这上边三个例子,再看下taskset的manual,就比较清楚了。

    OPTIONS
    -p, --pid
    operate on an existing PID and not launch a new task

    -c, --cpu-list
    specify a numerical list of processors instead of a bitmask. The list may contain multiple items, separated by comma, and ranges. For example, 0,5,7,9-11.

    2.sched_setaffinity系统调用

    如下文章部分翻译自:http://www.thinkingparallel.com/2006/08/18/more-information-on-pthread_setaffinity_np-and-sched_setaffinity/

    问题描述

    sched_setaffinity可以将某个进程绑定到一个特定的CPU。你比操作系统更了解自己的程序,为了避免调度器愚蠢的调度你的程序,或是为了在多线程程序中避免缓存失效造成的开销,你可能会希望这样做。如下是sched_setaffinity的例子,其函数手册可以参考(http://www.linuxmanpages.com/man2/sched_getaffinity.2.php):

    复制代码
     1 /* Short test program to test sched_setaffinity
     2 * (which sets the affinity of processes to processors).
     3 * Compile: gcc sched_setaffinity_test.c
     4 *              -o sched_setaffinity_test -lm
     5 * Usage: ./sched_setaffinity_test
     6 *
     7 * Open a "top"-window at the same time and see all the work
     8 * being done on CPU 0 first and after a short wait on CPU 1.
     9 * Repeat with different numbers to make sure, it is not a
    10 * coincidence.
    11 */
    12  
    13 #include <stdio.h>
    14 #include <math.h>
    15 #include <sched.h>
    16  
    17 double waste_time(long n)
    18 {
    19     double res = 0;
    20     long i = 0;
    21     while(i <n * 200000) {
    22         i++;
    23         res += sqrt (i);
    24     }
    25     return res;
    26 }
    27  
    28 int main(int argc, char **argv)
    29 {
    30     unsigned long mask = 1; /* processor 0 */
    31  
    32     /* bind process to processor 0 */
    33     if (sched_setaffinity(0, sizeof(mask), &mask) <0) {
    34         perror("sched_setaffinity");
    35     }
    36  
    37     /* waste some time so the work is visible with "top" */
    38     printf ("result: %f
    ", waste_time (2000));
    39  
    40     mask = 2; /* process switches to processor 1 now */
    41     if (sched_setaffinity(0, sizeof(mask), &mask) <0) {
    42         perror("sched_setaffinity");
    43     }
    44  
    45     /* waste some more time to see the processor switch */
    46     printf ("result: %f
    ", waste_time (2000));
    47 }
    复制代码

    根据你CPU的快慢,调整waste_time的参数。然后使用top命令,就可以看到进程在不同CPU之间的切换。(启动top命令后按“1”,可以看到各个CPU的情况)。

    父进程和子进程之间会继承对affinity的设置。因此,大胆猜测,taskset实际上是首先执行了sched_setaffinity系统调用,然后fork+exec用户指定的进程。

  • 相关阅读:
    迭代器和生成器
    小练习函数
    python学习(函数)
    python学习(文件的操作)
    【Python基础】数据结构
    【Python基础】break 和 continue 语句, 以及循环中的 else 子句
    【Python算法】汉诺塔
    【Python基础】序列(字符串、列表、元组)
    【Python基础】正则表达式
    【Python练习】分类数据
  • 原文地址:https://www.cnblogs.com/x_wukong/p/5924298.html
Copyright © 2020-2023  润新知