sched_setaffinity(2) を使って任意のプログラムを任意のCPU上で動かす

Linux 2.6 には sched_setaffinity(2) というシステムコールがあり、これを利用して任意のスレッドを(マルチCPU環境下で)特定の CPU で実行させることができます。http://www-06.ibm.com/jp/developerworks/linux/051028/j_l-affinity.shtml によるとリアルタイムプロセスでマネージャとなるスレッドをこのシステムコールで特定の CPU に固定する...といった応用が考えられるそうです。

へえ、と思ったのでちょっと遊んでみました。LD_PRELOAD を使って任意のプログラムを任意の CPU に固定して動かしてみます。GCC__attribute__)((constructor))( で sched_setaffinitiy(2) を呼びます。(参考: http://0xcc.net/blog/archives/000091.html)

#include <sched.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>

void __attribute__((constructor))
bind_cpu()
{
    char *p = getenv("BIND_CPU_ID");
    if (p == NULL)
        p = "0";

    int cpu_id = atoi(p);

    cpu_set_t mask;
    __CPU_ZERO(&mask);
    __CPU_SET(cpu_id, &mask);

    if (sched_setaffinity(0, sizeof(mask), &mask) == -1) {
        perror("Failed to set CPU affinity");
        exit(-1);
    }

    fprintf(stderr, "Bind main thread to CPU %d\n", cpu_id);
}

これを

% gcc -shared -fPIC -o bind_cpu.so bind_cpu.c

と共有オブジェクトとしてコンパイルして

% BIND_CPU_ID=1 LD_PRELOAD=./bind_cpu.so hostname

とすると hostname が必ず CPU ID 1 (2個目の CPU (コア)) を使って動きます。

本当に指定した ID の CPU が使われているか試してみます。ビジーループする perlワンライナーを上記のオブジェクトにリンクさせて動かします。

% BIND_CPU_ID=1 LD_PRELOAD=./bind_cpu.so perl -e 'while (1) { $i++ }';
Bind main thread to CPU 1

正しく CPU 1 に固定できていれば、ID 1 の CPU にだけ負荷がかかっているはずです。sar で確認してみます。

% sar -P ALL 1 1000
Linux 2.6.19.2-103.hatena.centos5 (kyobashira.hatena.ne.jp)     08/24/07

17:51:28          CPU     %user     %nice   %system   %iowait    %steal     %idle
17:51:29          all     50.00      0.00      0.00      0.00      0.00     50.00
17:51:29            0      0.00      0.00      0.00      0.00      0.00    100.00
17:51:29            1    100.00      0.00      0.00      0.00      0.00      0.00

17:51:29          CPU     %user     %nice   %system   %iowait    %steal     %idle
17:51:30          all     50.25      0.00      0.00      0.00      0.00     49.75
17:51:30            0      0.00      0.00      0.00      0.00      0.00    100.00
17:51:30            1    100.00      0.00      0.00      0.00      0.00      0.00

確かに CPU 1 だけ負荷が 100% になっています。おもしろ。

Binary Hacks ―ハッカー秘伝のテクニック100選

僕もバイナリアンになりたいです。