忍者ブログ
物理学者(ポスドク)による日々の研究生活のメモ書きです ( python/emacs/html/Japascript/シェルスクリプト/TeX/Mac/C言語/Linux/git/tmux/R/ポケモンGO)
C言語を勉強して使い始めて10年くらい経つけど、この度初めてbool型というのがあることを知りました
boolの存在自体はpythonとか他の言語で知ってたけど、Cにもあるとは・・・・




■ 参考 : stdbool.h

/usr/include/stdbool.hというヘッダーファイルにbool型の値の定義が書いてあるらしい
基本的に
false が 0
true が 1
らしい

手元の環境でファイルを見てみたかったけど、同じ場所にないんだが・・・

bool型を使ったコードをコンパイルするときは --std=gnu99 をつける(--std=c99との違いはわからぬ)




面白い記事を見つけたので貼っとく

■ 参考 :C99 の bool と int の振る舞い





bool型の変数をprintfするときは整数型と同じ%dでいいらしい
無理やり0のときはfalse, 1のときはtrueで出力する方法もあるっちゃーある(以下のリンクを参照)

■ 参考 : c言語のbool型変数の出力変換指定子




PR
コマンドの例
hogeが実行コマンド
valgrind -v -v --error-limit=no --leak-check=full --tool=memcheck --show-reachable=no hoge

出力を記録しておきたいなら@tcsh
valgrind -v -v --error-limit=no --leak-check=full --tool=memcheck --show-reachable=no hoge >& val_err.txt
-vと2回書いてるのはより情報を出力するため

--error-limit はデフォルトだとyes
エラー報告の数を1000くらいで打ち切るオプションなので、これを外してすべてのエラーを出力する

--leak-check=full は必要

--tool=memcheck はvalgrindで使えるツールのうちどれを使うか指定する
このオプションがない場合もデフォルトでmemcheckが選ばれるのでなくてもいい

--show-reachable=no
確保された領域が解放されないままプログラムがabortした場合に検出される? わからん




コンパイル時に CFLAGS="-g -O0" のようにしてコンパイルオプションを追加しておく
-gはデバッグ関連(行番号とか)の情報を実行ファイルに入れておくオプション
-O0は本来-O2とかするところを、最適化しないようにしてコンパイルする
最適化してしまうと、順番とかが実行される変わる可能性があるかららしい

これをしておくと、valgrindのエラー出力の表示に関数名やコードの何行目かが表示されるので、バグ取りがとてもしやすくなる
逆にないと、とてもつらい・・・





ワーニング、エラーメモ

■ Warning: set address range perms: large range
大きいサイズのメモリ確保をしたとき


■ memcheck GC: 1000 nodes, 55 survivors (5.5%)
これは自分のコードには関係なくて、memcheckの性能を示すものらしい
バグ取りには関係ないので無視


■ メモリリークの例
==224793== 704,643,072 bytes in 1 blocks are possibly lost in loss record 1,312 of 1,312
==224793== at 0x4C2BC3C: memalign (vg_replace_malloc.c:857)
==224793== by 0x4C2BD01: posix_memalign (vg_replace_malloc.c:1020)
==224793== by 0x4E47325: HOGE (my_malloc.c:38)
==224793== by 0x4E475A0: HOGE (my_malloc.c:123)
==224793== by 0x4031E2: main (coinc.c:347)
-g -O0を付け加えてコンパイルしてるとこんな感じで情報が出てくる
実際はHOGEとかmy_malloc.cとかは別の名前なので適当に差し替えておきました

valgrindで実行ファイルを動かした場合は、メモリ確保の関数とかが通常のライブラリのではなく
valgrindのライブラリのものが用いられるっぽい
例えばposix_memalignとか


■ メモリの不正アクセスの例
==224793== Invalid read of size 8
==224793== at 0x4121D2: zpk2sos (iir.c:845)
==224793== by 0x4126BE: iir_design_sos (iir.c:1029)
==224793== by 0x404A12: main (coinc.c:509)
==224793== Address 0x187b0e28 is 8 bytes after a block of size 304 alloc'd
==224793== at 0x4C2B955: calloc (vg_replace_malloc.c:711)
==224793== by 0x4117DC: zpk2sos (iir.c:746)
==224793== by 0x4126BE: iir_design_sos (iir.c:1029)


参考になりそうなページ

■ 参考 : Using and understanding the Valgrind core(valgrindの公式ドキュメント)

