512×512の正方行列を100乗する計算時間の計測。 AVX、SSE,OpenMPの効果がどれ位あるかを計測する。 ■コンパイル方法■ ●Windows:OpenMP x64 m 2010 m 2013 m 2017 m 2019 m Gcc x86 m 2010 32 m 2013 32 m 2017 32 m 2019 32 m Gcc 32 ●Windows:No OpenMP x64 m 2010 +n m 2013 +n m 2017 +n m 2019 +n m Gcc +n x86 m 2010 32 +n m 2013 32 +n m 2017 32 +n m 2019 32 +n m Gcc 32 +n ●Ubuntu:OpenMP x64 : g++ -I. -Wall -fopenmp -O4 AvxOmp.c x86 : g++ -I. -Wall -fopenmp -O4 -m32 AvxOmp.c ●Ubuntu:No OpenMP x64 : g++ -I. -Wall -O4 AvxOmp.c x86 : g++ -I. -Wall -O4 -m32 AvxOmp.c ※注意 並列リージョンの中でポコムの関数をできるだけ呼び出さないでください。 例えば、GetMem( ), FreeMem( ), Strdup( ), SetStr( ), SetSvec( ), SetSmat( ), SetSjag( ), AllocStr( ), AllocSvec( ), AllocSmat( ), AllocSjag( ) 等を 呼び出すと恐らくトラブルが起こります。 これらはクリティカルセクションを使えばコンソールモードでは上手くいく かもしれません。 一方、ウィンドウズモードではメモリ確保や解放を行う関数は、 マスタースレッド以外でエラーが起きた場合にメッセージループを 呼び出すのでクリティカルセクションで囲ってもクラッシュします。 GetMem( ), FreeMem( ) は代わりに GetMemRaw( ), FreeMemRaw( ) を使用して下さい。 ポコム Version 8.16 以降では Progress( ), Progress2( ) は ウィンドウズモードでもクリティカルセクションで囲めば、並列リージョン内でも 正常に動作します。理由は、マスタースレッド以外ではメッセージポンプや タイトルの書き換えを呼び出さなくなったからです。 ただし、ウィンドウズモードで OpenMP の場合は旧形式表示の指示をする マクロ OLD_PROGRESS は無効にされます。 ポコム Version 8.15 以前の場合、ウィンドウズモードで並列リージョンの中で クリティカルセクションで囲っても Progress( )、Progress2( ) を呼び出すと マスタースレッド以外からメッセージポンプやタイトルの書き換えをするので クラッシュしていました。 並列リージョンの中で Progress( ) をクリティカルセクションで囲む例を示します。 例えば、以前のバージョンでは以下のように Progress( ) を並列リージョンの 外に書いていましたが、 void F87Mth1(void) { Int i,z; Copy(); for (z=0;z<Z;z++) { #pragma omp parallel for for (i=0;i<N;i++) { Int j; for (j=0;j<N;j++) F87(i,j); } Progress("#F87Mth(1) ",z,Z); } PrintSum("Normal multi thread(1)"); } は次のように書き換えます。 void F87Mth2(void) { Int z,n=0; Copy(); #pragma omp parallel for for (z=0;z<Z;z++) { Int i,j; for (i=0;i<N;i++) for (j=0;j<N;j++) F87(i,j); #pragma omp critical Progress("#F87Mth(2) ",n++,Z); } PrintSum("Normal multi thread(2)"); } この例の場合、後者の方が速くなります。 もし for (i=0;i<N;i++) for (j=0;j<N;j++) F87(i,j); の実行時間が長くて、 応答と表示が遅くなる場合は Progress2( ) を使います。以下に例を示します。 void F87Mth3(void) { Int z,n=0,m=0; Copy(); #pragma omp parallel for for (z=0;z<Z;z++) { Int i,j; for (i=0;i<N;i++) { for (j=0;j<N;j++) F87(i,j); #pragma omp critical Progress2("#F87Mth(3) ",n,Z,m++,N); } #pragma omp atomic n++; m=0; } PrintSum("Normal multi thread(3)"); } 乱数については Rand_t 型をスレッド毎に用意していれば Srand_r( ), Jump_r( ), Rand_r( ), Unif_r( ), BackRand_r( ), BackUnif_r( ) 等は 並列リージョンの中で性能を落とさず使用することができます。 また Srand( ), と Jump( ), は並列リージョンの中で使えませんが、 Rand( ), Unif( ) BackRand( ), BackUnif( ) などは並列リージョンの中で 性能は落ちますが使用することができます。 これは、Rand( ) から Rand_r( ) を、BackRand( ) から BackRand_r( ) を呼び出すときに クリティカルセクションで排他処理をするからです。 また例えば8スレッドならば #define FAST_RAND 8 として、Rand_m( omp_get_thread_num() ), Unif_m( omp_get_thread_num() ) 等も 並列リージョンの中で使用することができます。