2010年2月28日日曜日

DebianでNFSサーバ&クライアント

ググれば大量に出てくるものを書いてもなんかなぁ...と思いつつも、
そんなことを考えていると全然Blogが書けないということに気がついたので、もう遠慮なく書くことにする。

今回は、かがみねサーバ(kagamine.h.hachune.net)の/home/mikuをめぐりねサーバ(megurine.h.hachune.net)の/home/mikuにマウントする。

まず、かがみねサーバ(NFS Server)の設定。
% sudo aptitude install nfs-kernel-server
% sudo vi /etc/exports
で、以下を追加する。
/home/miku *.h.hachune.net(ro,sync,no_subtree_check)


・ディレクトリをエクスポート(再エクスポート)する。
% sudo exportfs -ar
(nfs-kernel-serverを再起動する方法もある)

・公開できているか確認する。
% showmount -e


次に、めぐりねサーバ(NFS Client)の設定を行う。
/etc/fstabに以下を追加し、sudo mount -aする。
kagamine.h.hachune.net:/home/miku /home/miku nfs ro,sync 0 0

これでマウントできた。
サーバ側でshowmount -aコマンドを打つと、マウント状況が確認できる。
簡単だけれど、セキュアではないな…


/etc/exportsの書式は、man exports、
/etc/fstabのNFS関連の情報は、man nfs、
NFSエクスポートリスト操作コマンドexportfsの情報は、man exportfs
マウント情報確認コマンドshowmountの情報は、man showmount
を見ると良い。

Ruby1.9.1のcursesでUTF-8文字列を表示

RubyのCursesでプレイリスト操作ツールを作成しようとしたところ、文字化けして全然使い物にならないということが判明。ついでなので1.9.1にパッチを当ててビルドしてみることにする。

・ext/curses/curses.cを編集

追加:
+ #include "locale.h"

