CPU_SET, CPU_CLR, CPU_ISSET, CPU_ZERO, CPU_COUNT, CPU_AND, CPU_OR, CPU_XOR,
CPU_EQUAL, CPU_ALLOC, CPU_ALLOC_SIZE, CPU_FREE, CPU_SET_S, CPU_CLR_S,
CPU_ISSET_S, CPU_ZERO_S, CPU_COUNT_S, CPU_AND_S, CPU_OR_S, CPU_XOR_S,
CPU_EQUAL_S - CPU
集合を操作するためのマクロ
#define _GNU_SOURCE /* feature_test_macros(7) 参照 */
#include <sched.h>
void CPU_ZERO(cpu_set_t *set);
void CPU_SET(int cpu, cpu_set_t *set);
void CPU_CLR(int cpu, cpu_set_t *set);
int CPU_ISSET(int cpu, cpu_set_t *set);
int CPU_COUNT(cpu_set_t *set);
void CPU_AND(cpu_set_t *destset,
cpu_set_t *srcset1, cpu_set_t *srcset2);
void CPU_OR(cpu_set_t *destset,
cpu_set_t *srcset1, cpu_set_t *srcset2);
void CPU_XOR(cpu_set_t *destset,
cpu_set_t *srcset1, cpu_set_t *srcset2);
int CPU_EQUAL(cpu_set_t *set1, cpu_set_t *set2);
cpu_set_t *CPU_ALLOC(int num_cpus);
void CPU_FREE(cpu_set_t *set);
size_t CPU_ALLOC_SIZE(int num_cpus);
void CPU_ZERO_S(size_t setsize, cpu_set_t *set);
void CPU_SET_S(int cpu, size_t setsize, cpu_set_t *set);
void CPU_CLR_S(int cpu, size_t setsize, cpu_set_t *set);
int CPU_ISSET_S(int cpu, size_t setsize, cpu_set_t *set);
int CPU_COUNT_S(size_t setsize, cpu_set_t *set);
void CPU_AND_S(size_t setsize, cpu_set_t *destset,
cpu_set_t *srcset1, cpu_set_t *srcset2);
void CPU_OR_S(size_t setsize, cpu_set_t *destset,
cpu_set_t *srcset1, cpu_set_t *srcset2);
void CPU_XOR_S(size_t setsize, cpu_set_t *destset,
cpu_set_t *srcset1, cpu_set_t *srcset2);
int CPU_EQUAL_S(size_t setsize, cpu_set_t *set1, cpu_set_t *set2);
cpu_set_t データ構造体は CPU
集合を表現している。
CPU 集合は
sched_setaffinity(2)
や同様のインターフェースで使用されている。
cpu_set_t
データ型はビットマスクとして実装されている。
しかし、
データ構造体はその実装を意識せずに扱うべきであり、
CPU
集合のすべての操作は、
このページで説明されているマクロを通して行うべきである。
以下のマクロが CPU 集合
set
を操作するために提供されている。
-
CPU_ZERO()
-
set
をクリアする。
集合には何も CPU
が含まれない状態となる。
-
CPU_SET()
-
set に cpu
を追加する。
-
CPU_CLR()
-
set から cpu
を削除する。
-
CPU_ISSET()
- CPU cpu が set
のメンバーであるかを検査する。
-
CPU_COUNT()
-
set に含まれる CPU
数を返す。
cpu
引数が指定する場合、
その引数は副作用を伴うべきではない。
上記のマクロは引数を複数回評価する可能性があるからである。
The first CPU on the system corresponds to a
cpu value of 0, the next CPU
corresponds to a
cpu value of 1, and so on. No assumptions should be
made about particular CPUs being available, or the set of CPUs being
contiguous, since CPUs can be taken offline dynamically or be otherwise
absent. The constant
CPU_SETSIZE (currently 1024) specifies a value one
greater than the maximum CPU number that can be stored in
cpu_set_t.
以下のマクロは CPU
集合どうしの論理操作を行う。
-
CPU_AND()
- 集合 srcset1 と srcset2
の積集合を destset
に格納する
(元の集合のいずれかが
destset
として使用される場合もある)。
-
CPU_OR()
- 集合 srcset1 と srcset2
の和集合を destset
に格納する
(元の集合のいずれかが
destset
として使用される場合もある)。
-
CPU_XOR()
- 集合 srcset1 と srcset2
の XOR を destset
に格納する
(元の集合のいずれかが
destset
として使用される場合もある)。
XOR とは、 srcset1 か srcset2
のいずれかに含まれるが、両方には含まれない集合のことである。
-
CPU_EQUAL()
- 二つの CPU
集合が全く同じ CPU
を含んでいるかを検査する。
いくつかのアプリケーションでは
CPU
集合の大きさを動的に決める能力
(例えば、 標準の
cpu_set_t
データ型で定義されたよりも大きい集合を割り当てるなど)
が必要となることがあるため、
現在 glibc
はこれに対応するためにいくつかのマクロを提供している。
以下のマクロを使うと
CPU
集合の割り当てと解放ができる。
-
CPU_ALLOC()
- 0 から num_cpus-1
までの範囲の CPU
を保持するのに十分な大きさの
CPU
集合を割り当てる。
-
CPU_ALLOC_SIZE()
- 0 から num_cpus-1
までの範囲の CPU
を保持するのに必要な
CPU
集合の大きさをバイト数で返す。
このマクロが返す値は、
後述の CPU_*_S() マクロの
setsize
引数として使用できる。
-
CPU_FREE()
- 以前に CPU_ALLOC()
で割り当てられた CPU
集合を解放する。
名前が "_S"
で終わるマクロは
"_S"
なしの同じ名前のマクロと同等である。
これらのマクロは
"_S"
なしのものと同じ動作をするが、
動的に割り当てられた、
大きさが
setsize
バイトの CPU
集合に対して操作を行う点が異なる。
CPU_ISSET() と
CPU_ISSET_S() は、
cpu
が
set
に含まれていれば 0
以外を返し、含まれない場合
0 を返す。
CPU_COUNT() と
CPU_COUNT_S() は
set
に含まれる CPU
数を返す。
CPU_EQUAL() と
CPU_EQUAL_S() は、
二つの CPU
集合が等しければ 0
以外を返し、
等しくない場合 0
を返す。
CPU_ALLOC()
は成功するとポインターを返し、
失敗すると NULL を返す
(エラーは
malloc(3)
と同じである)。
CPU_ALLOC_SIZE()
は指定された大きさの
CPU
集合を格納するのに必要なバイト数を返す。
他の関数は値を返さない。
マクロ
CPU_ZERO(),
CPU_SET(),
CPU_CLR(),
CPU_ISSET() は glibc 2.3.3
で追加された。
CPU_COUNT() は glibc 2.6
で初めて登場した。
CPU_AND(),
CPU_OR(),
CPU_XOR(),
CPU_EQUAL(),
CPU_ALLOC(),
CPU_ALLOC_SIZE(),
CPU_FREE(),
CPU_ZERO_S(),
CPU_SET_S(),
CPU_CLR_S(),
CPU_ISSET_S(),
CPU_AND_S(),
CPU_OR_S(),
CPU_XOR_S(),
CPU_EQUAL_S() は glibc 2.7
で初めて登場した。
これらのインターフェースは
Linux 固有である。
CPU
集合を複製するには、
memcpy(3) を使用する。
CPU
集合はロングワード単位に割り当てられるビットマスクなので、
動的に割り当てられた
CPU 集合の実際の CPU 数は
sizeof(unsigned long)
の次の倍数に切り上げられることになる。
アプリケーションは、
これらの余分なビットの内容は不定と考えるべきである。
名前は似ているが、
定数
CPU_SETSIZE は
cpu_set_t
データ型に含まれる CPU
数
(つまり、事実上ビットマスク内のビットカウント)
を示すのに対して、
マクロ
CPU_*_S() の
setsize
引数はバイト単位のサイズである点に注意すること。
「書式」に書かれている引数と返り値のデータ型は、それぞれの場合でどんな型が期待されるかのヒントである。
しかしながら、
これらのインターフェースはマクロとして実装されているため、
このヒントを守らなかった場合に、
コンパイラが必ずしも全ての型エラーを捕捉できるとは限らない。
glibc 2.8 以前の 32
ビットプラットフォームでは、
CPU_ALLOC()
は必要な空間の割り当てを二度行い、
CPU_ALLOC_SIZE()
は本来あるべき値の二倍の値を返す。
このバグはプログラムの動作には影響を与えないはずだが、
無駄にメモリーを消費し、
動的に割り当てられた
CPU
集合に対して操作を行うマクロの動作の効率が下がる結果となる。
これらのバグは glibc 2.9
で修正された。
以下のプログラムは、動的に割り当てた
CPU
集合に対していくつかのマクロを使用する例を示している。
#define _GNU_SOURCE
#include <sched.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <assert.h>
int
main(int argc, char *argv[])
{
cpu_set_t *cpusetp;
size_t size;
int num_cpus;
if (argc < 2) {
fprintf(stderr, "Usage: %s <num-cpus>\n", argv[0]);
exit(EXIT_FAILURE);
}
num_cpus = atoi(argv[1]);
cpusetp = CPU_ALLOC(num_cpus);
if (cpusetp == NULL) {
perror("CPU_ALLOC");
exit(EXIT_FAILURE);
}
size = CPU_ALLOC_SIZE(num_cpus);
CPU_ZERO_S(size, cpusetp);
for (int cpu = 0; cpu < num_cpus; cpu += 2)
CPU_SET_S(cpu, size, cpusetp);
printf("CPU_COUNT() of set: %d\n", CPU_COUNT_S(size, cpusetp));
CPU_FREE(cpusetp);
exit(EXIT_SUCCESS);
}
sched_setaffinity(2),
pthread_attr_setaffinity_np(3),
pthread_setaffinity_np(3),
cpuset(7)
この man ページは Linux
man-pages
プロジェクトのリリース
5.10
の一部である。プロジェクトの説明とバグ報告に関する情報は
https://www.kernel.org/doc/man-pages/
に書かれている。