このトピックは、インテル® メニー・インテグレーテッド・コア (インテル® MIC) アーキテクチャーにのみ適用されます。
コプロセッサーのユーザー割り当てデータでは、malloc や _mm_malloc の代わりに mmap() で大きな (2MB の) ページ割り当てを使用すると、アプリケーションのパフォーマンスが向上する場合があります。
malloc と _mm_malloc のデフォルトのページサイズは 4KB で、サイズが 2MB の THP (トランスペアレント・ヒュージ・ページ) は現在サポートされていません。 このため、メモリーを割り当てる前に 2MB ページを手動で予約し、mmap() を使用してメモリーを割り当てる必要があります。
すべてのアプリケーションで大きなページサイズを使用するメリットがあるわけではありません。一般に、大きなページサイズがパフォーマンスに影響するかどうかはデータ・アクセス・パターンに大きく依存します。アプリケーションが異なるページに割り当てられた複数のデータ構造にアクセスする場合、コプロセッサーの 2MB ページに 8 つの TLB (トランスレーション・ルックアサイド・バッファー) エントリーしかないとパフォーマンスの低下を引き起こします。
コプロセッサーで使用できる 2MB ページの数を制御するには、コプロセッサーの /proc/sys/nr_hugepages に値を記述します。
例えば、コプロセッサーで次のコマンドを実行すると、Linux* uOS はサイズがそれぞれ 2MB の 5 つのヒュージページを構成します。
echo 5 >/proc/sys/vm/nr_hugepages
アプリケーションのすべての malloc で必要なページの合計値を指定することを推奨します。 例えば、アプリケーションにページ数 P1 と P2 が必要な 2 つの malloc が含まれる場合、P1+P2 の合計の値を記述します。 ファイルを解析して現在の値を取得し、必要な値を追加して、ファイルに新しい値を書き込むこともできます。すべての割り当てではじめから合計のページ数を要求すると、メモリーの断片化が改善され、要求した割り当てが行われる可能性が高くなります。
この変更を行うアトミックなインターフェイスはありません。この変更により、フリープールで利用可能な物理メモリーは少なくなります。このファイルの値が減ると、uOS はメモリーが実際に解放されるまで待ちます。
コンパイラーは、要求されたページサイズに対するユーザー制御を提供しません。2MB ページを割り当てるアプローチのサンプルを次に示します。
2MB ページを割り当てるには、HUGE_TLB フラグを使用して mmap() を呼び出します。 要求を満たせない場合は、MAP_FAILED が返されます。
/proc/meminfo を使用して、コプロセッサーで使用している 2MB ページの数をモニターすることができます
コプロセッサーで次のコマンドを使用します。
cat /proc/meminfo
出力には次の値が含まれます。
... HugePages_Total: 0 HugePages_Free: 0 HugePages_Rsvd: 0 HugePages_Surp: 0 Hugepagesize: 2048 kB ...
下記の関数 allocate_huge_pages() は、Linux* uOS で複数の 2MB ページを割り当てる方法の例です。
/* ヒュージページのサポートを使用してメモリーを割り当て */
#define MALLOC_2M(size) \
mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | \
MAP_PRIVATE | MAP_HUGETLB, -1, 0);
size_t _get_huge_pages()
{
FILE * f;
size_t sz = 0;
char rvalue[128] = {0};
f = popen("cat /proc/sys/vm/nr_hugepages","r");
if(f==NULL)
return -1;
sz = fread(rvalue, 1, sizeof(rvalue)-1, f);
if(sz==0) {
pclose(f);
return -1;
}
pclose(f);
if (rvalue[0])
return atoi(rvalue);
else {
errno = ENODATA;
return -1;
}
}
int _set_huge_pages(size_t pages)
{
int rval = 0;
char cmd[256];
sprintf(cmd, "echo %d > /proc/sys/vm/nr_hugepages", (int)pages);
rval = system(cmd);
return rval;
}
void* allocate_huge_pages(size_t size)
{
size_t current_pages = 0;
size_t request_pages = 0;
current_pages = _get_huge_pages();
if( current_pages == -1)
return MAP_FAILED;
request_pages = size/1024/1024/2 + 1;
request_pages += current_pages;
int err = _set_huge_pages(request_pages);
if( err == -1)
return MAP_FAILED;
return MALLOC_2M(size);
}