2013年5月15日水曜日

[Code reading] time command

[Motivation]
FORTRANで記述されコンパイラで自動並列化した数値解析のプログラムの実行時間を下記環境でtimeコマンドを使って測定したら下記の様な結果になった。


-実行環境-
OS: Cent OS
CPU: Intel Xeon Processor L5640 x 2

-並列数-
OMP_NUM_THREAD=12

-time コマンド結果-

real 84m23.521s
user 1010m2.767s
sys 0m7.199s


[reasoning]
user時間は、各コアのuser時間の合計となるためスレッド並列化して実行したコマンドでは、real時間よりも長くなることがある?

[research]


適当なミラーサイトからソースを取ってくる。
後、linuxカーネル(2.6.34)のソースも取ってくる。

まずは、タイムコマンドのmain関数
-time.c: main
632 main (argc, argv)
633      int argc;
634      char **argv;
635 {
636   const char **command_line;
637   RESUSE res;

640   run_command (command_line, &res);
641   summarize (outfp, output_format, command_line, &res);

run_commandという関数を見てみる
-time.c: run_command
597 static void
598 run_command (cmd, resp)
599      char *const *cmd;
600      RESUSE *resp;
601 {

605   resuse_start (resp);

614       execvp (cmd[0], cmd);

623   if (resuse_end (pid, resp) == 0)

timeコマンドで指定したコマンドをexecvp関数で実行している.
execvp関数の前後で呼んでいるresuseで始まる関数を次に見てみる

-resuse.c: resuse_start
 46 void
 47 resuse_start (resp) //resuseは、resource use startの略と思われる。
 48      RESUSE *resp;
 49 {
 50 #if HAVE_WAIT3
 51   gettimeofday (&resp->start, (struct timezone *) 0);
 52 #else
 53   long value;
 54   struct tms tms;
 55
 56   value = times (&tms); // man によると返り値は過去のある時点からのtick
 57   resp->start.tv_sec = value / HZ; // HZ は、CPUクロックか? 確証は得られてない
 58   resp->start.tv_usec = value % HZ * (1000000 / HZ);
 59 #endif
 60 }
現在のクロックカウント(と言っていいのか?)をHZで割って時刻をresp->start.tvに保持する

-resuse.c: resuse_end
117   resp->elapsed.tv_sec -= resp->start.tv_sec; // real time (sec)?
124   resp->elapsed.tv_usec -= resp->start.tv_usec; // real time (micro sec)?
コマンド実行後に省略したが同様にCPU時刻を取得して実行前の時刻を引いている。=> 正味実行にかかった時間(real time)を算出。


struct tmsとは何か?
struct tms -> linux/times.h
 6 struct tms {
  7         __kernel_clock_t tms_utime; // user time
  8         __kernel_clock_t tms_stime; // system time
  9         __kernel_clock_t tms_cutime; // child process user time
 10         __kernel_clock_t tms_cstime; // child process system time
 11 };

__kernel_clock_t -> linux/types.h
 79 typedef __kernel_clock_t        clock_t;


-time.c : summarize
320 static void
321 summarize (fp, fmt, command, resp)
322      FILE *fp;
323      const char *fmt;
324      const char **command;
325      RESUSE *resp;
326 {


-kernel/sys.c 912 void do_sys_times(struct tms *tms)
 921         tms->tms_utime = cputime_to_clock_t(tgutime);
 922         tms->tms_stime = cputime_to_clock_t(tgstime);
 923         tms->tms_cutime = cputime_to_clock_t(cutime);
 924         tms->tms_cstime = cputime_to_clock_t(cstime);


thread_group_timesとは
kernel/sched.c

3398 void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *st)
3399 {
3400         struct task_cputime cputime;
3401        
3402         thread_group_cputime(p, &cputime);
3403
3404         *ut = cputime.utime;
3405         *st = cputime.stime;
3406 }


kernel/posix_cpu_timers.c

234 void thread_group_cputime(struct task_struct *tsk, struct task_cputime *times)
 235 {
 236         struct sighand_struct *sighand;
 237         struct signal_struct *sig;
 238         struct task_struct *t;
 239
 240         *times = INIT_CPUTIME;
 241
 242         rcu_read_lock();
 243         sighand = rcu_dereference(tsk->sighand);
 244         if (!sighand)
 245                 goto out;
 246
 247         sig = tsk->signal;
 248
 249         t = tsk;
 250         do {
 251                 times->utime = cputime_add(times->utime, t->utime);
 252                 times->stime = cputime_add(times->stime, t->stime);
 253                 times->sum_exec_runtime += t->se.sum_exec_runtime;
 254
 255                 t = next_thread(t);
 256         } while (t != tsk);
 257
 258         times->utime = cputime_add(times->utime, sig->utime);
 259         times->stime = cputime_add(times->stime, sig->stime);
 260         times->sum_exec_runtime += sig->sum_sched_runtime;
 261 out:
 262         rcu_read_unlock();
 263 }


include/asm-generic/cputime.h
12 #define cputime_add(__a, __b)           ((__a) +  (__b))

next_thread(t);とは
include/linux/sched.h

2177 static inline struct task_struct *next_thread(const struct task_struct *p)
2178 {              
2179         return list_entry_rcu(p->thread_group.next,
2180                               struct task_struct, thread_group);
2181 }

thread_group.nextとは、
include/linux/sched.hのtask_structのメンバー
1285         struct list_head thread_group;

list_headとは、
include/linux/list.h

 41 struct list_head {
 42         struct list_head *next, *prev;          
 43 };


list_entry_rcuとは?
include/linux/rculist.h

210 #define list_entry_rcu(ptr, type, member) \
211         container_of(rcu_dereference_raw(ptr), type, member)




spin_lock_irq のirqとは?
include/linux/spinlock.h

307 static inline void spin_lock_irq(spinlock_t *lock)
308 {      
309         raw_spin_lock_irq(&lock->rlock);
310 }
include/linux/spinlock.h
220 #define raw_spin_lock_irq(lock)         _raw_spin_lock_irq(lock)
include/linux/spinlock-api_up.h
59 #define _raw_spin_lock_irq(lock)                __LOCK_IRQ(lock)


spin_local_irqに渡しているcurrent_sighand_siglockとは?


[conclusion]
utimeとstimeは、とりあえず全てのスレッド分足してそうだというとこまでは行ったがかなり消化不足気味

[気になるキーワード]
Hyper Threading
SMT (Simultaneous Multi Threading) 同時マルチスレッディング
SMP (Symmetric Multi Processing) 対象型マルチプロセシング

[Visual Studio C++] PEバイナリのエクスポートされたシンボル

PEバイナリのエクスポートされたシンボル名を確認する

漢は黙ってバイナリエディタといきたいとこだけど
今回は、MSさんのツール(dumpbin)を使います。

このdumpbinは、Visual Studioを使うと [Install Direcotry]\VC\bin にインストールされます。

ここは、PATHが通ってないし、dumpbinが使うライブラリがあるPATHがサーチパスに含まれてないため、dumpbin.exeと同一ディレクトリにあるバッチファイル vcvars32.bat を実行する必要があります。


そして、

dumpbin /EXPORT input.dll

とすることでシンボル名を確認することができる。

[c言語] Windows と Linux の共有ライブラリ

分けあってWindows向けの共有ライブラリ(dll) と Linux向けの共有ライブラリ(so) を
一つのC言語のソースで用意する必要が生じだ。

後にも先にもこれ一回限りな気がするけど一応メモ
検証環境は、

Windows 7 64bit版 C Compiler: gcc ライブラリを使う言語とコンパイラ Delphi XE2
Linux (RHEL) C Compiler: gcc ライブラリを使う言語とコンパイラ Fortran 90  pgfortran



まずは、ヘッダファイルとソース

add.h

#ifndef ADD_H
#define ADD_H

int add_(int *a, int *b)

int devide_(float *a, float *b, float *c)
#endif


add.c
#include<stdio.h>


int add_(int *a, int *b){
    int c;

  c = *a + *b;
  return c;
}

int devide_(float *a, float *b, float *c){

    *c = *a / *b;

    return 0;
}

ポイントは、引数がすべて参照渡しになっている点です。 Fortranが参照渡しがデフォルトなためです。 また、関数名がアンダースコアで終わっているのは、また後で。。。

お次は、コンパイル
まずは、Windowsで

gcc -shared -m32 -o add.dll add.c

-m32 は、32bi tPEバイナリを出力するためのオプションでdllを使う、アプリケーション(exe)が32bitであるため。

次に、Linuxで
gcc -fPIC -shared -o libadd.so add.c

-fPICは、位置独立コード(Position Independent Code)というメモリのどのアドレにもロード可能にするためのオプションです。


そして、使う側。
まずは、Delphi

unit use;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm6 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

  TAdd = function(a : PInteger; b : PInteger) : integer ; stdcall;
  TDevide = function(a : PSingle; b : PSingle; c : PSingle) : integer ; stdcall;

var
  Form6: TForm6;

implementation

{$R *.dfm}

procedure TForm6.Button1Click(Sender: TObject);
var
 ret : integer;
 a,b : integer;
 c,d,e   : single;
 Handle : THandle;
 Add    : TAdd;
 Devide : TDevide;
begin
 a := 4;
 b := 2;
 c := 4.0;
 d := 2.0;
 Handle := LoadLibrary('add.dll');
 if Handle <> 0 then
 begin
   @Add := GetProcAddress(Handle, 'add_');
   if @Add <> nil then
   begin
     ret := add(@a, @b);
     ShowMessage(IntToStr(ret));
   end;
   @Devide := GetProcAddress(Handle, 'devide_');
   if @Devide <> nil then
   begin
     ret := devide(@c, @d, @e);
     ShowMessage(FloatToStr(e));
   end;
   FreeLibrary(Handle);
 end;
end;

end.

関数をtypedefして、GetProcAddress にて関数のあるアドレスを取得する。

次は、Linux上のFortran
interface節を記述したインクルードファイルを作成

addf.h
      interface
        integer function add(a,b)
          integer a,b
        end function add

        integer function devide(a,b,c)
          real  a,b,c
        end function devide

      end interface

次にFortranのソース本体
       program test
       include 'addf.h'
       integer c,d
       real e,f,g
       c=4
       d=2
       e=4.0 
       f=2.0
       d = add(c,d)
       i = devide(e,f,g)
       write(*,*) d,g,i
       end program test

そしてコンパイル
pgfortran -I./include -L./lib -ladd src/use.f

-l で使用するライブラリを指定します。
また、Fortranの場合、関数名は、アンダースコアがついたシンボルを探すのでCの関数名には、アンダースコアをつける必要があります。


2013年5月2日木曜日

[CentOS] コマンドラインでWindowsなホストの共有ディレクトリをマウント

Windows独自プロトコルであるSMB (Server Message Block)を拡張仕様公開した、CIFS を実装してGPL v3 にて公開しているのがSamba ということらしいのですが

今回は、mountコマンドにてWindowsなホストで共有でしているディレクトリをCentOS release 6.4 にてマウントしてみます。

まず、必要パッケージのインストール

yum -y install samba-client
yum -y install cifs-utils


必要に応じてマウントポイントの作成

mkdir -p /mnt/winshare

そして、マウント

mount -t cifs //192.168.100.2/Users/hoge /mnt/winshare -o username=hoge

実行するとWindows上の共有しているディレクトリへのアクセス権のあるWindowsドメインのユーザーアカウントのパスワードを聞かれるので入力する。

192.168.200.2は、WindowsホストのIPアドレス

2013年4月29日月曜日

[CentOS] Building Bewulf type PC cluster

Bewulf型PCクラスタを構築してみる。
目標は、
 「MPIライブラリを使ったサンプルプログラムを複数ノードで実行する」

今回構築するクラスタの概要は、
*ヘッドノード、スレーブノード2ノードの計3ノード
*すべてのノードは、CentOS release 6.4 minimal
*ヘッドノードは、/home のみをNFSにて共有する(ディスクレスに挑戦したかったけどまた今度

ネットワークは、下図の様になる。
192.168.200.0/24がクラスタ専用のネットワークです。

各ノードのスペックは、

node name      CPU                       RAM         HDD
bwhead       amd64 (1 core)*1     2 Gbyte       50Gbyte x 2*2
bwslv01      amd64  (1 core)     1 Gbyte       50 GByte
bqslv02      amd64  (1 core)     1Gbyte        50 GByte

*1 型名になっていないのは、今回構築したノードすべてが仮想マシンだからです。
*2 /home 用に1台、/用に1台



-目次-

[0] HeadノードへのOSのインストール
一番上の項目を選択
イメージをマウントしてますが、メディアテスト

Testを選択

OK



Continueを選択

OK

Next

Engilish

キーボードレイアウトの選択英字配列キーボードを使ってます。

Basic strage device


Yesを選択

ホスト名 ここでは、間違っていたので後でbwheadに修正しました。

タイムゾーン Tokyo/Asia


root のパスワード

パーティション構成を決めます

今回は、このように切ることにしました

Formatを押下

Write changes to diskを押下

Nextを押下


インストール中です

インストール完了 再起動します

再起動後 ログイン状況


[1] Head ノードの設定

A) ネットワークインターフェースの設定
前述のネットワーク構成図に沿って設定します。
/etc/sysconfig/network-scripts/ifcfg-eth0
ONBOOT=yes
BOOTPROTO=dhcp

/etc/sysconfig/network-scripts/ifcfg-eth1
ONBOOT=yes
BOOTPROTO=static
IPPADDR=192.168.200.1
NETMASK=255.255.255.0


B) /etc/hosts の編集
以下を追加
192.168.200.1 bwhead
192.168.200.2 bwslv01
192.168.200.3 beslv02
上記の編集を反映させるためにネットワークサービスを再始動
/etc/init.d/networking restart

C) DHCPサーバーのインストール
slaveノードへのOSのインストールは、物理マシンでの構築の演習としてPXEによるネットワークブートとします。ネットワークブートでは、ブートローダーの場所等の情報を配布するのにDHCPを用います。そこでDHCPサーバーを構築します。

