1 of 25

共有メモリを使ったデータ交換と同期 �

慶應義塾大学理工学部

天野英晴

hunga@am.ics.keio.ac.jp

2 of 25

同期の必要性

  • あるプロセッサが共有メモリに書いても、別のプロセッサにはそのことが分からない。
  • 同時に同じ共有変数に書き込みすると、結果がどうなるか分からない。
  • そもそも共有メモリって結構危険な代物
  • 多くのプロセッサが並列に動くには何かの制御機構が要る

  • 不可分命令、同期用メモリ、バリア同期機構

3 of 25

Fork-join: 並列プロセスの開始と終了

fork

forkで生まれたプロセス(スレッド)間は

メモリを共有

joinで全プロセスの待ち合わせをする

→同期を取っている

簡単な並列プログラムはfork/joinのみ

で制御できる→OpenMP

fork

join

join

4 of 25

排他制御

  • プリンタがあり、一度に一つのプロセッサしか使えない。同時に要求があった場合に一人を選びたい。
  • アイディア:
    • 変数xを0に初期化しておく。
    • xを読んだプロセッサは、0ならば素早く1を書き込み、プリンタを利用。終わったら0を書き込む。
    • 1を読み込んだプロセッサは0を読み込めるまで繰り返し読み続ける(Busy Waiting)

→しかしこれはうまく行かない。なぜか?

5 of 25

P1とP2が同時に変数を読んだら?

0

P1

1.xを読み出す

2.0かどうかをチェック

3.1を書きこむ

P2

1.xを読み出す

2.0かどうかをチェック

3.1を書きこむ

P1がxを読んで0かどうかをチェックしている間に、P2がxを読み出すかも

しれない→P1,P2共に0を取ることができる。

読む操作と書く操作を不可分(Atomic/Indivisible)に行う命令が必要

→不可分命令

6 of 25

Test & Set (x)

0

P1

同時に命令が実行されても、必ず一つだけ0を読み、他は1にする。

→ハードウェアの支援が必要

他にもSwap, Compare&Swap, Fetch&Dec, Fetch&Addなど色々

あるが、原理は同じ

P2

Test&Set(x)

Test&Set(x)

xを読み出す。

1を書きこむ

2つの操作を不可分に行う

この間共有メモリを占有

7 of 25

Critical Sectionの実行

Test&Set(x)=0?

No.

Yes.

Critical Section

この例ではプリンタを使う

x = 0

忘れずにx=0にしておく.

一つだけが実行できる領域

不可分命令があればCritical Sectionが作れる→なんでもできる!

でもちょっと使いにくい

8 of 25

バリア同期

Barrier;

Barrier;

Barrier;

バリア成立

.

バリア同期は不可分命令があれば作れるが、専用の

ハードウェアを使う場合もある

バリア成立を待つ

P1

P2

P3

9 of 25

OpenMP:�最も簡単なマルチコア利用法

  • 共有メモリをベースにして、普通のC,C++プログラムを言語の構造単位に並列化
  • directive (pragma)と呼ぶ指示子を使う
  • gccに環境が組み込まれているので簡単に利用できる
  • 効果が得られるコアは比較的少数

10 of 25

OpenMPの実行モデル

Block A

#pragma omp parallel

