とある実験をするのにスレッドに対してCPUアフィニティを設定する必要があったので、メモ。
CPUアフィニティとは
プロセス・スレッドはOSによってどれかのCPUコア上で実行される。CPUアフィニティを設定することで、その実行されるCPUコアを任意に制限・指定することができる。
プロセスにCPUアフィニティを設定
LinuxはCPUアフィニティを設定するための関数sched_setaffinityが用意されている。
一応、例
#define _GNU_SOURCE
#include <sched.h>
int main() {
pid_t pid;
cpu_set_t cpu_set;
int result;
pid = getpid;
CPU_ZERO(&cpu_set);
CPU_SET(2, &cpu_set);
result = sched_setaffinity(pid, sizeof(cpu_set_t), &cpu_set);
if (result != 0) {
// エラー
}
// 処理
return 0;
}
cpu_set_t構造体はCPU集合を表している。
CPU_ZERO関数でcpu_set_t構造体を初期化してから、CPU_SET関数で実行するCPUコアを指定する。4コアのCPUであれば0から3までの値を第一引数に指定する。詳しくはマニュアルを参照。
sched_setaffinity関数の引数は順に、プロセスID、cpu_set_tのデータサイズ、cpu_set_tのポインタ。
第一引数はgetpid関数を使うなりすればよい。
第二引数は基本的にsizeof(cpu_set_t)。
第三引数はCPU_SETで指定したcpu_set_t構造体変数のポインタを指定する。
スレッドにCPUアフィニティを設定
上の方法だとプロセス自体に設定されるので、スレッド単位でアフィニティ設定をしたいのであれば少しだけ違う。
環境によってはpthread_setaffinity_npで可能である。プログラム例はマニュアルに載っているので省略。
上の関数が使えない場合は、sched_setaffinity関数の第一引数にスレッドIDを渡すことで設定できる。
gettid関数が使える環境であるならば、gettid関数で取得したpid_t構造体変数をそのまま投げればよい。
gettid関数が使えないのであれば、システムコールを直接呼んでスレッドIDを取得する。
システムコールを使ってスレッドIDを取得して、CPUアフィニティを設定する時の例
#include <sched.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/types.h>
pid_t gettid(void) {
return syscall(SYS_gettid);
}
void* thread_main(void* args) {
pid_t pid;
cpu_set_t cpu_set;
int result;
pid = gettid;
CPU_ZERO(&cpu_set);
CPU_SET(2, &cpu_set);
result = sched_setaffinity(pid, sizeof(cpu_set_t), &cpu_set);
if (result != 0) {
// エラー
}
// 処理
return NULL;
}
int main() {
pthread_t p;
pthread_create(&p, NULL, thread_main, NULL);
// 処理
return 0;
}
まとめ
間違ってるところがあればご指摘お願いします。