yum list dhcp
でパッケージを検索

yum install dhcp
そして、設定ファイルを作成
---- /etc/dhcp/dhcpd.conf ------

#
# DHCP Server Configuration file.
#   see /usr/share/doc/dhcp*/dhcpd.conf.sample
#   see 'man 5 dhcpd.conf'
#

DHCPDARGS=eth1;

# network boot setttings
allow booting;
allow bootp;
option option-128 code 128 = string;
option option-129 code 129 = text;
next-server 192.168.200.1;
filename "pxelinux.0";


subnet 192.168.200.0 netmask 255.255.255.0{

  # default gateway
  option routers                192.168.200.1;
  option subnet-mask            255.255.255.0;

  option domain-name-servers    192.168.100.1;

  range 192.168.200.100 192.168.200.254;
  default-lease-time 21600;
  max-lease-time 43200;

  host bwslv01{
    hardware ethernet 08:00:27:9C:25:55;
    option host-name "bwslv01";
    fixed-address 192.168.200.2;
  }
 
  host bwslv02{
    hardware ethernet 08:00:27:29:4E:37;
    option host-name "bwslv02";
    fixed-address 192.168.200.3;
  }

   
}

------------------------------------



設定ファイルの構文チェック
service dhcpd configtest
service dhcpd start
chkconfig dhcpd on