■ 参考 : Valgrindの結果の見方、日本語訳、など役に立つことまとめ

■ 参考 : Valgrindの使い方







ちょっと関係ないけど、もし動的メモリを2回freeしてしまうとエラーになる

このエラーの箇所を探すコツを↓の記事で見かけたのでメモ

■ 参考 : double freeバグのデバッグ.



実行ファイルに対して、以下のコマンドを実行するとコマンドのバイナリファイルがどういう順で何を実行するのか見える
逆アセンブルとかいうらしい(なにかに使えるかもしれないのでメモ)
objdump -D a.out | more











(Cの話なのでCカテゴリで)




■ 状況
1. ~/local/lib/以下にhogeというライブラリがインストールされている
2. ~/local_foo/lib以下にhogeというライブラリがインストールされている
3. PKG_CONFIG_PATHが~/local/libに通っているのが問題かと思って
PKG_CONFiG_PATHを空にして(unsetenv PKG_CONFiG_PATHしても)
コンパイルオプションに
LDFLAGS = -L/home/myname/local_foo/lib -lhoge
を追記してもダメ
どうやってるのかわからんが勝手に~/local_foo/libにあるhogeライブラリを見つけて来てしまう
ちなみに、実際にリンクされてるライブラリは
ldd [実行ファイル]
で調べられる

Macなら
otool -L [実行ファイル]

今回解決方法がわかったのでメモ

コンパイル時に
LDFLAGS="-L/home/myname/local_foo/lib -Wl,-rpath /home/myname/local_foo/lib"
を追加すればOK
ダブルコーテーションはなくても動いた

コンパイル後にlddでちゃんと正しい方にリンクされていれば成功



■ 参考 : Linux: ライブラリの動的リンクでエラーが出た場合の対処方法








exp(x)-1 が入った計算をしてて、計算の精度が気になった
gslのドキュメントを見てたら、expm1という関数があるっぽい

よくよく調べてみたら、別にgsl内に限らずmath.hにある一般的な関数だった
expm1 = exp(x)-1

expm1fは返り値がfloat
expm1lは返り値がlong double

■ 参考 : C言語関数辞典 - expm1, expm1f, expm1l


忘れそうなのでメモ








C言語で書かれたライブラリをC++のコードで読んで使っていたが次のようなエラーが出た
hoge.h:85:18: error: use of parameter outside function body before ']' token
・・・

原因はわかりやすく↓に書かれていた
■ 参考 : 「2次元配列の値を関数の引数として渡したい」
C++言語ではNGです。nはコンパイル時定数でければなりません。
C言語(C99以降)ではOKです。第1引数に与えたnの値は、第2引数の2次元配列型に適用されます。(厳密には"VLA型へのポインタ型"になります)
C++にはないCの機能として VLA(Variable Length Array; 可変長配列) があります。C/C++の差異はこの言語機能の有無から生じています。


ほほぉ〜







いろんな人と話してていくつか解決方法の案が出てきた

(1) インライン関数にしてしまう

インライン関数はコンパイル時に展開されるので、関数コールをするわけではない
なので、関数の引数の型とかも気にする必要がない

■ 参考 : [C][GCC]C言語のインライン関数につい


(2) C++言語の定義済みマクロ __cplusplus を使ってコードを分岐させる

■ 参考 : 定義済みマクロ__cplusplusとgccの長い歴史

■ 参考 : よくみる extern "C" {} と __cplusplus

これが一番わかり易いかなぁ〜と感じた
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

/* Cのコードがたくさん */

#ifdef __cplusplus
}
#endif /* __cplusplus */
のようにするといいっぽい


extern "C" { /* Cのコード */ }で囲まれているところはC言語っぽく扱ってねとのこと







■ 参考 : C言語 プログラム実行時からの時間を取得 - time.h - [ clock ]

■ 参考 : 手を動かしてさくさく理解する C言語/C++ 処理時間計測 入門



#include <time.h>

clock_t time1 = clock();

// ここでなんか計算する

clock_t time2 = clock();
fprintf(stderr, "%f [s]\n", (time2-time1)/(double)CLOCKS_PER_SEC);

time1とtime2に代入されるのはミリ秒とかマイクロ秒が単位の数字
CLOCKS_PER_SECで割ってあげることで、それを秒単位に換算することができる







