プログラミングインタフェース

近傍性グループ、スレッド、およびメモリー配置

この節では、各 lgroup のスレッドとメモリー配置を検出し、制御するために使用する API について説明します。

lgrp_home() の使用法

lgrp_home() 関数は、指定したプロセスまたはスレッドのホーム lgroup を返します。

#include <sys/lgrp_user.h>
lgrp_id_t lgrp_home(idtype_t idtype, id_t id);

無効な ID タイプを指定した場合、lgrp_home() 関数は EINVAL を返します。呼び出しプロセスの実効ユーザーがスーパーユーザーではなく、実ユーザー ID または実効ユーザー ID が指定したスレッドの実ユーザー ID または実効ユーザー ID とも一致しない場合、lgrp_home() 関数は EPERM を返します。指定したプロセスまたはスレッドが存在しない場合は、lgrp_home() 関数は ESRCH を返します。

madvise() の使用法

madvise() 関数は、ユーザーの仮想メモリー領域の addr で指定された開始アドレスから len パラメータの値で示される長さの範囲について特定の使用パターンに従うように、カーネルに対してアドバイス情報を与えます。カーネルはこの情報を使用して、指定された範囲に関連付けられた資源の操作と管理の手順を最適化します。メモリーに対するアクセスパターンに関する適切な情報を持つプログラムで madvise() 関数を使用できれば、システム性能を向上させることができます。

#include <sys/types.h>
#include <sys/mman.h>
int madvise(caddr_t addr, size_t len, int advice);

madvise() 関数では、複数 lgroup に対するスレッドのメモリーの割り当て方法を操作するために、次のフラグが提供されています。

MADV_ACCESS_DEFAULT

このフラグは、指定範囲に関して期待されるカーネルのアクセスパターンを取り消してデフォルトに戻します。

MADV_ACCESS_LWP

このフラグは、指定のアドレス範囲に次回アクセスする LWP が、その領域にもっとも頻繁にアクセスする LPW であることをカーネルに指定します。それに応じて、カーネルはメモリーやほかの資源をこの領域と LWP に割り当てます。

MADV_ACCESS_MANY

このフラグは、多くのプロセスまたは LPW が、ランダムにシステム全域から指定の領域にアクセスしていることをカーネルに指定します。それに応じて、カーネルはメモリーやほかの資源をこの領域に割り当てます。

madvise() 関数は、次の値を返します。

EAGAIN

addr から addr+len までのアドレス範囲で指定されたマッピング領域の全体または一部が、入出力操作によりロックされている場合。

EINVAL

addr パラメータの値が sysconf(3C) で返されるページサイズの倍数ではない、指定したアドレス範囲の長さがゼロ以下、またはアドバイスが無効の場合。

EIO

ファイルシステムに対する読み取りや書き込み中に入出力エラーが発生した場合。

ENOMEM

指定したアドレス範囲のアドレスが、プロセスの有効なアドレス空間の範囲外、またはマップされていないページが指定されている場合。

ESTALE

NFS ファイルハンドルが無効の場合。

madv.so.1 の使用法

共有オブジェクト madv.so.1 は、起動されたプロセスやその子プロセスに対して選択された仮想メモリーの構成を実現します。共有オブジェクトを使用するには、環境変数に次の文字列を指定する必要があります。

LD_PRELOAD=$LD_PRELOAD:madv.so.1

madv.so.1 共有オブジェクトは、 MADV 環境変数の値に従ってメモリーのアドバイス情報を適用します。MADV 環境変数は、プロセスのアドレス空間におけるすべてのヒープ、共有メモリー、および mmap 領域のために使用する仮想メモリーのアドバイス情報を指定します。この情報は生成されたすべてのプロセスに適用されます。次に示す MADV 環境変数値は、複数の lgroup 間での資源の割り当てに影響を与えます。

access_default

この値は、カーネルに期待されるアクセスパターンをデフォルトに戻します。

access_lwp

この値は、アドレス範囲に次回アクセスする LWP が、その領域にもっとも頻繁にアクセスする LPW であることをカーネルに指定します。それに応じて、カーネルはメモリーやほかの資源をこの領域と LWP に割り当てます。

access_many

この値は、多くのプロセスまたは LPW が、ランダムにシステム全域からメモリーにアクセスしていることをカーネルに指定します。それに応じて、カーネルはメモリーやほかの資源を割り当てます。

MADVCFGFILE 環境変数の値は、1 つまたは複数のメモリーのアドバイス情報構成エントリが exec-name: advice-opts の書式で記述されているテキストファイルの名前です。