dhcpの使うポートを開けておく
iptables  -I INPUT -i eth1 -p udp --dport 67:68 --sport 67:68 -j ACCEPT
再起動時に設定が無効にならないように
/etc/init.d/iptables save
ファイヤーウォールの再起動
/etc/init.d/iptables restart


D) tftpサーバーのインストール
ネットワークブートにおいてブートローダ等を配布するのに必要

yum install tftp tftp-server
/etc/xinetd.d/tfptd
chkconfig xinetd on
service xnetd start

chkconfig tftp on

E) slave ネットワークブートのための準備
syslinuxをインストールします。
yum install syslinux

PXEブートにブートローダ関係の必要なファイルをtftpの公開ディレクトリにコピーします。
cp /usr/lib/syslinux/pxelinux.0 /var/lib/tftpboot
cp /usr/lib/syslinux/menu.c32 /var/lib/tftpboot
cp /usr/lib/syslinux/memdisk /var/lib/tftpboot
cp /usr/lib/syslinux/mboot.c32 /var/lib/tftpboot
cp /usr/lib/syslinux/chain.c32 /var/lib/tftpboot

OS関係の必要なファイルをtftpサーバーの公開ディレクトリに取ってきます。
yum install wget
mkdir -p /tftpboot/images/centos/x86_64/6.4
cd /var/lib/tftpboot/images/centos/
wget http://linux.mirrors.es.net/centos/6.4/os/x86_64/images/pxeboot/initrd.img
wget http://linux.mirrors.es.net/centos/6.4/os/x86_64/images/pxeboot/vmlinuz

