sched_setaffinity, sched_getaffinity - スレッドの
CPU affinity
マスクを設定・取得する
#define _GNU_SOURCE /* feature_test_macros(7) 参照 */
#include <sched.h>
int sched_setaffinity(pid_t pid, size_t cpusetsize,
const cpu_set_t *mask);
int sched_getaffinity(pid_t pid, size_t cpusetsize,
cpu_set_t *mask);
スレッドの CPU affinity (親和度)
マスクは、そのスレッドが
実行を許可されている
CPU の集合を決定する。
マルチプロセッサシステムでは、CPU
affinity
マスクを設定することで
性能上のメリットを得られる可能性がある。
例えば、特定のスレッドを一つの
CPU に括り付け
(すなわち、そのスレッドの
affinity マスクを一つの CPU
に設定し)、
他の全てのスレッドの
affinity マスクからその CPU
を除外することで、
確実にそのスレッドの実行速度を最大にすることができる。
また、あるスレッドの実行を一つの
CPU に限定することで、
一つの CPU
での実行を停止してから別の
CPU
で実行を再開するときに発生する
キャッシュ無効化 (cache
invalidation)
による性能面の劣化を避けることもできる。
CPU affinity マスクは「CPU
の集合」を表す
cpu_set_t
構造体で表現され、
cpu_set_t へのポインター
mask で指定される。 CPU
集合を操作するためのマクロ群については
CPU_SET(3)
で記載されている。
sched_setaffinity() は、スレッド ID
が
pid のスレッドの CPU
affinity マスクを
mask
で指定された値に設定する。
pid が 0
の場合、呼び出し元スレッドが使われる。
cpusetsize 引き数には
mask
が指すデータの長さ
(バイト単位) である。
通常は、この引き数には
sizeof(cpu_set_t)
を指定すればよい。
pid
で指定されたスレッドが
mask で指定された CPU
のいずれかで現在実行されていない場合、
そのスレッドは
mask
で指定された CPU
のいずれかに移動される。
sched_getaffinity() は、 スレッド ID
が
pid のスレッドの affinity
マスクを
mask が指す
cpu_set_t
構造体に書き込む。
cpusetsize 引き数には
mask
の (バイト単位の)
大きさを指定する。
成功した場合、
sched_setaffinity() と
sched_getaffinity() は 0
を返す。
エラーの場合は -1
を返し、
errno
を適切に設定する。
- EFAULT
- 指定されたメモリー番地が不正である。
- EINVAL
- システム上に現在実際に存在し、かつ
"cpuset"
機構が課す制限においてそのスレッドに対して許可されている
プロセッサが、 affinity
ビットマスク mask
に含まれていない。
"cpuset"
機構については cpuset(7)
を参照。
- EINVAL
- (sched_getaffinity()
と、カーネル 2.6.9
以前の sched_setaffinity()) cpusetsize
がカーネルで使われている
affinity
マスクのサイズより小さい。
- EPERM
- (sched_setaffinity())
呼び出し元のスレッドに適切な特権がなかった。
呼び出し元は、実効ユーザー
ID が pid
で識別されるスレッドの実ユーザー
ID
または実効ユーザー
ID と同じであるか、
CAP_SYS_NICE
ケーパビリティ (capability)
を持たなければならない。
- ESRCH
- ID が pid
のスレッドが見つからなかった。
CPU affinity システムコールは
Linux kernel 2.5.8 で導入された。
これらのシステムコールのラッパー関数は
glibc 2.3 で導入された。
最初は、glibc
のインターフェースには
unsigned int 型の
cpusetsize
引き数が入っていた。
glibc 2.3.3 では
cpusetsize
引き数が削除されたが、glibc
2.3.4 で
size_t
型で復活した。
これらのシステムコールは
Linux 固有である。
sched_setaffinity()
を呼び出した後は、スレッドが実際に実行される
CPU の集合は、
mask
引き数で指定された集合と、システム上に実際に存在する
CPU の集合の 共通集合 (AND)
となる。 "cpuset"
機構が使用されている場合には、スレッドが動作する
CPU 集合
に対してシステムはさらに制限を加えるかもしれない
("cpuset" 機構については
cpuset(7) を参照)。
スレッドが動作する実際の
CPU
集合に対する制限はカーネルにより
暗黙のうちに適用される。
システムで利用可能な
CPU
数を判定する方法はいくつかある。
/proc/cpuinfo
の内容を調べる、
sysconf(3) を使って
_SC_NPROCESSORS_CONF
と
_SC_NPROCESSORS_ONLN
の値を取得する、
/sys/devices/system/cpu/ の CPU
ディレクトリの一覧を調べる、などがある。
sched(7) に Linux
のスケジューリング方式についての説明がある。
affinity
マスクはスレッド単位の属性で、スレッドグループの
各スレッド単位に独立して調整することができる。
gettid(2)
コールからの返り値をこのコールの
pid
引き数として渡すことができる。
pid に 0
を指定すると呼び出し元のスレッドの属性が設定され、
getpid(2)
コールからの返り値を
pid
に指定するとスレッドグループのメインスレッドの属性が設定される
(POSIX スレッド API
を使用している場合、
sched_setaffinity() の代わりに
pthread_setaffinity_np(3)
を使用すること)。
fork(2)
経由で生成された子プロセスは親プロセスの
CPU affinity
マスクを継承する。
affinity マスクは
execve(2)
の前後で保存される。
このマニュアルページでは
CPU affinity コールの glibc
インターフェースを
説明している。実際のシステムコールインターフェースは少し違っており、
実際の実装では CPU
集合は簡単なビットマスクであるという実状を反映し、
mask の型が
unsigned long *
となっている。
成功時には、生の
sched_getaffinity()
システムコール自身は
cpumask_t データ型の
(バイト単位の)
大きさを返す。
cpumask_t
はカーネル内部で CPU
集合のビットマスクを表現するのに
使われているデータ型である。
lscpu(1),
nproc(1),
taskset(1),
clone(2),
getcpu(2),
getpriority(2),
gettid(2),
nice(2),
sched_get_priority_max(2),
sched_get_priority_min(2),
sched_getscheduler(2),
sched_setscheduler(2),
setpriority(2),
CPU_SET(3),
pthread_setaffinity_np(3),
sched_getcpu(3),
capabilities(7),
cpuset(7),
sched(7)
この man ページは Linux
man-pages
プロジェクトのリリース
3.79 の一部
である。プロジェクトの説明とバグ報告に関する情報は
http://www.kernel.org/doc/man-pages/
に書かれている。