AsiaBSDCon 帰りの同僚に先週聞いたんですが、OpenBSD 5.0 の pthread 実装では、複数スレッド走らせても 1 コアしか使わない(ので速くならない)そうです。

えー、と思って以下のプログラムで 2 スレッド走らせてみます。

#include <pthread.h>

volatile int n;

void *proc(void *arg)
{
        for (;;)
                n++;
}

int main(void)
{
        pthread_t ptid;

        pthread_create(&ptid, NULL, proc, NULL);
        proc(NULL);
        return 0;
}

んで top コマンドで CPU 使用率を見てみると…

load averages:  0.38,  0.15,  0.10                    devopenbsd.local 10:04:05
26 processes:  24 idle, 2 on processor
CPU0 states:  0.0% user,  0.0% nice,  0.0% system,  0.0% interrupt,  100% idle
CPU1 states:  0.0% user,  0.0% nice,  0.0% system,  0.0% interrupt,  100% idle
CPU2 states:  0.0% user,  0.0% nice,  0.0% system,  0.0% interrupt,  100% idle
CPU3 states:  100% user,  0.0% nice,  0.0% system,  0.0% interrupt,  0.0% idle
Memory: Real: 14M/137M act/tot Free: 347M Cache: 88M Swap: 0K/1024M

  PID USERNAME PRI NICE  SIZE   RES STATE     WAIT      TIME    CPU COMMAND
28750 umezawa   64    0 1656K 1244K onproc/1  -         0:17 56.05% pthread-run
 1304 _syslogd   2    0  624K  960K sleep/0   poll      2:23  0.00% syslogd
14212 _pflogd    4    0  644K  384K sleep/2   bpf       1:32  0.00% pflogd
 7883 umezawa    2    0 3476K 2372K sleep/1   select    1:12  0.00% sshd
(以下略)

ほんまや。

ちなみに Linux (CentOS 6, kernel-2.6.32-220.7.1.el6.x86_64) だと、以下のようにちゃんと 2 コア使っています。

top - 10:06:00 up 18 days,  8:43,  9 users,  load average: 1.06, 0.28, 0.09
Tasks: 158 total,   2 running, 156 sleeping,   0 stopped,   0 zombie
Cpu0  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu1  :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu2  :  0.3%us,  0.3%sy,  0.0%ni, 99.3%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu3  :100.0%us,  0.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:    502224k total,   438068k used,    64156k free,    33720k buffers
Swap:  1015800k total,    21324k used,   994476k free,   195152k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
13661 umezawa   20   0 16440  496  392 R 200.0  0.1   1:24.29 pthread-run
    1 root      20   0 19272  696  508 S  0.0  0.1   0:01.21 init
    2 root      20   0     0    0    0 S  0.0  0.0   0:00.01 kthreadd
    3 root      RT   0     0    0    0 S  0.0  0.0   0:00.13 migration/0
(以下略)

OpenBSD の pthread にはスピンロックがないんですが、それはこのせいだったんですね。(シングルプロセッサ環境ではスピンロックは使っていけない)

ただし、よくあるユーザーランドスレッド(協調的マルチスレッド)と違い、ちゃんとプリエンプティブです。つまり、スレッドを切り替える関数やシステムコールを呼ばなくても、カーネルが勝手に切り替えてくれます。これは以下のコードで確認できます。

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

volatile long long n0 = 0;
volatile long long n1 = 0;

void *proc(void *arg)
{
        volatile long long *np = arg;

        for (;;)
                (*np)++;
}

void sigint(int sig)
{
        printf("\n");
        printf("n0 = %lld\n", n0);
        printf("n1 = %lld\n", n1);
}

int main(void)
{
        pthread_t ptid;

        signal(SIGINT, sigint);
        pthread_create(&ptid, NULL, proc, (void *)&n1);
        proc((void *)&n0);
        return 0;
}

printf() はシグナルセーフではないとか細かいことは言いっこなしで。

で、これを実行すると、

[umezawa@devopenbsd:ttyp0 ~]$ ./pthread-run
^C
n0 = 203792139
n1 = 206249524
^C
n0 = 470482870
n1 = 474856626
^C
n0 = 830385269
n1 = 828581258
^C
n0 = 1135243828
n1 = 1139698685

となって、2 つのスレッドが同じ時間だけ走っていることが分かります。(協調的マルチスレッドの場合だと一方のカウンタだけが進んでいくはず)

OpenBSD-current では複数コア使うようにコーディング中だそうです。

Trackback

only 1 comment untill now

  1. 5.1-current で試してみたら、2CPU で動くようにようになってました。
    http://yasuoka.net/~yasuoka/hack-2012.html#d20120502

Add your comment now