clang: error: argument unused during compilation: '-L/usr/local/lib' [-Werror,-Wunused-command-line-argument]
■ 参考 :xcode/clang: clang: warning: argument unused during compilation: '-fcheck-new'

-Werrorの横に -Qunused-arguments を追加すればOK


clang: error: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated [-Werror,-Wdeprecated]
appleのg++使うの辞めたら消えた
こっから、portでインストールしたgccを使ってる

g++ (MacPorts gcc5 5.5.0_0) 5.5.0
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


g++: error: unrecognized command line option '-stdlib=libc++'
未解決・・・・・
ググったけど全然わからぬ





(2021/02/08 追記)

原因はmac portsで入れたg++を使っていたからっぽい
バイナリでインストールしたROOTはもともとMacに入っているc++を使うように設定されてる

適切に分岐して動くようにするにはmakefileに
ROOTCFLAGS = $(shell root-config --cflags)
ROOTLIBS = $(shell root-config --libs)
CXXFLAGS = $(ROOTCFLAGS)
CXXLIBS = $(ROOTLIBS)
CXX=$(shell root-config --cxx)

hogehoge:$(OBJ)
$(CXX) $(OBJ) -o $@ $(CXXLIBS) -lm

と書いておけばいいっぽい
最後のCXXのところが大事
TARGET名やOBJは適時置き換えてください









以下のページにまとめられてた
■ 参考 : 暗黙ルールに用いられる変数

1998年の記事だけど大きくは変わってないやろ・・・


使うかもしれない変数だけメモ
CC
CXX
CPP
CFLAGS
CXXFLAGS
CPPFLAGS
LDFLAGS

CXXとCPPの関係
CXXFLAGSとCPPFLAGSの関係がよくわからん





ブログを書き始めて苦節8年
ついにタイトル回収しましたw





■ やること

1.コンパイル時にgオプションを付ける
 g++ -g
2. ulimitの設定を変更してcore dumpを出力するようにする
% ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 386124
max locked memory (kbytes, -l) unlimited
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 4096
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
設定を変えるには、
% ulimit -c unlimited
% ulimit -a
core file size (blocks, -c) unlimited
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 386124
max locked memory (kbytes, -l) unlimited
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 4096
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
2'. ただ、自分の環境では↑の設定はしなくてもうまくいった。condor経由で実行したので、そっちの設定が上書きされたとか?
3. プログラム実行時にsegmentation faultなどのエラーで終了すると core.5045.5 のようなファイルが作成される
4. このファイルを解析する

(追記)
coreファイルがクッソファイル容量が大きいので注意
自分の環境だと64GBもあって思わず吹いてしまった
どーしてもこのバグを取らないと死ぬって状況以外では使わないほうがいいかもしれん





コアファイルについての情報を表示するときは
% file core.5045.5
これでどの環境でどのプログラムのcoreファイルかわかる


gdbコマンドでこのcoreファイルを解析するときのフォーマットはこんな感じ
gdb [実行プログラムの名前] ./[コアファイルの名前]

% gbd hoge core.5045.5
これでいろいろと画面出力が出てくるはず(自分の結果をここに貼ることはできないので、↓の方にある他の人の記事参照)
ちなみにコアファイルと実行プログラムは1対1対応しているので、実行プログラムを修正してコンパイルし直すときちんとgdbが動かなくなるので注意な(すでに体験済)



このあとプログラムがどこまで進んだかをBackTraceで調べる
(gbd) の後に今のカーソルがあるので、btと入力する

左端に#0, #1, #2...と通し番号がある、これをframeというらしい

もっと詳しく見たい場合は
frame 25
と打つと、そのframeでの詳細が見れる


変数について詳しくみたいときはpを使う
p [変数名、配列名、構造体名]
と入力する
(gdb) p npoint_total
$2 = 1415577600
(gdb) p dataParameters[iChannel].sampleRate
value has been optimized out
(gdb) p dataParameters[iChannel]
value has been optimized out
「value has been optimized out」と表示されるのはなんでだろう?
=> コンパイル時に最適化してしまって見れなくなっている値らしい
ということは -O2 オプションを外せば見えるのかな? 今回は見てもしゃあないけど

最適化関連の話題については次の記事がわかりやすかった
■ 参考 : デバッガ


他にもxというコマンドもあるらしい、配列の中身を見るとかだった気がするけど
今回は使ってないので省略


gdbを終了するときは quit または q と入力する



