08/09/07 17:53:44
#pragma omp for は #pragma omp parallel ブロックの中に書く必要があるが、
parallelブロックにforブロックが1つのことも多いので
#pragma omp parallel for でまとめて書けるようにしてある。
167:デフォルトの名無しさん
08/09/09 22:58:56
なるほど。
168:デフォルトの名無しさん
08/09/16 07:09:33
>>143 >>68
スレチな質問で申し訳ないのだけどdllをリンクする設定を
教えて頂けないでしょうか
>>119を参考に
WindowsVista+Visual Studio2005 standardで
Microsoft Windows Software Development Kit for Windows Vistaと
vcredist_x86.exeでReleaseのビルドは通るようになった
で>>68を参考に
インストーラーを作ってみたのですが
C\ProgramFiles\Microsoft Visual Studio 8\VC\redistに入ってしまい
winsxsには入ってくれません…
169:デフォルトの名無しさん
09/01/21 13:22:31
並列化前後で答えが変わってしまいます。どこがおかしいのでしょうか?
//画像上でランダムで数点選んできた線との距離が最少になる座標を算出
#ifdef _OPENMP
#pragma omp parallel for private(data,x,y,a,b,i,error)
#endif
for(j=0;j<KURIKAWSIKAISUU;j++){
better_error[j] = 1000;//距離初期化
for(y=100;y<=HEIGHT-100;y++){
for(x=100;x<=WIDTH-100;x++){
error = 0;
get_randum_number(data); //ランダムでデータNo.を選択
for(i=0;i<ITIDONIERAZUKAZU;i++){
error += abs(y - a[data[i]]*x - b[data[i]]) / sqrt(1+pow(a[data[i]],2));
}
error /= select;
if(better_error[j] > error){
better_error[j] = error;
ans[j].x = x;
ans[j].y = y;
}
}
}
}
170:デフォルトの名無しさん
09/01/21 14:08:01
よくわかんねけど
get_randum_number
で配列dataにはいる乱数が変わるからじゃね?
たぶん呼ばれる順番が並列と1CPUのときで違うだろうから。
ループ内で乱数つくらないで、でかい乱数用の2次元配列
data0[KURIKAWSIKAISUU][ITIDONIERAZUKAZU]
をループが始まる前に「並列処理しないで」作ってから
(配列data0をshared属性付けて)ループ処理するといいかも。
計算は遅くなりそうだけどね。
171:デフォルトの名無しさん
09/01/21 14:12:47
んでループ内で乱数生成してた部分は
for (i=.....){data[i]=data0[j][i];}
と乱数値の複製に置き換える、と。
172:169
09/01/26 11:03:50
>170
>171
ありがとうございます。
いただいた意見を参考に修正し、できたらご報告します。
173:デフォルトの名無しさん
09/01/26 11:33:59
マルチスレッドでrand()使うと全然ランダムじゃないデータが出てくるよ
174:デフォルトの名無しさん
09/01/26 12:52:37
rand_r
175:デフォルトの名無しさん
09/02/24 20:57:22
gcc-4.3 で OMP を使い始めました。初心者で正しい使いかたをしている
かどうか判然としません。/proc/cpuinfo で cpufamily 6, model
23 (Harpertown と呼ぶらしい)と表示されるXEONでは確かに速くなるので
すが、cpufamily 15 model 4 (Nocona と呼ぶらしい) では非常に遅くな
ります。これは正しい振る舞いでしょうか。時間は
clock()/CLOCKS_PER_SEC; で測っていますが、これで正しい判断ができる
のでしょうか? 並列化すれば速くなる速度のネックになっている部分を
探す方法はあるのでしょうか? 並列化できるかどうか判然としない部分
を並列化可能なコードに書き直してくれるようなソフトはないでしょうか?
176:デフォルトの名無しさん
09/02/24 23:13:22
どうせNoconaの方はデュアルCPU構成じゃなくてしかもHT無効というオチだろ。
177:デフォルトの名無しさん
09/02/25 00:35:19
Nocona の /proc/cpuinfo は
processor : 0
..
processor : 3
vendor_id : GenuineIntel
cpu family : 15
model : 4
model name : Intel(R) Xeon(TM) CPU 3.80GHz
stepping : 3
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca
cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx
lm constant_tsc pebs bts nopl pni monitor ds_cpl est tm2 cid cx16 xtpr
となっています
178:デフォルトの名無しさん
09/02/25 23:58:19
環境変数 OMP_NUM_THREADS などでスレッド数を指定してますよね。
明示的に指定しないと環境によってスレッド数が1になったりコア数になったりします。
きちんと並列実行できているのに 4-way Nocona で並列性能が出ないとすると
応用依存の問題かと。例えばメモリ帯域幅がネックになっているのかも知れません
(Harpertown ではメモリ帯域幅が足りていて Nocona では足りていないとか)。
どういう計算をしているのかを書くともっと直接的なアドバイスが得られるかもです。
計時の仕方はそれでいいと思います。精度が気になるなら RDTSC について調べると良さげ。
速度のネックになっている部分は、皆目見当がつかないならプロファイラが利用できます。
GCC なら -pg オプション付きでコンパイル、プログラム実行後に gprof コマンドを使って
統計情報を得ます。
時間のかかっている部分が分かったとしてそれを並列化して高速化できるかは別問題。
OpenMP はループを分割して並列化するのがお手軽で効果的ですが、
それができるのはループ間にデータの依存関係がない場合です。
a[i] += a[i-1] のように前後の反復の計算結果を利用したり、
配列の同じ要素に書き込むといった処理がデータ依存性の典型例です。
データ依存関係がある場合はコードを書き換えないと普通は並列化できません。
このあたりは並列プログラミングの普遍的な課題で、対策はケースバイケースです。
自動並列化は研究レベルではよく聞きますが実用的なツールは寡聞にして知りません。
よい自動並列化ツールがあれば私も試してみたいです。
179:デフォルトの名無しさん
09/02/26 01:53:54
Intel C++ Compiler 11.0の自動並列化オプション(-parallel)でSPEC CPU 2006のいくつかのベンチマークが高速化しているが
実際のコードでどれだけ役に立つかは使ったことが無いのでわからない
180:デフォルトの名無しさん
09/03/07 23:30:29
OpenMPの効果を調べるため、同じコードを、gfprtranで二通りにコンパイルして実行してみました。
全然速くなりません。むしろ遅くなっています。実行方法やコードが間違っているのでしょうか?
gcc version 4.3.2 (Debian 4.3.2-1.1)
$ gfortran -fopenmp test.o -o test_omp.out
$ time ./test_omp.out
real 9m14.642s
user 3m51.902s
sys 4m22.468s
$ gfortran test.o -o test.out
$ time ./test.out
real 1m15.142s
user 1m14.809s
sys 0m0.340s
CPUは...(/proc/cpuinfoの抜粋)
model name : Intel(R) Pentium(R) D CPU 2.80GHz
cpu MHz : 2793.101
cache size : 1024 KB
cpu cores : 2
181:180
09/03/07 23:32:33
ソースコードは
module ompParam
use omp_lib
implicit none
!integer :: OMP_GET_NUM_THREADS
!integer :: OMP_GET_THREAD_NUM
integer :: myid ! thread ID
end module ompParam
program variation !(coeff, NUM)
!$ use ompParam
implicit none
integer :: i, j, k
integer :: maxI=1000, maxJ=100, maxK=1000
integer :: NUM
double precision, allocatable :: coeff(:,:)
double precision :: alpha ! random number
NUM=1000
allocate( coeff(NUM, maxK) )
coeff(:,:) = 0.0d0
182:180
09/03/07 23:33:54
(続き)
!$omp parallel num_threads(2) private(myid, i, j, k, alpha)
!$ !myid = OMP_GET_THREAD_NUM()
!$ !write(*,*) '(Number of threads in front of do)=', myid
open(unit=100, file='data.bin', form='unformatted', status='unknown')
!$OMP DO
do k = 1, maxK
do j = 1, NUM
do i = 1, maxI
call RANDOM_NUMBER( alpha )
coeff(j,k) = coeff(j,k) + alpha
!$ !myid = OMP_GET_THREAD_NUM()
!$ !write(*,'(3(A4,I3),A37,I2)') 'k=', k, 'j=',j, 'i=', i, 'Number of threads at the end of do:', myid
end do
coeff(j,k) = coeff(j,k) / maxI
write(100) coeff(j,k)
end do
end do
!$omp master
!$ !myid = OMP_GET_THREAD_NUM()
!$ !write(*,*) '(Number of threads after the do)=', myid
!$omp end master
!$omp end parallel
end program variation
183:デフォルトの名無しさん
09/03/08 14:53:53
gfortranは良くしらんけど・・
環境変数で使うCPUの数を指定してみて。
setenv OMP_THREAD_NUM 2
とか。プログラム内で明示しているからいらない気もするけど、まあ
正確にはマニュアルで確認してね。
あとは、I/O(read,write文)はparallel文の外で
するのが吉。この例だと、open(100,....) と write(100)....は
!$omp end parallel
の後でする。ふつうI/OはプライマリのCPUが単独で担当させる方が安全。
同じファイルに複数のプロセスが書き込みしようとすると
順序の保証が無くなるのであとで使いにくいし、書き込みの順番待ちが
発生するのでのろくなる。
乱数代入のループだけなら1/2になっている可能性大。そうなら
作ったコードは一応OpenMPとして動作している・・・と思う。
184:180
09/03/09 17:16:44
>>183
ありがとうございます。実行シェルは作らず、そのまま
$time ./test_omp.out
という風にやっていました。これから実行シェルを作って見ようと思います。
あと、i/oを外に書いたら、確かに一割ほど速くなりました。
でも、それでも圧倒的にOpenMPは遅いです...
185:180
09/03/09 17:18:47
乱数を使わないプログラムだとOKでした!!
~/test$ /bin/csh ./testOMP_exec.sh
Normal version executing...
2.2u 0.0s 0:02.20 100.4% 0+0k 0+1584io 0pf+0w
OpenMP version executing...
2.1u 0.0s 0:01.14 190.3% 0+0k 0+1584io 0pf+0w
資源使用率190%!!乱数発生器がパラレルに対応していなかったようです。
アドバイス、ありがとうございました。
186:183
09/03/10 04:04:33
あ、そっか
乱数生成って種を使いまわすから、並列のときは最初に疑うべきだったね。
あまり役に立たなかったっぽいけど、
とりあえず、おめでとう。