CPUバインド技術
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
#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