{

Block B

Block C

Block A

Block B

Block B

Block B

Block C

Thread fork

Thread join

Master Thread

環境変数: OMP_NUM_THREADS で実行スレッド数を設定

Parallel Region

11 of 25

for 文

# pragma omp parallel

{

#pragma omp for

for(i=0; i<1000; i++) {

c[i]=a[i]+b[i];

}

}

# pragma omp parallel for

for(i=0; i<1000; i++) {

c[i]=a[i]+b[i];

}

反復は各スレッドに等分に

割り当てられる

12 of 25

 sections 文

#pragma omp parallel sections

{

#pragma omp section

sub1();

#pragma omp section

sub2();

#pragma omp section

sub3();

}

sub1

sub2

sub3

Thread join

三つの違った処理が並列に実行され、

終了時に同期される

13 of 25

 private sub-directive

# pragma omp parallel for firsptrivate(c)

for(i=0; i<1000; i++) {

d[i]=a[i]+c*b[i];

}

c は各スレッドにコピーされる → 高速実行が可能

firstprivateで初期化

14 of 25

private sub-directiveの利用

# pragma omp parallel for private(j)

for(i=0; i<100; i++) {

       for(j=0; j<100; j++)

a[i]=a[i]+amat[i][j]*b[j];

}

shared: 全スレッドで共有

private:各スレッドで用意、初期化はしない

firstprivate: 各スレッドで用意、初期化される

この文をprivate(j)なしに実行したらどうなるだろう?→

全てのスレッドでjが更新される→エラー!

15 of 25

reduction sub-directive

# pragma omp parallel for reduction(+:ddot)

for(i=0; i<100; i++) {

ddot+= a[i]*b[i];

}

リダクション演算は、データを足し込んでいく演算。

良く用いられるが、並列実行は、このsub-directiveを使わないと

難しい

16 of 25

組み込み関数

  • omp_get_num_threads();
    • 並列実行されるスレッド数を返す。
  • omp_get_thread_num();
    • 自分のスレッド番号を返す。
  • omp_get_max_threads();
    • 並列実行可能な最大スレッド数を返す
  • 使い方

#include <omp.h>

int nth, myid;

nth = omp_get_num_threads();

myid = omp_get_thread_num();

17 of 25

時間を計る: omp_get_wtime();

#include <omp.h>

double ts, te;

ts = omp_get_wtime();

実行

te = omp_get_wtime();

printf(“time[sec]:%lf\n”,te-ts);

18 of 25

他のpragma

  • single:

#pragma omp single

{ blocks….. }

指定されたブロック内の文を単一スレッドに割り当てる

  • master:

#pragma omp master

{ blocks..... }

指定されたブロック内の文をマスタースレッドに割り当てる。

19 of 25

OpenMPを使ってみる

  • ITCにログインする
    • windows 10を使っている場合
    • コマンドプロンプトをオープン

ssh login_name@XXXX.educ.cc.keio.ac.jp

https://keio.box.com/s/zd3i2rhx0254bkqms7ky5lq5jbojy2yu

自分の学籍番号に割り当てられたマシンにログインしてください

  • 演習資料を取ってくる

20 of 25

コンパイルと実行

gcc –fopenmp hello.c –o hello

./hello

Hello OpenMP world from 2 of 8

….

ここではスレッド数は8に設定されている。

これは、環境変数OMP_NUM_THREADS をコマンドラインで設定することで変更できる。

export OMP_NUM_THREADS=6

./reduct

じっさいのコア数を超える設定も可能だが速くならない

21 of 25

例題プログラムreduct4k.c

  • 乱数で作った配列aとbの積を計算してcに入れる
  • このcの要素の全てを足してsumに入れる(リダクション演算)

  • extport OMP_NUM_THREADS=xにより、スレッド数を1,2,3,4,6,8に設定して実行し、実行時間を計測してみよ。

22 of 25

演習 CG法

  • 共役勾配法は、大規模な連立一次方程式の反復 解法
  • 行列は正定値対称でないと解けないが、一定回数の反復で収束するという特徴がある
  • cg.cにpragmaを挿入し、スレッド数を1,2,4に 変化させて時間を計測せよ
  • 提出物は、pragmaを挿入したプログラムと実行時間
  • 提出はkeio.jpまで、期限は6月2日

23 of 25

演習で困ったら

  • ITCにアカウントがない
    • https://id-info.itc.keio.ac.jp
    • アクティベイトには時間が掛かるので注意!
  • ITCにログインできない
  • 演習資料が取ってこれない
  • エディタが使えない
    • vim

https://uguisu.skr.jp/Windows/vi.html など

    • emacs

windowは開かないが同様に使える

https://uguisu.skr.jp/Windows/emacs.htmlなど

  • ITCからのデータの転送

https://www.st.itc.keio.ac.jp/ja/com_remote_winscp_st.html

24 of 25

マシンの割り当て

J科3年

https://keio.box.com/s/zd3i2rhx0254bkqms7ky5lq5jbojy2yu

自分の学籍番号に割り当てられたマシンにログインしてください

25 of 25

まとめ

  • 集中共有メモリ型並列計算機は、PC、タブレット、スマフォに広く使われる
  • メモリの共有方法、キャッシュの実現手法が鍵となる
  • 共有メモリを用いた同期、データ交換は本当は結構難しい
  • OpenMPで簡単に並列化が可能