cpu亲和性(affinity)以及位数组内核的实现.

1.对使用的介绍讲述的挺清晰

http://www.oenhan.com/cpu-affinity

2.对该机制原理进行了阐述

http://www.ibm.com/developerworks/cn/linux/l-affinity.html

其实CPU affinity就是可以让某个进程/线程在指定的CPU上运行.在默认情况下,调度算法具有软亲和性,即它可以在任意的核上运行.实现上其实就是cpu的bit数组全位1.

过会会对它的实现机制,进行分析,并自己根据glib自己编写了代码.

CPU affinity会用到两个函数sched_setaffinity和sched_getaffinity.

下面简单演示如何使用它:

#include
#include
#include
#include
#include

#define __USE_GNU
#include
#include
#include

int main(int argc, char* argv[])
{
       int num = sysconf(_SC_NPROCESSORS_CONF);
       int cpuid;
       

       cpu_set_t mask;
       cpu_set_t get;

       if (argc != 2)
       {
            printf("usage : ./cpu num\n");
            exit(1);
       }

       cpuid = atoi(argv[1]);

       printf("system has %i processor(s). \n", num);

       CPU_ZERO(&mask);
       CPU_SET(cpuid, &mask);

       if (sched_setaffinity(0, sizeof(mask), &mask) == -1) 

       {
            printf("没有设置成功,此时cpuset集全为1,即可以运行在所以核上\n");
       }
        
       int i;
       while (1)
       {

            CPU_ZERO(&get);
            if (sched_getaffinity(0, sizeof(get), &get) == -1)
            {
                     printf("warning: cound not get cpu affinity, continuing...\n");
            }
            for (i = 0; i < num; i++)
            {
                     if (CPU_ISSET(i, &get))
                     {
                               printf("this process %d is running processor : %d\n",getpid(), i);
                     }
            }
       }
       return 0;
}
我的机制只有两个逻辑处理器,你也可以在shell中查看,cat /proc/cpuinfo

cpu亲和性(affinity)以及位数组内核的实现._第1张图片

此时为processor 0 和 processor 1

运行 ./a.out 0 (或./a.out 1),就可以看到当前进程只运行在cpu0上(或cpu1上)

cpu亲和性(affinity)以及位数组内核的实现._第2张图片

运行./a.out 2或其他数字,此时sched_setaffinity失败,所以此时还是默认情况,即可以运行任意cpu上,因此,看到当前进程运行在两个核上.

cpu亲和性(affinity)以及位数组内核的实现._第3张图片


修改掩码需要用到以下的宏

void CPU_ZERO (cpu_set_t *set)
这个宏对 CPU 集 set 进行初始化,将其设置为空集。
void CPU_SET (int cpu, cpu_set_t *set)
这个宏将 cpu 加入 CPU 集 set 中。
void CPU_CLR (int cpu, cpu_set_t *set)
这个宏将 cpu 从 CPU 集 set 中删除。
int CPU_ISSET (int cpu, const cpu_set_t *set)
如果 cpu 是 CPU 集 set 的一员,这个宏就返回一个非零值(true),否则就返回零(false)。
其实本质上就是对位数组的位操作而已,下面根据glic sched.h中的源码自己实现了一下.

代码如下:

#include 
#include
#include 
#include




#define __CPU_SETSIZE 1024
#define __NCPUBITS (8 * sizeof(__mycpu_mask) )
typedef long int __mycpu_mask;//32位机器大小为4B,64位大小位8B
//create mycpu_set_t with bit array
typedef struct{
    __mycpu_mask __bits[__CPU_SETSIZE / __NCPUBITS];//不采用int数组,而根据cpu字长来采用相应类型数组,能够提高效率
}mycpu_set_t;

#define MYCPU_ZERO(cpusetp)       \
    do{ \
       mycpu_set_t *arr = (cpusetp);       \
       unsigned int __i;                 \
       for(__i = 0; __i < __CPU_SETSIZE / __NCPUBITS; __i++)      \
       {                                 \
          arr->__bits[__i] = 0;          \
       }                            \
    }while(0)