ブートローダメニューの設定ファイルを作成
---/var/lib/tftpboot/pxelinux.cfg/default---

default menu.c32
prompt 0
timeout 300
INTIMEOUT local

MENU TITLE PXE Menu

LABEL local
MENU LABEL Boot from local hard disk drive
LOCALBOOT 0

LABEL CentOS 6.4 x86_64
MENU LABEL CentOS 6.4 x86_64
KERNEL images/centos/6.4/x86_64/vmlinuz
APPEND load initrd=images/centos/6.4/x86_64/initrd.img devfs=nomount


--------------------------------------



tftp(udp 69番ポート)を開ける
iptables -A INPUT -m state --state NEW -i eth0 -p udp --dport 69 -j ACCEPT
再起動時に設定が無効にならないように
/etc/init.d/iptables save
ファイヤーウォールの再起動
/etc/init.d/iptables restart

フォワーディングを有効にする
-- /etc/sysctl.conf--
# Controls IP packet forwarding
net.ipv4.ip_forward = 1   # 0 から 1に変更
----------------------


[2] slavve ノードのOSインストール
仮想マシンを起動したら即座にF12キーを押下する

PXEブートするために「l」キーを押下する

予め行った設定が適切に行われていれば
tftpサーバーからブートロードがDLされてメニューが表示される
CentOSを選択して、Enterを押下
インストール中に用いる言語の選択