exec-name の値は、アプリケーションまたは実行プログラムの名前です。exec-name には、フルパス名、基本名、またはパターン文字列による指定が可能です。

advice-opts の値は、region=advice の書式で表します。advice の値は、MADV 環境変数の値と同じです。region には、次のいずれかの規定された値を指定します。

madv

プロセスのアドレス空間のすべてのヒープ、共有メモリー、および mmap(2) 領域に、アドバイスが適用されます。

heap

ヒープは、brk(2) 領域として定義されます。アドバイス情報は、既存のヒープにも将来割り当てられる追加ヒープメモリーにも適用されます。

shm

アドバイス情報は、共有メモリーセグメントに適用されます。共有メモリー操作に関する詳細は、shmat(2) を参照してください。

ism

アドバイス情報は、SHM_SHARE_MMU フラグを使用している共有メモリーセグメントに適用されます。ism オプションは、shm より優先されます。

dsm

アドバイス情報は、SHM_PAGEABLE フラグを使用している共有メモリーセグメントに適用されます。dsm オプションは、shm より優先されます。

mapshared

アドバイス情報は、MAP_SHARED フラグを使用した mmap() システムコールにより作成されたマッピングに適用されます。

mapprivate

アドバイス情報は、MAP_PRIVATE フラグを使用した mmap() システムコールにより作成されたマッピングに適用されます。

mapanon

アドバイス情報は、MAP_ANON フラグを使用した mmap() システムコールにより作成されたマッピングに適用されます。複数のオプションが指定された場合は、mapanon オプションが優先されます。

MADVERRFILE 環境変数値は、エラーメッセージが記録されるパスの名前です。MADVERRFILE による指定がない場合は、madv.so.1 共有オブジェクトは syslog(3C) を使用してエラーを記録します。重要度は LOG_ERR、機能記述子は LOG_USER になります。

メモリーに関するアドバイス情報は継承されます。子プロセスには親と同じアドバイス情報が適用されます。madv.so.1 共有オブジェクトにより異なるレベルのアドバイスを設定しない限り、exec(2) が呼び出されたあとには、アドバイスはシステムデフォルトの設定に戻されます。アドバイス情報は、ユーザープログラムによって作成された mmap() 領域にのみ適用されます。実行時リンカーまたはシステムライブラリによって作成された直接システムコールを呼び出す領域は影響を受けません。

madv.so.1 の使用例

次の例では、madv.so.1 共有オブジェクトの機能について個別に説明します。


例 5–2 アプリケーションセットへのアドバイスの設定

この設定では、exec が foo で始まるすべてのアプリケーションの ISM セグメントにアドバイス情報を適用しています。

$ LD_PRELOAD=$LD_PRELOAD:madv.so.1
$ MADVCFGFILE=madvcfg
$ export LD_PRELOAD MADVCFGFILE
$ cat $MADVCFGFILE
        foo*:ism=access_lwp


例 5–3 特定のアプリケーションセットに対するアドバイスの除外

この設定では、ls を除くすべてのアプリケーションにアドバイスを適用しています。

$ LD_PRELOAD=$LD_PRELOAD:madv.so.1
$ MADV=access_many
$ MADVCFGFILE=madvcfg
$ export LD_PRELOAD MADV MADVCFGFILE
$ cat $MADVCFGFILE
        ls:


例 5–4 構成ファイルでのパターンマッチの使用

MADVCFGFILE に指定された構成は MADV の設定値より優先されるので、ファイルの最後の構成エントリで exec-name に指定した * は、MADV を指定した場合と同じ意味になります。この例は、前述の例と同じ結果になります。

$ LD_PRELOAD=$LD_PRELOAD:madv.so.1
$ MADVCFGFILE=madvcfg
$ export LD_PRELOAD MADVCFGFILE
$ cat $MADVCFGFILE
        ls:
        *:madv=access_many


例 5–5 複数の領域に対するアドバイス

この構成では、あるアドバイスのタイプを mmap() 領域に適用し、さらに別のアドバイスのタイプを exec() の名前が foo で始まるアプリケーションのヒープおよび共有メモリー領域に対して適用しています。

$ LD_PRELOAD=$LD_PRELOAD:madv.so.1
$ MADVCFGFILE=madvcfg
$ export LD_PRELOAD MADVCFGFILE
$ cat $MADVCFGFILE
        foo*:madv=access_many,heap=sequential,shm=access_lwp

