mbind -
メモリー領域に対してメモリーポリシーを設定する
#include <numaif.h>
long mbind(void *addr, unsigned long len, int mode,
const unsigned long *nodemask, unsigned long maxnode,
unsigned flags);
-lnuma でリンクする。
mbind() は、
addr
から始まる長さ
len
バイトの範囲のメモリーに
NUMA
メモリーポリシーを設定する。
NUMA
ポリシーはポリシーモードと
0
個以上のノードから構成される。
メモリーポリシーはどのノードからメモリーを割り当てるかを決定する。
addr と
len
で指定されたメモリー範囲に、
メモリーの「無名」領域
—
MAP_ANONYMOUS 付きの
mmap(2)
システムコールを使って作成されたメモリー領域
— や
MAP_PRIVATE 付きの
mmap(2)
を使ってマップされたメモリーマップファイルが含まれている場合、アプリケーションがそのページへの書き込み
(データの格納)
を行った時には指定されたポリシーのみに基づいてページが割り当てられる。無名領域の場合、最初の読み出しアクセスの際には
カーネル内の全データが
0
である共有ページが使用される。
MAP_PRIVATE
でマップされたファイルの場合、最初の読み出しアクセスがあると、
ページ割り当てが発生するきっかけとなったスレッドのメモリポリシーにしたがってページの割り当てが行われる。
ページ割り当てのきっかけとなったスレッドは、
mbind()
を呼び出したスレッドと同じとは限らない。
指定されたメモリー範囲内にある
MAP_SHARED
のマッピングでは指定されたポリシーは無視され、
ページ割り当てが発生するきっかけとなったスレッドのメモリポリシーに
したがってページの割り当てが行われることになる。
繰り返しになるが、ページ割り当てのきっかけとなったスレッドは、
mbind()
を呼び出したスレッドと同じとは限らない。
指定されたメモリー範囲に、
shmget(2)
システムコールを使って作成されたり、
shmat(2)
システムコールを使って付加
(attach)
されたりした共有メモリー領域が
含まれる場合、無名メモリー領域や共有メモリー領域に対するページ割り当ては、
共有メモリーセグメントへポリシーの設定を行ったプロセスがページ割り当て
のきっかけとなったかに関わらず、指定されたポリシーにしたがって割り当て
が行われる。
しかしながら、共有メモリー領域が
SHM_HUGETLB
フラグを指定して作成された場合には、ヒュージページ
(huge page) の割り当てが
指定されたポリシーにしたがって行われるのは、その領域に対して
mbind()
を呼び出したプロセスがページ割り当てのきっかけとなった場合のみである。
デフォルトでは、
mbind()
は新規のメモリー割り当てに対してのみ効果を持つ。
ポリシーが設定される前にすでに使用されている範囲内のページに対しては、
ポリシーは影響しない。
このデフォルトの動作は、以下で説明するフラグ
MPOL_MF_MOVE や
MPOL_MF_MOVE_ALL
により上書きされる可能性がある。
mode 引数には、
MPOL_DEFAULT,
MPOL_BIND,
MPOL_INTERLEAVE,
MPOL_PREFERRED,
MPOL_LOCAL (詳細は下記参照)
のいずれか一つを指定しなければならない。
MPOL_DEFAULT
以外のポリシーモードの場合、呼び出し元は
nodemask
引数でそのポリシーモードを適用するノードを指定する必要がある。
mode 引数には、追加で
モードフラグ
を含めることもできる。
サポートされている
モードフラグ
は以下の通りである。
-
MPOL_F_STATIC_NODES (Linux-2.6.26
以降)
- 空でない nodemask
は、物理ノード ID
である。 Linux
では、そのスレッドが異なる
CPU 集合コンテキスト
(cpuset context)
に移動した場合でも、そのスレッドの現在の
CPU
集合コンテキストで
許可されているノード集合が変化した場合でも、
nodemask
をマッピングし直すことはない。
-
MPOL_F_RELATIVE_NODES (Linux-2.6.26
以降)
- 空でない nodemask
は、そのスレッドの現在の
CPU
集合で許可されているノード
ID 集合
における相対的なノード
ID である。
nodemask は、最大で
maxnode
ビットから構成されるノードのビットマスクを指す。
ビットマスクの大きさは、直近の
sizeof(unsigned long)
の倍数に切り上げられるが、カーネルが使用するのは
maxnode
個までのビットだけである。
NULL 値の
nodemask
もしくは値が 0 の
maxnode
はノードの空集合を表す。
maxnode の値が 0 の場合、
nodemask
引数は無視される。
nodemask
が必須の場面では、
nodemask
に、オンラインで、そのスレッドの現在の
CPU 集合コンテキストで
許可されており (
MPOL_F_STATIC_NODES
モードフラグが指定されていない場合)、メモリーがあるノードが
少なくとも一つ入っていなければならない。
mode
引数には、以下の値のいずれかひとつを含めなければならない。
- MPOL_DEFAULT
- このモードはデフォルトではないメモリーポリシーを削除し、
デフォルトの動作に戻すことを指定するものである。
mbind()
経由で、あるメモリー領域に対して
MPOL_DEFAULT
が適用された場合、スレッドのメモリポリシーを使用することを意味する。
スレッドのメモリポリシーは、
set_mempolicy(2)
で変更されているかもしれない。
スレッドのメモリポリシーのモードも
MPOL_DEFAULT
の場合、システム全体のデフォルトポリシーが使用される。
システム全体のデフォルトポリシーでは、割り当てのきっかけとなった
CPU
のノードからページの割り当てを行う。
MPOL_DEFAULT では、引数
nodemask と maxnode
にノードの空集合を指定しなければならない。
- MPOL_BIND
- This mode specifies a strict policy that restricts memory
allocation to the nodes specified in nodemask. If nodemask
specifies more than one node, page allocations will come from the node
with sufficient free memory that is closest to the node where the
allocation takes place. Pages will not be allocated from any node not
specified in the IR nodemask . (Before Linux 2.6.26, page allocations came
from the node with the lowest numeric node ID first, until that node
contained no free memory. Allocations then came from the node with the
next highest node ID specified in nodemask and so forth, until none
of the specified nodes contained free memory.)
- MPOL_INTERLEAVE
- このモードは、メモリー割り当てが
nodemask
に指定されたノード間で交互に行われることを指定するものである。
このポリシーでは、複数のノードにページを広げて配置し、これらのページへの
メモリーアクセスを分散することで、遅延ではなく、帯域を最適化する。
効果を得るには、メモリー領域をある程度大きくすべきであり、
メモリーアクセスのパターンがかなり均一な場合でも
少なくとも 1 MB
以上にすべきである。
このモードでも、一つのページへのアクセスに関しては
一つのノードのメモリー帯域が上限となることは変わりない。
- MPOL_PREFERRED
- このモードは、割り当て時に優先されるノードを設定する。
カーネルはまず優先ノードにページ割り当てを行おうとし、
優先ノードに空きメモリーが少ない場合に他のノードに割り当てを行う。
nodemask に複数のノード
ID
が指定された場合は、
nodemask
内の最初のノードが優先ノードとして選択される。
引数 nodemask, maxnode
で空集合が指定された場合は、割り当てのきっかけとなった
CPU のノードに
メモリー割り当てが行われる。
-
MPOL_LOCAL (Linux 3.8 以降)
- This mode specifies "local allocation"; the
memory is allocated on the node of the CPU that triggered the allocation
(the "local node"). The nodemask and maxnode
arguments must specify the empty set. If the "local node" is low
on free memory, the kernel will try to allocate memory from other nodes.
The kernel will allocate memory from the "local node" whenever
memory for this node is available. If the "local node" is not
allowed by the thread's current cpuset context, the kernel will try to
allocate memory from other nodes. The kernel will allocate memory from the
"local node" whenever it becomes allowed by the thread's current
cpuset context. By contrast, MPOL_DEFAULT reverts to the memory
policy of the thread (which may be set via set_mempolicy(2)); that
policy may be something other than "local allocation".
flags に
MPOL_MF_STRICT が
指定され、
mode が
MPOL_DEFAULT でない場合、
指定されたポリシーに従っていないメモリー領域にページが存在すると、
mbind() はエラー
EIO
で失敗する。
flags に
MPOL_MF_MOVE
が指定されると、カーネルはそのメモリー領域内の既存の全てのページを移動し、
指定されたポリシーに従うようにしようとする。
他のプロセスと共有されているページは移動されない。
MPOL_MF_STRICT
も指定された場合、移動できなかったページがあると、
mbind() はエラー
EIO
で失敗する。
flags に
MPOL_MF_MOVE_ALL
が指定されると、カーネルはそのメモリー領域内の既存の全てのページを、
他のプロセスがページを使用しているかどうかに関わらず移動する。
このフラグを使用するには、呼び出し元のスレッドは特権
(
CAP_SYS_NICE)
を持っていなければならない。
MPOL_MF_STRICT
も指定された場合、移動できなかったページがあると、
mbind() はエラー
EIO
で失敗する。
成功すると、
mbind() は 0
を返す。エラーの場合、-1
を返し、
errno
にエラーを示す値を設定する。
- EFAULT
-
nodemask と maxnode
で指定されたメモリー領域の一部または全部が、
呼び出し元がアクセス可能なアドレス空間外を指している。
もしくは addr と len
で指定されたメモリー領域にマップされていない部分
(unmapped hole) があった、
- EINVAL
-
flags や mode
に不正な値が指定された。
addr + len が addr
より小さい。 addr
がシステムのページサイズの倍数になっていない。
または mode が MPOL_DEFAULT で
nodemask
に空でない集合が指定された。
mode が MPOL_BIND か MPOL_INTERLEAVE
で nodemask
が空であった。 maxnode
がカーネルに適用された上限を超えている。
nodemask
に、サポートされている最大ノード
ID
より大きいノードが指定された。
nodemask
に、オンラインで、かつそのスレッドの現在の
CPU
集合コンテキストで
許可されているノードが一つも含まれていないか、
メモリーを含むノードが一つも指定されていない。
mode 引数に MPOL_F_STATIC_NODES と
MPOL_F_RELATIVE_NODES
の両方が指定された。
- EIO
-
MPOL_MF_STRICT
が指定されたが、このポリシーに従っていないノードに
すでにページが存在していた。
もしくは MPOL_MF_MOVE か
MPOL_MF_MOVE_ALL
が指定されたが、カーネルが指定された領域内の既存の全てのページを
移動することができなかった。
- ENOMEM
- 利用可能なカーネルメモリーが十分でなかった。
- EPERM
-
flags 引数に
MPOL_MF_MOVE_ALL
フラグが含まれているが、呼び出し元が
CAP_SYS_NICE
特権を持たない。
mbind()
システムコールはバージョン
2.6.7 で Linux
カーネルに追加された。
このシステムコールは
Linux 固有である。
ライブラリによるサポートについては
numa(7) を参照。
NUMA ポリシーは、
MAP_SHARED
フラグが指定されてマップされたメモリーマップファイルの領域では
サポートされていない。
MPOL_DEFAULT モードは、
mbind()
と
set_mempolicy(2)
で異なる効果を持つことができる。
set_mempolicy(2) で
MPOL_DEFAULT
が指定された場合、そのスレッドのメモリポリシーはシステムの
デフォルトポリシー、すなわちローカルからの割り当て、に戻る。
mbind()
を使ってメモリーのある領域に
MPOL_DEFAULT
が指定された場合、その範囲に対してそれ以降に行われるページの割り当てでは、
set_mempolicy(2)
で設定したのと同じように、そのスレッドのメモリポリシーが適用される。
これにより、特定のメモリー領域についてだけ明示的なポリシーを削除し、
デフォルトのポリシーに「戻す」ことができる。
あるメモリー領域に対して「ローカルからの割り当て」を明示的に設定するには、
mode に
MPOL_LOCAL か
MPOL_PREFERRED
を指定し、
nodemask
に空集合のノードを指定すればよい。
この方法は
set_mempolicy(2)
でも通用する。
2.6.16
でヒュージページポリシーへの対応が追加された。
インターリーブポリシーがヒュージページのマッピングで効果を持つには、
ポリシーが適用されるメモリーが数十メガバイト以上である必要がある。
Linux 5.7 より前では、
MPOL_MF_STRICT
はヒュージページのマッピングでは無視されていた。
MPOL_MF_MOVE と
MPOL_MF_MOVE_ALL は Linux 2.6.16
以降でのみ利用可能である。
get_mempolicy(2),
getcpu(2),
mmap(2),
set_mempolicy(2),
shmat(2),
shmget(2),
numa(3),
cpuset(7),
numa(7),
numactl(8)
この man ページは Linux
man-pages
プロジェクトのリリース
5.10
の一部である。プロジェクトの説明とバグ報告に関する情報は
https://www.kernel.org/doc/man-pages/
に書かれている。