キーボードレイアウトの選択

OSインストーラーのメディア種別を選択。セキュリティ的には、
あまり宜しくないけどHTTPで取ってきます。

ネットワーク設定
IPv4は、DHCPにします。

NIC設定中

インストーラーイメージ取得中

これ以降は、Headノードと同じGUIなインストーラーが起動しての同じインストールとなる。



[3] ssh でのhead から slave へのパスワード無しログイン
MPIライブラリのデータの移動、設定ファイルの配布のための仕組みを構築します。
よくr系コマンドが用いられますが、自分の環境では、rootでのパスワード無しログインが
できるようにすることを断念したため、sshを用います。

A) slave ノードへssh-server のインストール
yum install openssh-server
scpを使うため
yum install openssh-client


/etc/ssh/sshd_configの以下のコメントをはずす
#PermitRootLogin yes -> PermitRootLogin yes

chkconfig ssh on
service sshd start

試しにrootで全てのslaveノードにログインしてみる

ssh root@192.168.200.n # n は、整数
ログインしたまま後の作業の準備
cd $HOME
mkdir .ssh


B) head ノードでの作業

公開鍵生成

ssh-keygen -b 1024 -t rsa
鍵のパスフレーズは空にしておく

公開鍵を全てのslaveノードに配布しておく。
scp ~/.ssh/id_rsa.pub root@192.168.200.n:.ssh/authorized_keys

クラスタは、外からの開始される接続を許可しないネットワーク内で運用するのでとりあえずSElinuxは無効化しておく。
setenforce 0
そして、起動後も無効になるように/etc/selinux/configのSELINUXTYPEを下記のようにdisabledに変更しておく。
SELINUXTYPE=diabled


C)シェルスクリプトの作成