Init_curses関数内にsetlocaleを追加:
Init_curses()
{
+ setlocale(LC_ALL, "");


・ext/curses/extconf.rbを編集(ncurseswを探すようにする)

削除:
-if have_header(*curses=%w"ncurses.h") and have_library("ncurses", "initscr")
追加:
+if have_header(*curses=%w"ncurses.h") and
+ ( have_library("ncursesw", "initscr") or have_library("ncurses", "initscr") )
+ make=true
削除:
-elsif have_header(*curses=%w"ncurses/curses.h") and have_library("ncurses", "initscr")
追加:
+elsif have_header(*curses=%w"ncurses/curses.h") and
+ ( have_library("ncursesw", "initscr") or have_library("ncurses", "initscr") )
+ make=true


ruby-1.9.1-p378.tar.bz2をダウンロード
・ libncursesw-devをaptからインストール
% sudo aptitude install libncursesw-dev

・ビルド。-O2だと何故か途中でコケるらしいので、-O3にする。
% optflags="-O3 -pipe" ./configure --prefix=/usr/ruby19 --program-suffix=19

2010年2月19日金曜日

現状

なんか色々忘れそうなので書いておく。

ゼミ用論文…texA450枚越え。卒論として提出する時には一体どうなっていることやら…
応用情報技術者…毎日ちょっとずつ勉強。
Ruby…最近あんまり大きいのは作っていない。mtmef v2.0をさっさとどうにかしたい。Winでしか動かないのは不便過ぎる。
C…細かいのをいろいろやってる。
Python…あんまり触れてない。ついRubyに行ってしまう…

# はちゅね転送サービスの影響でAjaxが気になりだした。
# ちょっとやってみたら意外といけそうな気がした(ブラウザを気にしなければw)。
# 作業の効率化の為にも、zshをどうにかしたい。


鯖…最近環境を一期に更新中。去年作ったkagamine-server(Debian 5)大活躍。
逆にhatsune-server(WS2008R2)がちょっと弄れていない状態。
hatsuneは音楽関連専用機になりつつあるな…

megurine-serverは今年に入ってからほぼ常に稼働中。
春休み中にmegurine一度全部見直したいが、どうだろう。

hachune.net用Webサーバのバックアップもほぼ準備完了。
後は改良し続けるだけ…な気がする。
セキュリティの向上も必須。Gumblarとかにはまず引っかからないだろうけど。
公開サーバでパスワード認証とか怖すぎてもうできないw

# ルータがちょっと危険…かも?(VPN的な意味で)
# そろそろルータぐらい自作すべき(OpenBSDあたりでw)


まだ卒業まで1年ある。その間はひたすらこんな感じで勉強。
それでも、終わるのが早すぎて泣ける。

2010年2月14日日曜日

はちゅね転送サービス 開始!

以前勢いで取得したhachune.netドメインを使用し、URL転送サービスを作ってみた。

例えば、
otomania.hachune.netにアクセスが来たら、Otomaniaさんのページhttp://www.otomania.netに転送する
pocopoco.hachune.netにアクセスが来たら、たまごさんのページhttp://www.pocopoco.ccに転送する
twitter.hachune.netにアクセスが来たら、私のTwitterページhttps://twitter.com/Phenomerに転送する
といったことができます。

「サーバを間借りして作ったサイトに、分かりやすい名前が欲しい!」
「自分のボカロなサイト・ブログに分かりやすい別名を付けたい!」
などといった時に使えるかと思います。


詳細は以下からどうぞ。
http://hachune.net/hachune-forward.html


.comがドメイン広告になってるな…なんか寂しい。

2010年2月9日火曜日

CでOpenMPを使ってみる

せっかくマルチコアCPUがあることだし、全コアを全力で使えるプログラムを作ってみたいと考えていたが、いろいろ面倒で諦めがちだった。しかし、C/C++にはOpenMPという便利なものがあると聞いて、調べみたところ、本当に便利だったのでここに纏めてみる。


OpenMPを利用するには、GCC 4.2以降が必要で、コンパイル時に-fopenmpオプションを付ける必要がある。
% gcc openmp_test.c -o openmp_test -fopenmp

また、今回OpenMP関連で使用した関数とその役割は以下のとおり。
omp_get_thread_num() … 現在実行されているスレッドの番号を返す
omp_set_num_threads(10) … スレッド数を10に指定(通常はCPUコア数から自動的に割り振られる)


まずは一番簡単なスレッド作成方法。
スレッド処理したい関数の前に#pragma omp parallelを書くだけ。

#include<stdio.h>

int main(void){
int i;

#pragma omp parallel
for(i=0; i<20; i++){
printf("Thread %d : %d\n", omp_get_thread_num(), i);
}
return 0;
}


これをコンパイルし実行すると、

miku@kagamine:~/c-lang$ ./openmp_1
Thread 0 : 0
Thread 0 : 1
Thread 0 : 2
Thread 0 : 3
Thread 0 : 4
Thread 1 : 0
Thread 1 : 1
Thread 1 : 2
Thread 1 : 3
Thread 1 : 4

となったり、

miku@kagamine:~/c-lang$ ./openmp_1
Thread 1 : 0
Thread 1 : 1
Thread 1 : 2
Thread 1 : 3
Thread 1 : 4
Thread 0 : 0

となったりする。なにやら同時に処理されているように見え、スレッドの実験としては成功していることが分かる。
しかし、結果が安定していないため、このままではあまり使い物にならない。
開始したスレッド全てから変数iが参照され、変更されるためこうなってしまう。



そこで、変数iをスレッド内でプライベートに使うようにしてみる。

#include<stdio.h>

int main(void){
int i;

// 変数iをスレッド内プライベートとして渡し、スレッドを開始させる
#pragma omp parallel private(i)
for(i=0; i<3; i++){
printf("Thread %d : %d\n", omp_get_thread_num(), i);
}

return 0;
}

これを実行すると…

miku@kagamine:~/c-lang$ ./openmp_2
Thread 0 : 0
Thread 1 : 0
Thread 1 : 1
Thread 1 : 2
Thread 0 : 1
Thread 0 : 2

iの値はそのスレッド内のみの値として扱われ、
スレッド毎にi++されていることが分かる。



通常、全スレッドが全く同じ処理を繰り返しても意味が無い。
そこで、グローバルな変数iを操作するときのみ、排他処理を行わせる。

#include<stdio.h>

// 変数iをグローバルとして渡すが、printfとi++の部分を排他動作させる
int main(void){
int i;

i = 0;
#pragma omp parallel
while (i<10){
// 排他処理部分をブロックで指定
#pragma omp critical
{
printf("Thread %d : %d\n", omp_get_thread_num(), i);
i++;
}

sleep(1);
}
return;
}

これを実行すると…

miku@kagamine:~/c-lang$ ./openmp_3
Thread 1 : 0
Thread 0 : 1
Thread 1 : 2
Thread 0 : 3
Thread 1 : 4
Thread 0 : 5
Thread 1 : 6
Thread 0 : 7
Thread 1 : 8
Thread 0 : 9

iの値が、両スレッドで1づつ増えていっているのが分かる。

ただ、このテストプログラムには問題がある。
while (i<0)の判定後、whileループの中で別スレッドがiに値を追加し、
printf()するときにiの値が10または10以上になってしまうことがある(sleep(1)を外すと頻繁に発生する)。
この辺りを、正しく処理させるようにしないと、「数回に1回だけ何故かコケる」なんて厄介なバグになってしまうので、注意したい。



何でもかんでも排他処理させてしまうと、他の関数で実行中のスレッドにまで影響が及び、何かしらの問題(デッドロック等)が発生する可能性がある。
そこで、できる限り排他処理を使わないようにしてみる。
(ついでに、しっかり4コア使ってくれるのか確かめるため、dummy関数を用意した)

#include<stdio.h>
#include<unistd.h> // usleep()
#include<stdlib.h>


// ダミー処理関数(CPUに負荷を掛ける)
void dummy(int number){
int n, i, tmp;
int array[number];
for(i=0; i<number; i++){
array[i] = i;
}

for (n=0; n<number; n++){
for (i=0; i<number - 1; i++){
if (array[i] < array[i+1])
{
tmp = array[i];
array[i] = array[i+1];
array[i+1] = tmp;
}
}
}
return;
}


// 変数iをグローバルとして渡すが、printfとi++、dummy(10000)の部分をシングルスレッド動作させる
int main(void){
int i, while_count;

i = 0;
while_count = 0;

#pragma omp parallel
while (<<100){

// ブロック内をシングルスレッド動作させる
#pragma omp single
{
printf("Thread %d : %d\n", omp_get_thread_num(), i);
i++;
dummy(10000);
}
printf("Thread %d : loop...\n", omp_get_thread_num());
usleep(10);
while_count++;
}

printf("loop Count: %d\n", while_count);
return;
}



また、「ブロック内を他のスレッドが実行中なら、ブロック内の実行をスキップする」ということも可能。

#include<stdio.h>
#include<unistd.h> // usleep()
#include<stdlib.h>


// ダミー処理関数(CPUに負荷を掛ける)
void dummy(int number){
int n, i, tmp;
int array[number];
for(i=0; i<number; i++){
array[i] = i;
}

for (n=0; n<number; n++){
for (i=0; i<number - 1; i++){
if (array[i] < array[i+1])
{
tmp = array[i];
array[i] = array[i+1];
array[i+1] = tmp;
}
}
}
return;
}


// 変数iをグローバルとして渡すが、printfとi++、dummy(10000)の部分をシングルスレッド動作させる。
// もしその部分が別スレッドで処理中ならスキップする
int main(void){
int i, while_count;

i = 0;
while_count = 0;

#pragma omp parallel
while (i<100){

// single nowait : 他のスレッドがブロック内を実行中だったらスキップ
#pragma omp single nowait
{
printf("Thread %d : %d\n", omp_get_thread_num(), i);
i++;
dummy(10000);
}
printf("Thread %d : loop...\n", omp_get_thread_num());
usleep(10);
while_count++;
}
printf("loop Count: %d\n", while_count);
return;
}


#pragma omp singleと、#pragma omp single nowaitの場合を、
実際にコンパイルして実行、比較してみると、多分違いが分かる…と思う。
また、omp_set_num_threads(スレッド数)で、スレッド数を変更しながらいろいろ試してみるのも良い。


結構長い間やっていた筈なのに、C言語のBlog投稿は今回が初めて。
やっているけど書いていないことって、かなり多いな…。