#define __POS(cpuid)       ((cpuid) / __NCPUBITS)  //该cpuid在bits数组的哪个单元上
#define __CPUMASK(cpuid)   ( 1 << ((cpuid) % __NCPUBITS) )//该cpuid在单元的那个位上.

#define MYCPU_SET(cpuid, cpusetp) \
(  (cpusetp)->__bits[__POS(cpuid)] |= __CPUMASK(cpuid)  )

#define MYCPU_CLR(cpuid,cpusetp)  \
(  ((cpusetp)->__bits[__POS(cpuid)] ) &= ~__CPUMASK(cpuid) )

#define MYCPU_ISSET(cpuid, cpusetp) \
( ((cpusetp)->__bits[__POS(cpuid)] & __CPUMASK(cpuid)) != 0 )


//int main()
//{
//    mycpu_set_t mask;
//    MYCPU_ZERO(&mask);
//    int i;
//    for(i = 0; i < __CPU_SETSIZE / __NCPUBITS; i++)
//    {
//        printf("%d ", mask.__bits[i]);
//    }
//    printf("\n");

//    MYCPU_SET(3,&mask);
//    for(i = 0; i < __CPU_SETSIZE / __NCPUBITS; i++)
//    {
//        printf("%d ", mask.__bits[i]);
//    }
//    printf("\n");

//    MYCPU_CLR(3,&mask);
//    for(i = 0; i < __CPU_SETSIZE / __NCPUBITS; i++)
//    {
//        printf("%d ", mask.__bits[i]);
//    }
//    printf("\n");

//    MYCPU_SET(1,&mask);
//    MYCPU_SET(2,&mask);
//    MYCPU_SET(3,&mask);
//    MYCPU_SET(4,&mask);
//    printf("testing MYCPU_ISSET:\n");
//    for(i = 0; i < __CPU_SETSIZE / __NCPUBITS; i++)
//    {
//        if(MYCPU_ISSET(i, &mask))
//              printf("%d ", i);
//    }
//    printf("\n");
//    return 0;
//}

void test()
{
    int num_processors = sched_getcpu();
    printf("%d\n", num_processors);
}


void *threadFun(void *arg)
{
    mycpu_set_t mask;
    mycpu_set_t get;

    int *id = (int *)arg;
    printf("the thread is:%d\n", *id);
    MYCPU_ZERO(&mask);
    MYCPU_SET(*id, &mask);
    if(sched_setaffinity(0, sizeof(mask), &mask) == -1)
    {
        printf("warning: could not set CPU affinity\n");
    }

    MYCPU_ZERO(&get);
    if(sched_getaffinity(0, sizeof(get), &get) == -1)
    {
        printf("warning :could not get thread affinity\n");
    }

    int i;
    int num_procs = sysconf(_SC_NPROCESSORS_CONF);
    for(i = 0; i < num_procs; i++)
    {
        if(MYCPU_ISSET(i, &get))
        {
            printf("this thread %d is running processor:%d\n", *id, i);
        }
    }

    return NULL;
}

int main(void)
{
    int num_procs = sysconf(_SC_NPROCESSORS_CONF);
    pthread_t thread[num_procs];
    int id[num_procs];
    int i;
    for(i = 0; i < num_procs; i++)
    {
        id[i] = i;
        pthread_create(&thread[i], NULL, threadFun, (void *)&id[i]);
    }

    for(i = 0; i < num_procs; i++)
    {
        pthread_join(thread[i], NULL);
    }
    test();
    return 0;
}


结果如下:

可以看到0号线程运行在处理器0上,1号线程运行在处理器1上

cpu亲和性(affinity)以及位数组内核的实现._第4张图片

你可能感兴趣的:(C,Multithread,Libc source,code)