各ノードに同様の実行するためのシェルスクリプトを用意( rshでも実現可能だが自分の環境では、rootでの実行がPermission Denied ど言われで実現できなかった


----${HOME}/utils/rssh.sh-----

#!/bin/bash
BEGIN_ADDR=2
END_ADDR=3
ADDR_PREFIX="192.168.200."

for i in `seq $BEGIN_ADDR $END_ADDR`
do
  DST_ADDR="$ADDR_PREFIX$i"
  echo "Processing for $DST_ADDR"

ssh $DST_ADDR<<EOF
$*
EOF

done

---------------------------
chmod 744 ${HOME}/utils/rssh.sh

各ノードにファイルコピーするためのコマンド
---${HOME}/utils/rsscp.sh---

#!/bin/bash
SRC_FILE=$1
DST_PATH=$2

BEGIN_ADDR=2
END_ADDR=3

ADDR_PREFIX="192.168.200."

for i in `seq $BEGIN_ADDR $END_ADDR`
do
  DST_ADDR="$ADDR_PREFIX$i"
  echo "Copying $SRC_FILE -> $DST_ADDR:$DST_PATH"

scp $SRC_FILE $DST_ADDR:$DST_PATH

done

--------------------------

D) /etc/hosts の配布

/etc/hosts を作成して
 ${HOME}/utils/rsscp.sh /etc/hosts /etc/hosts


[4] NIS を用いたアカウント一元管理

A) サーバーの構築

アカウントを一括管理するためにNISサーバーを構築する

まずは、サーバーのインストール
yum install ypserv

ドメインの設定 このドメインは、DNSとは関係がない
ypdomainname clnet

/etc/sysconfig/network に 先ほど設定したNISドメインを追加
NISDOMAIN = clnet

/var/yp/Makefile の編集(下記がオリジナルのファイルとの差分)
-----差分-----------------------

*** Makefile.org 2013-04-27 17:41:09.642037547 +0900
--- Makefile 2013-04-27 17:42:41.594036564 +0900
***************
*** 39,49 ****
 
  # Should we merge the passwd file with the shadow file ?
  # MERGE_PASSWD=true|false
! MERGE_PASSWD=true
 
  # Should we merge the group file with the gshadow file ?
  # MERGE_GROUP=true|false
! MERGE_GROUP=true
 
  # These are commands which this Makefile needs to properly rebuild the
  # NIS databases. Don't change these unless you have a good reason.
--- 39,49 ----
 
  # Should we merge the passwd file with the shadow file ?
  # MERGE_PASSWD=true|false
! MERGE_PASSWD=false
 
  # Should we merge the group file with the gshadow file ?
  # MERGE_GROUP=true|false
! MERGE_GROUP=false
 
  # These are commands which this Makefile needs to properly rebuild the
  # NIS databases. Don't change these unless you have a good reason.
***************
*** 114,120 ****
  # If you don't want some of these maps built, feel free to comment
  # them out from this list.
 
! all:  passwd group hosts rpc services netid protocols mail \
  # netgrp shadow publickey networks ethers bootparams printcap \
  # amd.home auto.master auto.home auto.local passwd.adjunct \
  # timezone locale netmasks
--- 114,120 ----
  # If you don't want some of these maps built, feel free to comment
  # them out from this list.
 
! all:  passwd shadow group hosts rpc services netid protocols mail \
  # netgrp shadow publickey networks ethers bootparams printcap \
  # amd.home auto.master auto.home auto.local passwd.adjunct \
  # timezone locale netmasks

--------------------------------


このままだとすべてのホストからNIS情報を引き出すことができるようになっているので
NIS情報を引き出せるホストを限定するために /var/yp/securenets を作成して
以下を書き込みます。
255.255.255.0 192.168.200.0


これで指定したネットワークに属するホストだけがNIS情報を引き出せるようになりました。
ここでサーバーデーモンの起動
/etc/rc.d/init.d/ypserv start
/etc/rc.d/init.d/yppasswdd start

そして、起動時に自動でデーモンが走るように以下を実行
chkconfig ypserv on
chkconfig yppasswdd on

/usr/lib64/yp/ypinit -m を実行
NISサーバーの情報を確認される。今回は、サーバーは1台体制(冗長化無し)なのでNISDOMAINで設定した内容が表示されていればおk

B) ファイヤーウォールの設定
portmapper が使う tcp と udp 111番ポートへの通信を受け入れるようにしておく。


