Linux CPU affinity

6881 ワード

一.CPU affinity
linuxは、あるプロセスまたはスレッドを特定の1つまたは複数のcpuにバインドして実行します.
 
二.なぜCPU affinityが必要なのか
Cacheのパフォーマンスが向上し、複数のプロセスが交互にcpu上で実行され、キャッシュが無効になります.
マルチスレッドプログラムはcpuで実行され、各スレッドが順番にcpuリソースを占有し、cacheを共有し、cache性能が低下します.
専有プログラムのリアルタイム性は、専有プロセスを1つのコアに保証し、残りのすべてのプロセスを残りのコアにバインドし、専有プログラムの性能を保証します.
 
三.Linux cpu affinity呼び出し関数
a.プロセスcpu affinity設定
int sched_setaffinity(pid_t pid, size_t cpusetsize,  cpu_set_t *mask);
int sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask);
最初の関数設定プロセス番号pidのcpu親和性
2番目の関数取得プロセス番号pidのcpu親和性
 
b.スレッドcpu affinity設定
int pthread_setaffinity_np(pthread_t thread, size_t cpusetsize, onst cpu_set_t *cpuset);
 int pthread_getaffinity_np(pthread_t thread, size_t cpusetsize, cpu_set_t *cpuset);
最初の関数は、スレッド番号threadのcpu親和性を設定します.
2番目の関数は、スレッド番号threadのcpu親和性を取得します.
四.例
   1.プロセスcpu affinity設定task_affi.c:
#define _GNU_SOURCE

#include <stdio.h>
#include <math.h>
#include <unistd.h> 
#include <sched.h>
#include <pthread.h> 
#include <assert.h>

/*waste some time but ,ocuppy the cup*/
static waste_time(long n)
{

    double res = 0;

    long i = 0;

    while(i <n * 200000) {

        i++;

        res += sqrt(i);

    }

    return res;

}



int main()
{
        cpu_set_t cpuset;
        int ret, j, num_cpus, core;
        pid_t pid;

      
        pid = getpid();
        num_cpus = sysconf(_SC_NPROCESSORS_CONF);/*get the cpu nums*/
        assert(num_cpus > 0);

 

        printf("cpu num:%d
", num_cpus); core = 0 % num_cpus; CPU_ZERO(&cpuset); CPU_SET(core, &cpuset); ret = sched_setaffinity(pid, sizeof(cpu_set_t), &cpuset); assert(ret == 0); ret = sched_getaffinity(pid, sizeof(cpu_set_t), &cpuset); assert(ret == 0); for (j = 0; j < CPU_SETSIZE; j++) if (CPU_ISSET(j, &cpuset)) printf("after set program bind on CPU %d
", j); printf ("core %d result: %f
", core, waste_time (5000)); core = 1%num_cpus; CPU_ZERO(&cpuset); CPU_SET(core, &cpuset); ret = sched_setaffinity(pid, sizeof(cpu_set_t), &cpuset); assert(ret == 0); ret = sched_getaffinity(pid, sizeof(cpu_set_t), &cpuset); assert(ret == 0); for (j = 0; j < CPU_SETSIZE; j++) if (CPU_ISSET(j, &cpuset)) printf("after set program bind on CPU %d
", j); printf ("core %d result: %f
", core, waste_time (5000)); return 0; }
gccコンパイル:
gcc task_affi.c -lm

2.スレッドcpu affinity設定thread_affi.c:
#define _GNU_SOURCE


#include <stdio.h>

#include <unistd.h>
#include <sched.h>
#include <pthread.h>  
#include <assert.h>

static int cpu_nums;

static waste_time(long n)
{

    double res = 0;
    long i = 0;

    while(i <n * 200000) {
        i++;
        res += sqrt(i);
    }

    return res;
}



void *function1(void *argc)
{
     pthread_t  thread_id;
     int ret, j, core;
     cpu_set_t cpuset;

 
     thread_id = pthread_self();
     printf("porgran pid:%u, the function1 pthread id is %lu
",getpid(), thread_id); core = 0 % cpu_nums; CPU_ZERO(&cpuset); CPU_SET(core, &cpuset); ret = pthread_setaffinity_np(thread_id, sizeof(cpu_set_t), &cpuset); assert(ret == 0); /* Check the actual affinity mask assigned to the thread */ ret = pthread_getaffinity_np(thread_id, sizeof(cpu_set_t), &cpuset); assert(ret == 0); printf("thread_id:%lu set the cpu:", thread_id); for (j = 0; j < CPU_SETSIZE; j++) if (CPU_ISSET(j, &cpuset)) printf(" CPU %d

", j); printf ("the function1 pthread id is %lu, bind core %d
", thread_id, core ); printf("the function1 result: %f

",waste_time (5000) ); return 0; } void *function2(void *argc) { pthread_t thread_id; int ret, j, core; cpu_set_t cpuset; thread_id = pthread_self(); printf("porgran pid:%u, the function2 pthread id is %lu
",getpid(), thread_id); sleep(5); core = 1 % cpu_nums; CPU_ZERO(&cpuset); CPU_SET(core, &cpuset); ret = pthread_setaffinity_np(thread_id, sizeof(cpu_set_t), &cpuset); assert(ret == 0); /* Check the actual affinity mask assigned to the thread */ ret = pthread_getaffinity_np(thread_id, sizeof(cpu_set_t), &cpuset); assert(ret == 0); printf("thread_id:%lu set the cup:
", thread_id); for (j = 0; j < CPU_SETSIZE; j++) if (CPU_ISSET(j, &cpuset)) printf(" CPU %d
", j); printf ("the function2 pthread id is %lu, bind core %d
", thread_id, core); printf ("the function2 result is: %f
",waste_time (5000) ); return 0; } int main() { pthread_t thread_id[2]; int ret, j, core; pthread_t main_thread_id; cpu_set_t cpuset; main_thread_id = pthread_self(); cpu_nums = sysconf(_SC_NPROCESSORS_CONF); assert(cpu_nums > 0); printf("cpu num:%d
", cpu_nums); core = 0 % cpu_nums; printf("porgran pid:%u, mian_thread_id:%lu
", getpid(), main_thread_id); ret = pthread_create(thread_id, NULL, function1, NULL); assert(ret == 0); ret = pthread_create(thread_id + 1, NULL, function2, NULL); assert(ret == 0); ret = pthread_join(thread_id[0], NULL); assert(ret == 0); ret = pthread_join(thread_id[1], NULL); assert(ret == 0); core = 2 % cpu_nums; CPU_ZERO(&cpuset); CPU_SET(core, &cpuset); ret = pthread_setaffinity_np(main_thread_id, sizeof(cpu_set_t), &cpuset); assert(ret == 0); /* Check the actual affinity mask assigned to the thread */ ret = pthread_getaffinity_np(main_thread_id, sizeof(cpu_set_t), &cpuset); assert(ret == 0); printf("mian_thread_id:%lu set the cpu:", main_thread_id); for (j = 0; j < CPU_SETSIZE; j++) if (CPU_ISSET(j, &cpuset)) printf(" CPU %d

", j); printf ("the main function pthread id is %lu, bind core %d result: %f
", main_thread_id, core, waste_time (5000)); return 0; }

gccコンパイル:
$ gcc thread_affi.c -lpthread -lm

プログラムを実行するときはtopコマンドを介して、「1」を押して、各cpuの使用状況を表示することができる.