meminfo() の使用法

meminfo() 関数は、システムにより割り当てられた仮想メモリーおよび物理メモリーに関する情報を、呼び出しプロセスに提供します。

#include <sys/types.h>
#include <sys/mman.h>
int meminfo(const uint64_t inaddr[], int addr_count,
    const uint_t info_req[], int info_count, uint64_t outdata[],
    uint_t validity[]);

meminfo() 関数は、次に示す情報を返します。

MEMINFO_VPHYSICAL

指定した仮想アドレスに対応する物理メモリーのアドレス

MEMINFO_VLGRP

指定した仮想アドレスに対応する物理ページがある lgroup

MEMINFO_VPAGESIZE

指定した仮想アドレスに対応する物理ページのサイズ

MEMINFO_VREPLCNT

指定した仮想アドレスに対応する物理ページの複製の数

MEMINFO_VREPL|n

指定した仮想アドレスの n 番目の物理ページの複製

MEMINFO_VREPL_LGRP|n

指定した仮想アドレスの n 番目の物理ページの複製がある lgroup

MEMINFO_PLGRP

指定した物理アドレスがある lgroup

meminfo() 関数には、次のパラメータを指定できます。

inaddr

入力アドレスの配列。

addr_count

meminfo() 関数に渡されるアドレスの数。

info_req

要求される情報のタイプをリストする配列。

info_count

inaddr 配列にある各アドレスについて要求された情報の数。

outdata

meminfo() 関数が結果を返す配列。配列のサイズは、info_reqaddr_count パラメータに指定した値の積になります。

validity

addr_count パラメータの値と同じサイズの配列。validity 配列にはビット単位の結果コードが返されます。結果コードの 0 番目のビットでは、対応する入力アドレスの有効性が評価されています。続くビットでは、info_req 配列のメンバーへの応答の有効性が順番に評価されています。

outdata または validity 配列が指しているメモリー領域に書き込めない場合、meminfo() 関数は EFAULT を返します。info_req または inaddr 配列が指しているメモリー領域から読み込めない場合は、meminfo() 関数は EFAULT を返します。info_count の値が 31 より大きいか、または 1 より小さい場合は、meminfo() 関数は EINVAL を返します。addr_count() の値がゼロより小さい場合は、meminfo 関数は EINVAL を返します。


例 5–6 仮想アドレスのセットに対応する物理ページとページサイズを出力する meminfo() の使用法