C ) クライアントの準備 (サーバーマシンでも実行する)
./rssh.sh  ' echo "NISDOMAIN = clnet" >> /etc/sysconfig/network '
./rssh.sh "sed -ei 's/\(USENIS=\)no/\1yes/' /etc/sysconfig/authconfig "
./rssh.sh 'echo "domain clnet server bwhead" > /etc/yp.conf'

slaveノード用のNS設定ファイルを作成して配布する。
mkdir tmp
cd tmp
cp /etc/nsswitch.conf tmp.conf
スレーブ用設定ファルの変更。以下がオリジナルのファイルとの差分
------差分----------

*** /etc/nsswitch.conf 2013-04-29 15:43:35.280253996 +0900
--- tmp.conf 2013-05-06 22:59:03.979813909 +0900
***************
*** 30,38 ****
  #shadow:    db files nisplus nis
  #group:     db files nisplus nis
 
! passwd:     files nis
! shadow:     files nis
! group:      files nis
 
  #hosts:     db files nisplus nis dns
  hosts:      files dns nis
--- 30,38 ----
  #shadow:    db files nisplus nis
  #group:     db files nisplus nis
 
! passwd:     nis files
! shadow:     nis files
! group:      nis files
 
  #hosts:     db files nisplus nis dns
  hosts:      files dns nis

--------------------
cd
./rscp.sh ./tmp/tmp.conf /etc/nsswitch.conf

ypbind をインストールする
./rssh.sh 'yum -y install rpcbind'
./rssh.sh '/etc/rc.d/init.d/rpcbind start'
./rssh.sh 'chkconfig rpcbind on'

./rssh.sh 'yum -y install ypbind'
./rssh.sh '/etc/rc.d/init.d/ypbind start'
./rssh.sh 'chkconfig ypbind on'


D) ユーザーの追加 (適宜)
NISサーバーにて
useradd newuser_name
passwd newuser_name

以上で通常通りユーザーを追加した後

cd /var/yp
make

でNIS DBに追加したユーザーの情報を追加する。
これでもログイン出来ない場合は、まずクライアントマシンで
ypcat passwd して追加したユーザーの情報が反映されれているかチェック。

追加されているにもかかわらずログイン出来ない場合は、
/etc/ypserv.conf中の
files: 30

files: 0
に変更してキャッシュを無効にする。


[5] NFS の構築

すべてのノードでホームディレクトリを共有できるようにする。

A) サーバーの構築

yum -y install nfs-utils

共有するディレクトリに関する設定を行う /etc/exports に以下を追加

/home 192.168.200.0/24(rw,sync,no_root_squash,no_all_squash)

/home … 共有するディレクトリの指定
192.168.200.00/24 … 共有を許すネットワーク
sync … 遅延書き込みをしない
no_root_squash … root の特権を行こうにする
no_all_squash … そのままの権限でアクセスさせる

/etc/idampd.conf にドメインの設定をする。デフォルトでは、「Domain = 」を含む行がコメントアウトされているので有効にしてドメインを記述する。

Domain = clnet


起動していないデーモンを起動しておく
/etc/rc.d/init.d/rpcbind start
/etc/rc.d/init.d/nfslock start
/etc/rc.d/init.d/nfs start

起動時にデーモンが自動で起動するようにしておく

chkconfig rpcbind on
chkconfig nfslock on
chkconfig nfs on


B) クライアントの準備

サーバーマシンからシェルスクリプトを用いて実行する

./rssh.sh 'yum -y install nfs-utils'

先ほど編集したNFSサーバーの /etc/idamp


./rssh.sh '/etc/rc.d/init.d/rpcbind start'
./rssh.sh '/etc/rc,d/init.d/nfslock start'
./rssh.sh '/etc/rc.d/init.d/netfs start'

./rssh..sh 'chkconfig rpcbind on'
./rssh.sh 'chkconfig nfslock on'
../rssh.sh 'chkconfig netfs on'


ここからは、各ノードに直接ログインして操作する
まずは、サーバーのパーティションをマウントできるかをテスト


mount -t nfs bwhead:/home /home

