こんにちは。
前回はページテーブルエントリ(以下、PTE)の与える影響について説明しましたが、
今回はHugePageの仕組みについて検証を交えて説明します。
HugePageの仕組み
早速ですが、
実際にHugePageを使用した場合と使用しなかった場合でのPTEの獲得のされ方を確認したいと思います。
まず、HugePageによって縮小される範囲についてですが、デフォルトの設定ですと以下のようなページテーブルが獲得されます。

今回は2M HugePageを使用します。
これによりページテーブルの獲得が以下のように変化します。

HugePageの設定によってpte_t部分がpmd_t内のHugeTableビット設定によって省略されます。最後のオフセットは 、pte_t 分拡張され21bitとなります。
つまり、通常の設定4Kページと比べ、1/512 PageTableのサイズを縮小できることになります。
なお、ここで補足ですが、HugePageはmmap、shmgetシステムコールなどから獲得が可能で、malloc関数などで取得したプロセスのプライベート領域については使用できません。
つまりOracleDatabase(以下、Oracle)で考えた場合は、PGA領域は引き続き個別の設定が必要となります。
ひとまず、PTEの獲得が前回記載した通りの値となるのかを簡易プログラムで確認し、
次にOracleを実際に使用して確認したいと思います。
検証
今回は、以下のようなシンプルな共有メモリを使用するプログラムで行います。
※紙面の都合でヘッダファイル部分は省略しています。
<共有メモリをアロケートするプログラム: server.o>
int main(void) { int id; char *adr; if((id = shmget(IPC_PRIVATE, 1073741824, IPC_CREAT|0666)) == -1) { perror("shmget"); exit(-1); } if(( adr = (char *)shmat(id, NULL, 0)) == (void *)-1){ perror("shmat"); } else { while(1) { if (strcmp(adr, "quit") == 0) { break; } sleep(1); } if(shmdt(adr)==-1){ perror("shmdt"); } } if(shmctl(id, IPC_RMID, 0)==-1) { exit(EXIT_FAILURE); } return 0; }
<共有メモリをアタッチするプログラム: client.o>
int main(int argc, char *argv[]) { int id; char *adr; char a; char d; char *b; size_t msize; if( argc <= 1) { exit(EXIT_FAILURE); } id = atoi(argv[1]); msize=atoi(argv[2]); printf("共有メモリにアタッチする\n"); scanf("%c",&a); if(( adr = (char *)shmat(id,0,0)) == (void *)-1) { return 1; } scanf("%c",&a); printf("共有メモリをよむ\n"); scanf("%c",&a); memset(adr,0,msize); scanf("%c",&a); printf("共有メモリを開放する\n"); scanf("%c",&a); strcpy(adr,"quit"); }
<コンソールA> # server.o # ipcs ★ 獲得した共有メモリのIDを取得 <コンソールB> # client.o <共有メモリID> <アタッチするサイズ> 共有メモリにアタッチする 1 共有メモリをよむ 1 共有メモリを解放する 1
PTEの確認はclient.oが「共有メモリをよむ(というか書く)」を行った後に獲得されたPTEを確認します。
確認した結果が以下になります。
# ps -ef|grep client root 8749 ./client.o 3145731 1073741824 # grep PTE /proc/8749/status VmPTE: 2084 kB #
1GBの共有メモリに対して、2MBのPTEが消費されています。
OracleのSGAの構造上全領域をアタッチするということは考えにくいですが、それでも1セッションで獲得される領域にしては大きすぎるサイズです。
次回は、Oracleを使用して4KページとHugePageの動作比較を行います。