CPUバインド技術

14307 ワード

1コンセプト
CPU Affinityとは?Affinityは、プロセススケジューラがこのプロセスをどのCPUにスケジューリングできるかを示すプロセスの属性です.
Linuxでは、CPU affinityを使用して1つ以上のプロセスを1つ以上のCPUにバインドできます.CPU Affinityは2種類あり,soft affinityとhard affinityである.soft affinityは1つの提案にすぎず、避けられない場合、スケジューラはプロセスを他のCPUにスケジューリングします.hard affinityはスケジューラが守らなければならないルールです.
CPUバインドが必要な理由
●CPUキャッシュのヒット率を増加
CPU間ではキャッシュを共有しないが,プロセスを頻繁に各CPU間で切り替えると,古いCPUのcacheを絶えず失効させる必要がある.プロセスがCPU上でのみ実行されている場合、無効になることはありません.
●CPUキャッシュのヒット率を増加
複数のスレッドが同じデータで動作している場合、これらのスレッドを1つのプロセッサにスケジューリングすると、CPUキャッシュのヒット率が大幅に増加します.しかし、同時性の低下を招く可能性があります.これらのスレッドがシリアルである場合、この影響はありません.
●time-sensitive応用に適合
real-timeまたはtime-sensitiveアプリケーションでは、システムプロセスをいくつかのCPUにバインドし、アプリケーションプロセスを残りのCPUにバインドすることができます.典型的な設定は、アプリケーションをあるCPUにバインドし、他のすべてのプロセスを他のCPUにバインドすることです.

2バインドプロセスとCPUの符号化実装


プロセス親和性の設定と取得は、主に次の2つの関数によって実現されます.

#define _GNU_SOURCE
#include <sched.h>
long sched_setaffinity(pid_t pid, unsigned int len,
        unsigned long *user_mask_ptr);
long sched_getaffinity(pid_t pid, unsigned int len,
        unsigned long *user_mask_ptr);

とパラメータ から らかで、 しなければならないのは3 のパラメータで、このパラメータselectのfd_setは しており, bitはCPUを す.
 
//affinityの

unsigned long mask = 7; /* processors 0, 1, and 2 */
unsigned int len = sizeof(mask);
if (sched_setaffinity(0, len, &mask) < 0) 
{
    perror("sched_setaffinity");
}

//affinity の

unsigned long mask;

unsigned int len = sizeof(mask);
if (sched_getaffinity(0, len, &mask) < 0) {
    perror("sched_getaffinity");
    return -1;
    }
printf("my affinity mask is: %08lx
", mask);

また、rootユーザーまたはプロセスのownerである があることを に、ソースコードを しないでCPUをバインドすることもできます.セクション6.1を してください.
 

3バインドスレッドとCPUの


プロセスの と に、スレッド の と は に の2つの によって されます.
int pthread_setaffinity_np(pthread_t thread, size_t cpusetsize,
const cpu_set_t *cpuset);
int pthread_getaffinity_np(pthread_t thread, size_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); 


cpuセットはマスクと えられ、 されたビットは にスケジューリング なcpuに し、 されていないビットはスケジューリング なCPUに する.すなわち、スレッドはバインドされており、 するビットが されたプロセッサでのみ できます. 、マスク のすべてのビットはセットされ、すなわち、すべてのcpuでスケジューリングすることができる.
6.2 はスレッドバインドCPUの である.       
 

4プロセス CPU


1つ のプロセスが1つ のCPUを する すなわち、スケジューラは、 されたプロセスのみを されたCPUにスケジューリングすることができる. も な はfork()の を して,サブプロセスが プロセスのaffinityを することである.この では、カーネルコードを およびコンパイルする はありません.
Initプロセスはすべてのプロセスの であり、 たちはinitプロセスのaffinityを してすべてのプロセスのaffinityの を し、それから たち のプロセスを CPUにバインドすることができます.これにより、 されたCPU で されたプロセスのみを する に する.
では、initプロセスのaffinityをどのように しますか? たちは/etc/rc.d/rc.Sysinitまたは/etc/rc.Sysinitでは、bindが6.1 コンパイルにより する ファイル、rcである2 を に する.Sysinitファイルはinitプロセスが する のスクリプトです.
/bin/bind 1 1  # init 0
/bin/bind $$ 1  # 0

 

5スレッド CPU


カーネルパラメータisolcpusにより、システムにCPUの を します. に,ターゲットスレッドを のCPUにバインドする.

6ソースコード


6.1バインドプロセス

/* bind - simple command-line tool to set CPU

 * affinity of a given task

 */

 

#define _GNU_SOURCE

 

#include <stdlib.h>

#include <stdio.h>

#include <sched.h>

 

int main(int argc, char *argv[])

{

    unsigned long new_mask;

    unsigned long cur_mask;

    unsigned int len = sizeof(new_mask);

    pid_t pid;

 

    if (argc != 3) {

   fprintf(stderr,

                "usage: %s [pid] [cpu_mask]
",

                argv[0]);

   return -1;

    }

 

    pid = atol(argv[1]);

    sscanf(argv[2], "%08lx", &new_mask);

 

    if (sched_getaffinity(pid, len,

                          &cur_mask) < 0) {

   perror("sched_getaffinity");

   return -1;

    }

 

    printf("pid %d's old affinity: %08lx
",

           pid, cur_mask);

 

    if (sched_setaffinity(pid, len, &new_mask)) {

   perror("sched_setaffinity");

   return -1;

    }

 

    if (sched_getaffinity(pid, len,

                          &cur_mask) < 0) {

   perror("sched_getaffinity");

   return -1;

    }

 

    printf(" pid %d's new affinity: %08lx
",

           pid, cur_mask);

 

    return 0;

}


6.2バインドスレッド

#define _GNU_SOURCE

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <pthread.h>

#include <sched.h>

 

void *myfun(void *arg)

{

    cpu_set_t mask;

    cpu_set_t get;

    char buf[256];

    int i;

    int j;

    int num = sysconf(_SC_NPROCESSORS_CONF);

    printf("system has %d processor(s)
", num);

 

    for (i = 0; i < num; i++) {

        CPU_ZERO(&mask);

        CPU_SET(i, &mask);

        if (pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask) < 0) {

            fprintf(stderr, "set thread affinity failed
");

        }

        CPU_ZERO(&get);

        if (pthread_getaffinity_np(pthread_self(), sizeof(get), &get) < 0) {

            fprintf(stderr, "get thread affinity failed
");

        }

        for (j = 0; j < num; j++) {

            if (CPU_ISSET(j, &get)) {

                printf("thread %d is running in processor %d
", (int)pthread_self(), j);

            }

        }

        j = 0;

        while (j++ < 100000000) {

            memset(buf, 0, sizeof(buf));

        }

    }

    pthread_exit(NULL);

}

 

int main(int argc, char *argv[])

{

    pthread_t tid;

    if (pthread_create(&tid, NULL, (void *)myfun, NULL) != 0) {

        fprintf(stderr, "thread create failed
");

        return -1;

    }

    pthread_join(tid, NULL);

    return 0;

}


7リファレンス


[1] http://www.linuxjournal.com/article/6799?page=0,0
[2] http://blog.chinaunix.net/uid-26739406-id-3181199.html