■ 参考 : [GDB] 別環境で採取した Core ファイルを解析する方法

■ 参考 : コアダンプを解析しよう









(2018/06/16)
この記事はまだ執筆中です
そのうち修正します
非公開にしてると忘れるから晒しとくわ





こんなけC言語をやってて、配列とポインターをきちんと整理して理解できていない事に気づいた
というか、ある問題に直面して上手くいかないことがわかった(自分がちゃんと理解できてないから)


↓の記事は文字列じゃなくてint型の2次元配列の話だけど
*と[]の関係がわかりやすく書かれている

■ 参考 : 2次元配列を関数に渡すとき

**はポインタへのポインタ
ダブルポインタとも書かれる

あかん・・・理解できたと思って読み直したけど、またわからんなった・・・・






これは文字列の話ではないけど
int sum_all2(int xlength, int arr[][3]) {
・・・・
}
みたいな関数宣言がある
arrの最初の要素数は省略できるらしい
上の方の記事にわかりやすい説明が書いてあった

■ 参考 : C言語の引数に多次元配列を渡す

c99だと
int sum_all2(int size1, int size2, int arr[size1][size2]) {
という宣言ができるって書いてあったけど自分の環境ではダメだった
とりあえず今後のためにメモっておく






読んでも全然理解できなかったけどメモ
とりあえずダブルポインタを関数で跨がせるとダメなのは共感
■ 参考 : C言語 2重ポインタと関数に渡すときのまとめ


■ 参考 : 今こそ再考察! C言語ポインタ徹底解説


■ 参考 : C言語でのポインタのポインタについて

■ 参考 : 多次元配列の実現










切り捨て
double floor( double x )

切り上げ
double ceil( double x )

両方共math.hに入ってる

■ 参考 : C言語 小数点の切り捨て - math.h - [ floor ]

■ 参考 :C言語 小数点の切り上げ - math.h - [ ceil ]




なんか自分の書いたコードが思っているのと違う挙動をしていてちょっと困った・・・・

fprintf(stdout, "hoge ");
みたいな感じで改行を挟まずにループを何個も回して、最後に
fprintf(stdout, "\n");
と改行を入れるコード

実際に動かしてみると、待ってもhogeが表示されない・・・
しかし計算はどんどん進んでいっていることがstderrの情報からはわかる
stdoutは内部に出力バッファを持っていて、printfやfprintfでは改行文字を出力するか出力バッファが一杯になるまで溜め込みます。
改行文字がなくても強制的に吐き出させるのが fflush です。
■ 参考 : fflush(stdout)の意味

とのことらしい
なるほどね・・・
fprintfは、\nが来るまで実際に画面表示がされないというのは今回初めて知った・・・・

今回のコードでstderrは毎回\nが入っていたので、その都度表示されていたのも納得がいった
なおかつ、stderrとstdoutはバッファが違うから、今回のようなことになったんだろうなぁ〜














printf("%%\n");
でOK

\%でできるかな〜と思ったけどダメだった








判別する方法は、
#include <math.h>

if ( isnan(x) ) {
 // これはNaNの場合
} else {
 // NaNでない場合
}

if ( isinf(x) ) {
 // これはInfの場合
} else {
 // Infでない場合
}
じゃあ判別できているのかのテストの方法は、

■ 参考 : infやnanになる条件

log(0)とか、5/0.0とかやってみたけどすべてInfになってしまった・・・

■ 参考 : 8.3 math.h

このままではNaNのテストができないので、
math.hにNANってマクロがあるらしいので、それに対して調べてみた

あとでもうちょっと調べてみたら、sqrt(-1.0)って作り方もあるらしい




以前軽く調べた知識によると、IEEE_754では
NaNもInfも指数部のビット全て1(つまり255)
NaNは仮数部が0以外の任意の値
Infは仮数部が0
らしい

そんなことを知らなくても、上記のisnanとかで調べられるからまぁいっか・・・・










前回書いたMPIの記事はあまりにめちゃくちゃだった・・・
今回もめちゃくちゃです

一応、既存のコードの並列化自体はできて、並列処理はできました
(そもそも既存のコードが遅いので、、まだまだ改善の余地がありますが)

もっと早くする方法について色々と調べて行くと「master/slave方式」というのが見つかった




通常並列化するときは

例えば何かある値をn個計算するとして逐次コードだと、
for(i=0; i<n; i++){
// 何か計算
}
みたいにしてやる


これをncore個のcoreで並列化するときは、サイクリック配置
for(i=0; i<n; i=i+(ncore)){
// 何か計算
// MPI_Gatherで集める または printfとか
}
または、ブロック配置では
for(i=(myrank*ncore); i<(myrank+1)*ncore; i++){
// myrankはそのプロセスのrank
// 何か計算
// MPI_Gatherで集める または printfとか
}
みたいな感じか?(上ので合ってるかはわからんけど)
他にもこれらを組み合わせたブロックサイクリック配置というのがあるらしい

どうやって逐次コードを並列化するかはその計算処理自体に依存するのでケースバイケース





一方でmaster/slaveでは、myrank==0のプロセスは他の監視するためだけに使う
myrank!=0のプロセスは何かの処理や計算をする

言うのは簡単だけど、これを実装するのがなかなか大変・・・
サンプルコードも色々と探したけど、そのまま活用できそうなのが見つからない
もうちょっと書くと、計算に必要なパラメーターをmasterがsend(MPI_Send)して、slaveがreceive(MPI_Recv)して計算を走らせる
計算が終わったらslaveがmasterに値をsendして、masterが値をreceiveする
そのslaveは次の計算ができるので、また走らせて・・・というのを管理していく
masterはいつでも受信できるように
MPI_Recv(&result, 1, MPI_DOUBLE, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status);
のようにANYを使う

たぶんこういう理解で合ってるはず・・・

大まかなmaster/slave方式は以下のコードを見てもらえるとわかるはず
myidという変数で場合分けしてる
■ 参考 : code_mpi_exp/test_mpi5.c

他の例もある(githubでも割と探した)
■ 参考 : Parallel programming: an MPI example

■ 参考 : pi-pp/serie_4/master_slave_template.c

■ 参考 : pi-pp/serie_4/mpi-master-slave-template.c

一つ上のとすごく似ているが微妙に違う

■ 参考 : ValiTDS/valiTDS/gcd.c

ポルトガル語で説明が書いてあるけど、要するに3つの整数の最小公倍数を探す計算らしい


■ 参考 : Master/slave programs in MPI

動くコードがすべて書いてくれている
ありがたい


■ 参考 : /* 1からこの数までの和を求める */

どういう経路で見つけたページか忘れたけどすべてのコードが書いてある
コピペで完全に動いてビビった





他のサンプルコードは、「MPI 並列化 "サンプルコード" C言語 -pdf」とかで検索しても全然見つからない
その検索で見つけた興味深い記事をメモしておく

■ 参考 : Message Passing Interface (MPI) 統合スレ

ネット上にマジでまとまった情報がないから2chに行ってみた
2004年からある老舗だが、あまり活発ではないらしい
とりあえず一度全部さっと目を通しておくとMPIのソースコードには慣れられる


■ 参考 : link集/MPI

2009年で更新が止まっている


■ 参考 : MPI Programming samples

リンク集の中にあった東工大のサンプルコードページ
見つけたサイトの中ではかなり有意義なページ
実際にコピペでは動かないものがあるので注意



■ 参考 : MPI Documents

日本語のpdfもあるが、1997年のものだった
少しだけsample codeがある

■ 参考 : Web pages for MPI and MPE

上記のページのdocumentは少し検索しずらかったり、読みにくい
web page版があった






色々と調べて感じたのが、MPIによる並列化ってまだ今も使われている技術なんだろうか・・・
並列化って今はもっと他のライブラリとかを使ってたりするのだろう
ちょっと不安だけど、まぁもうちょっとやりこんでみる・・・・




(2016/10/10 追記)

今更だけど、すごくよくまとまったページを見つけた

■ 参考 : PCクラスタ超入門 講習会テキスト


この中で特に「MPIによる並列プログラミングの基礎」というのが役に立ちそう
他のドキュメントはまだ見てないけど、高速な並列化をするために重要なことが書かれていそう・・・ まだ見てないけど




(2017/06/18 追記)

たまたま↑のページを見に行ったら、ページがなくなっていた
オーマイガッ

















■ 参考 : MPI_Wtime
double MPI_Wtime( void )











計算に11時間かかるッスって言ったら並列化すればいいじゃん
なんならコードの並列化をやってあげる
という優しい言葉を受けて初めての並列化に手を出してしまった・・・・
わからないことだらけなのでメモしておく



まずはMPIのインストール
省略




■ 参考 : MPI Hello World

上記のサイトを参考にしてテストコードを書いてみる
途中まで読んで英語だったからめんどくなった・・・


■ 参考 : MPI「超」入門(C言語編) - 東京大学
↑難しいすぎる、猿の私には上っ面しかわからんかった

■ 参考 : MPIを用いた並列プログラミングの概要


こっちに日本語の文章があったのでこっちを見て行く

大事なのは「各プロセスは同じことをやるがデータがそれぞれ異なる、大規模なデータを分割し、各部分について各プロセスが計算をする」ということだと思う
並列のためにでかいデータを分割する、というのは初めてなので工夫しないといけないなぁ〜
スライドの中盤にも、「領域分割」としてそのことが書いてあった

・PE : Processing Elementの略、ここではプロセスという意味で使っているらしい

・MPIのプロセス番号は0から始まる、なので8プロセス走らせる場合は0~7が割り当てられる

・MPIのコードのコンパイラはgccではなくて、mpiccというのを使う

・MPIに関連した変数名はMPIで始まっている
 なので、ユーザー独自の変数としてMPIなんとかは使わない方がいい
#include <mpi.h>
まぁ、こういうヘッダーファイルがいるんだろう
インストールがうまくいってPATHがきちんと通っていれば問題ないはず
MPI_Init(&argc,&argv);

MPI_Finalize();
すべての並列化処理は MPI_Init から MPI_finalize の間で書かれなければならない
MPI_Comm_size(MPI_COMM_WORLD,&numprocs);
必須ではないらしい
これで総プロセス数の取得をしているらしい
numprocsがプロセス数
MPI_Comm_rank(MPI_COMM_WORLD,&myid);
起動した各プロセスにはそれぞれ「ランク」と呼ばれる値が割り当てられ、それを取得する関数
ランク値は他のプロセスを指定して通信するときとかに使うらしい


便利そうなのは
MPI_Barrier
すべてのプロセスの同期を取ってくれる関数
すべてのプロセスがこのサブルーチンを通らない限り、次のステップには進まない

と思ったけど「主にデバッグに使う、オーバーヘッドが大きいので実用計算には使わない方が無難」と書いてあるわ・・・・
sprintf(FileName, "%d.txt", MyRank);
のように各プロセスの通し番号を使うこともできる


MPIはCPU core毎にMPIプロセスを実行する
Rank数はコアの数に等しい

hostfileのフォーマットは
node01 slots=4
node02 slots=4
node03 slots=4
node04 slots=4
node05 slots=4
みたいな感じらしい
slotsには各ノードのCPU数を指定する


プロセスごとに通信(送信/受信)とかもできるらしいが、そんな難しいのはまだいらないと思うので・・・
今やりたいのは、単純に1つのコードを複数のプロセスに分担させて並列で走らせたいだけ





(2016/10/1 追記)

■ 参考 : 技術コラム

この記事の第50回〜58回あたりはMPIの並列化について説明されていて、わかりやすかった














ほんとたまに使うだけなので、いつも関数名を忘れるのでメモ
(そうだこのブログはポケモンGOブログではなくて備忘録だった!)
#include <complex.h>
double complex hoge;

double real_part = creal(hoge); //実数部のみ
double imaginary_part = cimag(hoge); //虚数部のみ

double absolute = cabs(hoge); //複素数の絶対値
double phase = carg(hoge); //複素平面上の偏角

double complex conjugate = conj(hoge); //複素数の共役複素数

double complex conjugate = cpow(hoge); //複素数のベキ乗(使うのか?)






(2020/03/15 追記)

cargというのを使ったが、これは便利だわ
realとimaginary成分に分けてatan2(imag, real)とかやらなくて済む





3ヶ月前から動かないコードが手元にあった
元々は3年以上前に自分が書いたコードなのだが、なぜか一括で
% make
とするとコンパイルがそこで止まる・・・
特に手を加えたわけでもないのになーぜー

Dropboxで過去のファイルに戻ろうとするも、古すぎて履歴が残っていない(もしかしたら、ファイルをコピーして作ったからとか移動させたからかもしれない)

とりあえず急務なものでもなかったので、放置してた
(実はそれがけっこう便利なプログラムで、周波数と周波数スペクトルの値を渡すと横軸質量、縦軸inspiral rangeのグラフを書いてくれる)

コンパイルが通らない理由がやっとわかって、コードの中からカンマがなくなっていた
「いや、なんでだよ」と言わざるを得ない・・・




コードに一つ改良を加えた
今までpdfしかグラフ出力できなかったが、与えた出力ファイル名から拡張子を判断してグラフを書かせる
今までこういうグラフ処理までさせるときは実行部分をC言語で書いて、グラフ描画をシェルスクリプトと分担していたが、今回のコードはかなり前のなので全部C言語でやっていた

そのためにはまず与えた文字列から拡張子を判断する必要がある
strrchrを使う
strchrも似たような文字列検索だけど、こっちは後ろから検索するので拡張子を見つけられる
そもそも.で検索すれば一発なはずだから、どっちを使っても同じ結果になるはずだけど後ろの情報が欲しいので実行時間を減らすためにもsttchrで
(.が2個以上あったら困るんじゃない?と思うかもしれないけど、たぶんMacでは.が2個あるファイルが作れない)

■ 使い方
cFindが検索する対象の文字列
cKeywordが検索する文字列(int型)
#include
char *strrchr(const char *cFind, int cKeyword);
例えば
cFind="hoge.png";
cKeyword=".";
だとすると、返り値は .png になる
拡張子にするためには 1つポインタを進めればよい(っていう表現で合ってる・・・?)


■ 例文
初めて使って動いたのでたぶんこんな感じなんだろう、知らん
char *cTerm=""; //初期化大事
int cKeyword = '.'; //検索する文字列
cTerm = strrchr( output, cKeyword); // cTermになんか入る

if( cTerm == NULL ) {
// こっちはkeywordが見つからなかったとき
//なんか例外処理
}else{
// keywordが見つかったとき
cTerm++; // これで.の後ろの文字列からなので拡張子になるはず
//なんか処理
}






非常に解りやすい記事があったのでそのメモ

■ 参考 : 2 関数のデータの渡し方




関数に変数を渡しても、その計算はmain関数のメモリとは別の場所で計算される
なので関数に何か変数を渡しても、その値が書き換えられることはない

では逆に書き換えて返してほしい場合はどうするか?
1. 関数の返り値に指定する
2. 関数に変数のアドレスを渡す

1は
int hoge(int a, int b);
みたいな感じ
けど、これじゃあ1つしか変数が返せない・・・


2は
void hoge(int a, int b, int *c, int *d);
みたいにして、aとbはただ関数に渡すだけで、cとdに欲しい値が入って返ってくる
この関数を呼ぶときは
hoge(a, b, &c, &d);
みたいにして、変数のアドレスで渡さないといけない
また、関数hogeの中ではcとdに何かを代入するときは
*c = a+b;
*d = a-b;
みたいにしないとだめ


(もしかしたら間違った理解をしているかもしれないので注意・・・・)









# 今更C言語のことを書くとは・・・

scanf系の関数でなぜオーバーフローが起こる可能性があるのかは、ここに書いてあります
■ 参考 : [迷信] scanf ではバッファオーバーランを防げない


また、その解決方法はこちら・・・
■ 参考 : scanf 系関数での文字列長指定方法

マクロ関数を使って、うまいこと回避しているようです



この記事を読んで初めてマクロ関数というのに触れました
一応知識では知っていましたが
#define SCNs(n) SCNs_(n)
#define SCNs_(n) #n "s"
の#nが何をしているのかわからず調べました
nという渡された変数に#を付けると、その値をそのままそこに展開できるらしい

これを使うと、
#define N 10
char s[N-1];
scanf("%"SCNs(N), s);
で、SCANs(N)の部分が"10s"に置き換わって、うまいこと文字配列の上限値を指定できると・・・

これ、char s[N+1]; の間違い?
よくわからん・・・・



これで
scanf without field width limits can crash with huge input data on some versions of libc.
というwarningがなくなればいいのが・・・・






最近、関数ポインタについてあれこれ理解する必要に迫られたので調べた

関数ポインタを利用して呼び出す関数を動的に変更する

このページの説明が割としっくり来た
関数Aに、さらに関数Bを渡すときにポインタでそれを渡してしまうことで
関数Aの中で使われる関数Bを簡単に置き換えることができる

例えば積分する関数などで(今思い返せばnumerical receipeの中で積分する関数もこれを用いていたような・・・)
積分するための関数をAとする
被積分関数をBとする
関数Aの引数にBを渡す

このときBをxとかcos(x)とか変えれば、積分値もそれにともなって変わるというのが関数ポインタ


という理解であってるのかなぁ?














やりたいことはタイトルの通り
forkというのを使ってみる
詳細な説明は参考にした記事をどうぞ

■ 参考
http://linuxjm.sourceforge.jp/html/LDP_man-pages/man2/wait.2.html



とりあえずサンプルコードを書いてみた
本当に必要なヘッダーがどれかわからん・・・
もしかしたら不要なものを呼んでるかもしれない

このforkを使えば色々と計算させるプログラムで役に立つかも・・・?









これまで4年ほど計算機に触れてきたけど、こんなに便利なものを見過ごしてきたなんて・・・・

とりあえず設定ファイルにPKG_CONFIG_PATHを設定する
自分の場合は
setenv PKG_CONFIG_PATH /usr/local/lib/pkgconfig:/opt/local/lib/pkgconfig/
の2つくらい

これで
$ pkg-config --cflags fftw3
-I/usr/local/include
$ pkg-config --libs fftw3
-L/usr/local/lib -lfftw3 -lm
あとはこれをmakefileの中でうまいこと使えばおーけー。





某ライブラリを使ってプログラムを書いていた
無事コンパイルまでは到達したが(ここまで4時間・・・)
実行してみると、以下のようなエラーが出てきた・・・
一瞬とても嫌な汗をかいた
error while loading shared libraries: libhoge.so.1: cannot open shared object file: No such file or directory
ググってみると、
「どうやらダイナミックリンクを使っているプログラムを実行はしたものの、そのダイナミックリンクを見つけられませんでした」
というエラーらしい

解決方法は、
・ダイナミックリンクをデフォルトで探しに行く場所(/usr/libとか?)にシンボリックリンクを貼る
・ダイナミックリンカーが参照する環境変数 LD_LIBRARY_PATH に追記する
らしい。

とりあえず LD_LIBRARY_PATH にライブラリの場所を追記したら、無事動きました・・・・。
setenv LD_LIBRARY_PATH /home/hoge/foo/lib

ほんと新しい計算機で、プログラムを動かすだけなのに一苦労・・・・

■ 参考
LD_LIBRARY_PATH とは







プロフィール
HN:coffee
職業:物理屋(自称)
趣味:映画鑑賞、登山
出身:大阪府の南の田舎
自己紹介:
import MyProfile
import coffee_pote from TWITTER
import amazonのほしい物リスト from WISH_LIST

print "先月子供が産まれました!"

# 最終更新 2022/10/25
カウンター
カウンター カウンター
ブログ内検索
ツイートするボタン
リンク
相互リンク募集中です (Twitterにてお知らせください)

Demo scripts for gnuplot version 5
(gnuplotのさまざまなデモ画像と作り方がまとめられている、眺めているだけでできるようになった気分になれる)

gnuplotスクリプトの解説
(米澤進吾さんの個人ページ、gnuplotと言えばこのかた)

gnuplot のページ
(Takeno Lab、うちのブログがリンクされていたのでリンク返し)

Twitterから映画の評価が分かる & 映画の鑑賞記録が残せる coco
(映画の感想をまとめられるサイト、いつもお世話になっています)

Astronomy Picture of the Day Archive
(天文や宇宙関連の最新の話題について画像とともにNASAが説明しているページ)

今日のほしぞら
(任意の時刻の空で見える星を表示してくれる、国立天文台が管理している)

GNUPLOTとアニメーション
(応用の項目の「見せてあげよう!ラピュタの雷を!!」あたりからすごすぎる)

読書メーター
(読んだ本をリストできる便利なサイト)

flickr難民の写真置き場
(20XX年、flickrは有料化の炎に包まれた。あらゆるflickr無料ユーザーは絶滅したかに見えた。 しかし、tumblr移住民は死に絶えてはいなかった。)

教授でもできるMac OS X へのLaTeX, X11, gccのインストレーションと環境設定
(阪大の山中卓さんのwebページ、タイトルにセンスが溢れている、内容は超充実してる、特にTeX関連、学振DCとかPDの申請書類作成時にはお世話になっております)

英語論文執筆用の例文検索サービス
(とんでもないものを見つけてしまった・・・・ arXivに収録されている 811,761報の 英語論文から,例文を検索するための検索エンジン)


Template "simple02" by Emile*Emilie
忍者ブログ [PR]