mmap(2)で共有メモリを実装する方法はいくつかある。前回、各方法ごとに性能を検証したところ、大きな違いは見られなかった。そこで今回は共有するデータサイズを100MBにして、あらためて性能の違いを調査していく。(編集部)
第6回ではmmap(2)を使って共有メモリを実装する方法を紹介した。mmap(2)で共有メモリを実装する場合、いくつかの選択肢があり、それぞれ性能にどういった違いがあるのかを調べた。
今回は前回の話に引き続き、共有するデータのサイズを変えた場合に性能にどのような違いが発生するのかを調査していく。
mmap(2)はメモリへのアクセスがそのままファイルへのアクセスになるところにその特徴がある。ファイルをマッピングしなくても利用できるが、本来的にはファイルに対してマッピングを実施するものだ。前回はファイルにマッピングするケースとそうでないケース、ファイルが置かれているファイルシステムをディスク上のUFSかメモリファイルシステムか、などいくつか条件を分けて性能の違いを調査した。
前回の調査ではほとんど性能の差が見られなかった。これは共有したデータのサイズが2バイトといった極めて小さいサイズだけだったからではないか、と推測した。今回は共有するデータサイズを100MBにして、同様の調査を実施する。
まず、次のように操作して実験環境を作成する。
1. ディスク上のUFS上に100MBの共有ファイルを作成
% dd if=/dev/zero of=/tmp/shm bs=104857600 count=1
2. malloc(9)バックエンドのmdconfigメモリファイルシステムUFS上に100MBの共有ファイルを作成
# mdconfig -a -t malloc -s 200M -u 0 # newfs /dev/md0 # tunefs -n enable /dev/md0 # mkdir /tmp1 # mount -o noatime /dev/md0 /tmp1 # chmod 1777 /tmp1
% dd if=/dev/zero of=/tmp1/shm bs=104857600 count=1
3. スワップバックエンドのmdconfigメモリファイルシステムUFS上に100MBの共有ファイルを作成
# mdconfig -a -t swap -s 200M -u 1 # newfs /dev/md1 # tunefs -n enable /dev/md1 # mkdir /tmp2 # mount -o noatime /dev/md1 /tmp2 # chmod 1777 /tmp2
% dd if=/dev/zero of=/tmp2/shm bs=104857600 count=1
3. tmpfsメモリファイルシステム上に100MBの共有ファイルを作成
# mkdir /tmp3 # mount -t tmpfs tmpfs /tmp3 # chmod 1777 /tmp3
% dd if=/dev/zero of=/tmp3/shm bs=104857600 count=1
前回紹介した手順とはオプションなどが少々異なっている。これはファイルシステムの条件がより同一に近づくように操作を追加したためだ。ここまで作業すると、共有ファイルを設置するファイルシステムは次のような状態になる。
% df -h | grep tmp /dev/ada0s1f 9.7G 101M 8.8G 1% /tmp /dev/md0 193M 100M 77M 56% /tmp1 /dev/md1 193M 100M 77M 56% /tmp2 tmpfs 32G 100M 32G 0% /tmp3 %
% mount | grep tmp /dev/ada0s1f on /tmp (ufs, local, noatime, soft-updates) /dev/md0 on /tmp1 (ufs, local, noatime, soft-updates) /dev/md1 on /tmp2 (ufs, local, noatime, soft-updates) tmpfs on /tmp3 (tmpfs, local) %
前回使ったソースコードを、今回は100MBのデータを読み書きするものへ変更する。一方から100MBのデータを書き込み、もう一方は書き込みが完了したのを検知したら読み出しを開始する。ソースコードはそれぞれ次のとおりとなる。
■ipc_mmap+fork.c : ファイルをマッピングしないmmap(2)で共有メモリ
#include <unistd.h>
#include <sys/mman.h>
#include <stdio.h>
int
main(void)
{
int i, rp=10;
long j;
char *s, *t, b;
s = mmap(0, 104857600, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0);
*s = '0';
if (0 == fork()) {
for (i = 0; i < rp; i++) {
while ('0' == *s)
;
t = s;
++s;
for (j = 1; j < 104857600; j++)
b = *s++;
s = t;
*s = '0';
}
}
else {
for (i = 0; i < rp; i++) {
while ('1' == *s)
;
t = s;
++s;
for (j = 1; j < 104857600; j++)
*s++ = 'a';
s = t;
*s = '1';
}
}
}
■ipc_mmap+mdconfig_malloc* : mallocバックエンドのmdconfigメモリファイルシステムUFS上のファイルをmmap(2)でマッピングしたケース
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
int
main(void)
{
int fd, i, rp=10;
long j;
char *s, *t;
fd = open("/tmp1/shm", O_RDWR);
s = mmap(0, 104857600, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
*s = '0';
for (i = 0; i < rp; i++) {
while ('1' == *s)
;
t = s;
++s;
for (j = 1; j < 104857600; j++)
*s++ = 'a';
s = t;
*s = '1';
}
}
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
int
main(void)
{
int fd, i, rp=10;
long j;
char *s, *t, b;
fd = open("/tmp1/shm", O_RDWR);
s = mmap(0, 104857600, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
for (i = 0; i < rp; i++) {
while ('0' == *s)
;
t = s;
++s;
for (j = 1; j < 104857600; j++)
b = *s++;
s = t;
*s = '0';
}
}
■ipc_mmap+mdconfig_swap* : スワップバックエンドのmdconfigメモリファイルシステムUFS上のファイルをmmap(2)でマッピングしたケース
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
int
main(void)
{
int fd, i, rp=10;
long j;
char *s, *t;
fd = open("/tmp2/shm", O_RDWR);
s = mmap(0, 104857600, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
*s = '0';
for (i = 0; i < rp; i++) {
while ('1' == *s)
;
t = s;
++s;
for (j = 1; j < 104857600; j++)
*s++ = 'a';
s = t;
*s = '1';
}
}
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
int
main(void)
{
int fd, i, rp=10;
long j;
char *s, *t, b;
fd = open("/tmp2/shm", O_RDWR);
s = mmap(0, 104857600, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
for (i = 0; i < rp; i++) {
while ('0' == *s)
;
t = s;
for (j = 1; j < 104857600; j++)
b = *s++;
s = t;
*s = '0';
}
}
Copyright © ITmedia, Inc. All Rights Reserved.