void
print_info(void **addrvec, int how_many)
{
        static const int info[] = {
                MEMINFO_VPHYSICAL,
                MEMINFO_VPAGESIZE};
        uint64_t * inaddr = alloca(sizeof(uint64_t) * how_many);
        uint64_t * outdata = alloca(sizeof(uint64_t) * how_many * 2;
        uint_t * validity = alloca(sizeof(uint_t) * how_many);

        int i;

        for (i = 0; i < how_many; i++)
                inaddr[i] = (uint64_t *)addr[i];

        if (meminfo(inaddr, how_many,  info,
                    sizeof (info)/ sizeof(info[0]),
                    outdata, validity) < 0)
                ...

        for (i = 0; i < how_many; i++) {
                if (validity[i] & 1 == 0)
                        printf("address 0x%llx not part of address
                                        space\n",
                                inaddr[i]);

                else if (validity[i] & 2 == 0)
                        printf("address 0x%llx has no physical page
                                        associated with it\n",
                                inaddr[i]);

                else {
                        char buff[80];
                        if (validity[i] & 4 == 0)
                                strcpy(buff, "<Unknown>");
                        else
                                sprintf(buff, "%lld", outdata[i * 2 +
                                                1]);
                        printf("address 0x%llx is backed by physical
                                        page 0x%llx of size %s\n",
                                        inaddr[i], outdata[i * 2], buff);
                }
        }
}

近傍性グループのアフィニティー

スレッドの軽量プロセス (LWP) が作成されるとき、カーネルはスレッドに近傍性グループを割り当てます。そのような lgroup は、スレッドのホーム lgroup と呼ばれます。カーネルは、スレッドをホーム lgroup の CPU で実行し、可能な限り lgroup からメモリーを割り当てます。ホーム lgroup の資源が使用可能でない場合は、ほかの lgroup から資源を割り当てます。スレッドに 1 つまたは複数の lgroup に対するアフィニティーがある場合は、オペレーティングシステムはアフィニティーの強さに応じて lgroup から順に資源を割り当てます。lgroup は、次の 3 つのアフィニティーレベルのうち 1 つを持つことができます。

  1. LGRP_AFF_STRONG は強いアフィニティーを示します。この lgroup がスレッドのホーム lgroup であるとき、オペレーティングシステムは、そのスレッドのホーム lgroup を変更する再ホーミングをできるだけ避けようとします。その場合でも、動的再構成、プロセッサのオフライン化、プロセッサ割り当て、プロセッサセットの割り当ておよび操作などのイベントは、スレッドの再ホーミングにつながる可能性があります。

  2. LGRP_AFF_WEAK は、弱いアフィニティーを示します。この lgroup がスレッドのホーム lgroup であるとき、オペレーティングシステムは、負荷均衡の必要に応じてスレッドの再ホーミングを行います。

  3. LGRP_AFF_NONE はアフィニティーを持たないことを示します。スレッドがどの lgroup にもアフィニティーを持たないとき、オペレーティングシステムはそのスレッドにホーム lgroup を割り当てます。

指定されたスレッドに資源を割り当てるときに、オペレーティングシステムは lgroup のアフィニティーをアドバイスとして使用します。このアドバイスはほかのシステム制限とともに考慮されます。プロセッサ割り当ておよびプロセッサセットによって lgroup のアフィニティーが影響を受けることはありませんが、スレッドが実行される lgroup を制限する場合があります。

lgrp_affinity_get() の使用法

lgrp_affinity_get(3LGRP) 関数は、指定した lgroup に対して LWP が持つアフィニティーを返します。

#include <sys/lgrp_user.h>
lgrp_affinity_t lgrp_affinity_get(idtype_t idtype, id_t id, lgrp_id_t lgrp);

idtype および id 引数により、lgrp_affinity_get() 関数で検証する LWP を指定します。idtype の値に P_PID を指定した場合、lgrp_affinity_get() 関数は、id 引数の値と一致するプロセス ID を持つプロセスにある LWP のいずれかについて lgroup アフィニティーを取得します。idtypeP_LWPID を指定した場合、lgrp_affinity_get() 関数は、実行中のプロセスにある、id 引数の値と一致する LWP ID を持つ LWP について lgroup アフィニティーを取得します。idtypeP_MYID を指定した場合、lgrp_affinity_get() 関数は、実行中の LPW について lgroup アフィニティーを取得します。

指定した lgroup または ID タイプが有効でないとき、lgrp_affinity_get() 関数は EINVAL を返します。呼び出しプロセスの実効ユーザーがスーパーユーザーではなく、呼び出しプロセスの ID がどの LPW の実ユーザー ID または実効ユーザー ID とも一致しない場合、lgrp_affinity_get() 関数は EPERM を返します。指定した lgroup または LPW が存在しない場合は、lgrp_affinity_get() 関数は ESRCH を返します。

lgrp_affinity_set() の使用法

lgrp_affinity_set(3LGRP) 関数は、指定した lgroup に対して LWP または LWP のセットが持つアフィニティーを設定します。

#include <sys/lgrp_user.h>
int lgrp_affinity_set(idtype_t idtype, id_t id, lgrp_id_t lgrp,
                      lgrp_affinity_t affinity);

idtype および id 引数により、lgrp_affinity_set() 関数で検証する LWP または LWP のセットを指定します。idtypeP_PID を指定した場合、lgrp_affinity_set() 関数は、id 引数の値が一致するプロセス ID を持つプロセスのすべての LWP について、lgroup アフィニティーを affinity 引数で指定したアフィニティーレベルに設定します。idtypeP_LWPID を指定した場合、lgrp_affinity_set() 関数は、id 引数の値が一致する LWP ID を持つ実行プロセス中の LWP について、lgroup アフィニティーを affinity 引数で指定したアフィニティーレベルに設定します。idtypeP_MYID を指定した場合は、lgrp_affinity_set() 関数は、実行中の LWP またはプロセスについて、lgroup アフィニティーを affinity 引数で指定したアフィニティーレベルに設定します。

指定した lgroup、アフィニティー、または ID タイプが有効でないとき、lgrp_affinity_set() 関数は EINVAL を返します。呼び出しプロセスの実効ユーザーがスーパーユーザーではなく、呼び出しプロセスの ID がどの LPW の実ユーザー ID または実効ユーザー ID とも一致しない場合、lgrp_affinity_set() 関数は EPERM を返します。指定した lgroup または LPW が存在しない場合は、lgrp_affinity_set() 関数は ESRCH を返します。