df -h

でマウントされたかどうかを確認する。

次に起動時に自動でマウントされるように/etc/fstab を変更
以下の行を追記
bwhead:/home /home nfs bg,intr 0 0

bg… NFSでのマウントが失敗した時にバックグランドで試行を繰り返す。
intr … 停止しているプロセスをkillするために、割り込みを可能にする。
0 … dump頻度
0 … fchkパスのフィールド

さらにインストール時に切った/home のパーティションをマウントしないようにコメントアウトしておく。
これ以上ができたNFSクライアントマシンを再起動して無事にマウントされるかを確認しておく。


[6] OpenMPI のインストール(headノード含めすべてのノードで)
その前にgcc とg++ ,makeのインストール

yum -y install gcc
yum -y install gcc-c++
yum -y install make

今回は、OpenMPI Ver.1.6.4 を用いる。
wget http://www.open-mpi.org/software/ompi/v1.6/downloads/openmpi-1.6.4.tar.gz
cd openmpi-1.6.4
./configure --prefix=/usr/local
make all # 複数コアある場合は make -j num_proc all で並列コンパイルできるらしい

[7] サンプルプログラムの実行

実行用専用ユーザーをNISサーバーにて作る
useradd cltest
passwd cltest
NIS DBへの反映
cd /var/yp ; make

ヘッドノードにてログアウトしてcltestでログインする
以下のソースを作成
-----main.c------------

#include <stdio.h>
#include <mpi.h>

int main(int argc, char **argv){
int rank, size, namelen;
char name[256];

MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Get_processor_name(name, &namelen);
sleep(5);
printf("This is %d of %d on %s\n", rank, size, name);
MPI_Finalize();
return 0;
}

----------------------

mpicc main.c
でコンパイル。


実行前にライブラリサーチPATHをbashrcに追加
export LD_LIBRARY_PATH=/usr/local
source .bashrc


そして、root権限を得て/usr/local/etc/openmpi-default-hostfile (headノード)
にどのユーザーのジョブでも常に実行させたシステム共通の計算ノードを追記する。
以下例
bwhead
bwslv01
bwslv02

本来なら、ヘッドノードは、ジョブ実行のみで計算は行わないがホストPCのリソースがそんなに潤沢ではないためヘッドノードも追加した。


mpirun -np 3 a,out

これで下記の様に各ノードでの出力が表示されればクラスタ構築一応完了。
---実行結果-----

This is 0 of 3 on bwhead.clnet
This is 1 of 3 on bwslv01
This is 2 of 3 on bwslv02

----------------



[7]参考
http://kuni255.blogspot.jp/2013/04/iptables.html





2013年4月24日水曜日

[grub] コマンドラインからのLinuxのブート

Ver.0.9.7


上記のようなメニューページにて「c」キーを押下するとgrubのコマンドラインへ移行する。


helpコマンドを実行すると要約されたコマンドリストが表示される。

root コマンドで起動パーティションを指定する。なお、「root (hd0,」でtabキーを押下すると、パーティションのリストが表示される。



なお、(hd0,0) は、/dev/hda1 or /dev/sda1 という具合である。
次にkernelコマンドでカーネールをロードする。
以降は、調査中。



[CentOS] SELinux 無効化後のカーネルパニック

SELinuxを無効化後に再起動したら 




上記のように「  Kernel panic – not syncing: Attempted to kill init!」カーネルパニックをおこした。

グーグル先生に聞くと同じようなミスを犯す人が多いみたいですぐに解決策が分かった。

とりあえずPCを再起動させて「Booting CentOS .以下略」と表示中に間髪入れずに「Enter」keyを押下する。


するとGrub のメニューが表示されるので


「e」キーを押下して、起動リストを表示させる。


2番目のCentOS のカーネルをハイライトして再び「e」キーを押下する。そして、起動オプション「enforcing=0」を追記する。



追記したら「Enter」キーを押下して保存して元のページに戻り、「b」キーを押下して起動オプションを加えたコマンドで起動する。


起動後は、毎回この作業をせずに済むように /etc/grub.conf に先ほどと同様に「encorcing=0」オプションを追記しておく。