共有メモリマシン 上での 並列計算プログラミング

57
共共共共共共共共共共共 共共共共共共共共共共共 共共共共

Upload: karik

Post on 20-Jan-2016

38 views

Category:

Documents


0 download

DESCRIPTION

共有メモリマシン 上での 並列計算プログラミング. 金田憲二. 背景. 速く計算ができると色々うれしいはず 一 つ一つのプロセッサはまだまだ遅い 並列に計算することで高速化 1 個のプロセッサで 1000 時間かかる計算を、 1000 個のプロセッサを使って 1 時間で !!!. どうやって並列計算をするのか. 並列計算機を手に入れなければいけない プログラムを記述しなければいけない ※ 当然、実現したい計算の種類によって 最適な手段は異なる. 並列計算機の種類. 共有メモリマシン 例) SunFire15K クラスタ - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 共有メモリマシン 上での 並列計算プログラミング

共有メモリマシン上での並列計算プログラミング

金田憲二

Page 2: 共有メモリマシン 上での 並列計算プログラミング

背景 速く計算ができると色々うれしいはず 一つ一つのプロセッサはまだまだ遅い

並列に計算することで高速化 1 個のプロセッサで 1000 時間かかる計算

を、 1000 個のプロセッサを使って 1 時間で !!!

Page 3: 共有メモリマシン 上での 並列計算プログラミング

どうやって並列計算をするのか 並列計算機を手に入れなければいけな

い プログラムを記述しなければいけない※ 当然、実現したい計算の種類によって

最適な手段は異なる

Page 4: 共有メモリマシン 上での 並列計算プログラミング

並列計算機の種類 共有メモリマシン

例) SunFire15K

クラスタ ネットワークでつながった数百~数千台の計算

機例) IBM BladeCenter例) Sun V210 x 128

Page 5: 共有メモリマシン 上での 並列計算プログラミング

並列計算を記述する方法 普通の言語

例) C/Java + スレッド / 通信ライブラリ とても大変

自動並列化コンパイラ ユーザは並列計算を意識しないで済む 性能などの面で問題がある

並列プログラミング言語例) Cilk 、 Linda 、 KLIC 、 Stackthreads 、… 簡便に高性能な並列計算を実現可能

Page 6: 共有メモリマシン 上での 並列計算プログラミング

今回取りあげるのは Cilk 言語

90 年代後半に MIT で研究・開発 C 言語にいくつかのキーワードを追加 共有メモリマシン上で動作 再帰関数などは結構簡単に並列化

例)チェスの次手の探索

Page 7: 共有メモリマシン 上での 並列計算プログラミング

発表の概要~ Cilk 言語のチュートリアル~ フィボナッチの並列化 言語の詳細 実装の概要

Page 8: 共有メモリマシン 上での 並列計算プログラミング

フィボナッチの並列化

Page 9: 共有メモリマシン 上での 並列計算プログラミング

フィボナッチ数を計算するC プログラム

#include <stdlib.h>

#include <stdio.h>

int fib (int n) {

if (n<2) return (n)

int x, y;

x = fib (n-1);

y = fib (n-2);

return (x+y);

}

int main (int args, char *argv[]) {

int n, result;

n = atoi(argv[1]);

result = fib (n);

printf(“Result: %d\n”, result);

return 0;

}

Page 10: 共有メモリマシン 上での 並列計算プログラミング

並列に計算できる箇所は?

fib (6);

fib (5);

fib (4);

fib (3);

fib (2);

fib (4);

fib (3);

fib (3);

fib (2);

fib (1);

fib (0);

fib (2);

fib (1);

fib (2);

fib (1);

Page 11: 共有メモリマシン 上での 並列計算プログラミング

並列に計算できる箇所は?#include <stdlib.h>

#include <stdio.h>

int fib (int n) {

if (n<2) return (n)

int x, y;

x = fib (n-1);

y = fib (n-2);

return (x+y);

}

int main (int args, char *argv[]) {

int n, result;

n = atoi(argv[1]);

result = fib (n);

printf(“Result: %d\n”, result);

return 0;

}

この 2 つの関数の呼び出しは

並列に実行できる

Page 12: 共有メモリマシン 上での 並列計算プログラミング

Cilk で記述された並列フィボナッチ

#include <stdlib.h>

#include <stdio.h>

#include <cilk.h>

cilk int fib (int n) {

if (n<2) return (n)

else {

int x, y;

x = spawn fib (n-1);

y = spawn fib (n-2);

sync;

return (x+y); } }

cilk int main (int args, char *argv[]) {

int n, result;

n = atoi(argv[1]);

result = spawn fib (n);

sync;

printf(“Result: %d\n”, result);

return 0;

}

Page 13: 共有メモリマシン 上での 並列計算プログラミング

プログラム中に現れるキーワード cilk spawn sync

Page 14: 共有メモリマシン 上での 並列計算プログラミング

cilk spawn や sync を呼び出す関数の先

頭につける識別子

cilk int f() {

}

※ 以降この識別子のついた関数を cilk procedure と呼ぶ

Page 15: 共有メモリマシン 上での 並列計算プログラミング

spawn

並列関数呼び出し 関数の終了を待たずに呼び出し元が実行を

続ける

spawn f (x);

g ();

f (x) の終了を待たずに g () も実行する

Page 16: 共有メモリマシン 上での 並列計算プログラミング

sync

spawn した関数の終了を待つ

y = spawn f (x);

sync;

printf (“%d”, y);

f (x) の終了を待つ

Page 17: 共有メモリマシン 上での 並列計算プログラミング

コンパイル コマンド名: cilk

gcc と同じコンパイルオプションが使える$ cilk -g -Wall -O2 fib.cilk -o cilk

$ cilk filename

Page 18: 共有メモリマシン 上での 並列計算プログラミング

実行 --nproc で計算機のプロセッサ数を指定

例) 64 プロセッサ上での fib (32) の計算$ ./fib --nproc 64 32

※fib (32) の計算は SunFire 15K 上で   約 55 倍のスピードアップ

$ filename --nproc n args

Page 19: 共有メモリマシン 上での 並列計算プログラミング

プロファイリング (1/2)

以下のオプションをつけてコンパイル --cilk-profile --cilk-critical-path

以下のオプションをつけて実行 --stats level

Page 20: 共有メモリマシン 上での 並列計算プログラミング

プロファイリング (2/2)$ cilk -cilk-profile -cilk-critical-path -O2 fib.cilk -o fib

$ ./fib --nproc 4 --stats 1 30

Result: 832040

RUNTIME SYSTEM STATISTICS

Wall-clock running time on 4 processors: 2.593270 s

Total work = 10.341069 s

Total work (accumulated) = 7.746886 s

Critical path = 779.588000 us

Parallelism = 9937.154003

Page 21: 共有メモリマシン 上での 並列計算プログラミング

言語の詳細

Page 22: 共有メモリマシン 上での 並列計算プログラミング

言語の詳細 Storage allocation Locking Inlets Aborting Timer (プログラム例: n-queens )

Page 23: 共有メモリマシン 上での 並列計算プログラミング

Storage Allocation (1/2)

Stack memory への割り当て Cilk procedure 内では

C 関数内では

※ 関数が return する時に自動的に開放される

ptr = Cilk_alloca(size) ;

ptr = alloca(size) ;

Page 24: 共有メモリマシン 上での 並列計算プログラミング

Storage Allocation (2/2)

Heap memory への割り当て 通常の C と同じ

ptr = malloc(size) ;

free(ptr) ;

Page 25: 共有メモリマシン 上での 並列計算プログラミング

Locking

Cilk は相互排他ロックを提供する スレッド間で共有されるデータへの

atomic なアクセスを可能にする

Page 26: 共有メモリマシン 上での 並列計算プログラミング

Data race の例 (1/2)

cilk int foo (void) {

int x = 0;

spawn bar(&x);

x = x + 1;

sync;

return (x);

}

cilk void bar (int *px)

{

*px = *px + 1;

return;

}

foo() が 2 を返す(ことを意図した)プログラム

Page 27: 共有メモリマシン 上での 並列計算プログラミング

Data race の例 (2/2) 実行によっては、値が正しく更新されない

cilk int foo (void) {

int x = 0;

spawn bar(&x);

x = x + 1;

sync;

return (x);

}

cilk void bar (int *px)

{

*px = *px + 1;

return;

}

(1) x を read (= 0)

(4) x へ write (= 1)

(2) x を read (= 0)

(3) x へ write (= 1)

(5) 1 をreturn

Page 28: 共有メモリマシン 上での 並列計算プログラミング

API (1/2)

ロックを初期化する関数

ロックを取得する関数

ロックを開放する関数

Cilk_lockvar

Cilk_lock_init( l )

Cilk_lock ( l )

Cilk_unlock( l )

Page 29: 共有メモリマシン 上での 並列計算プログラミング

API (2/2)

ロックを取得できるのは同時に一つの  スレッド

ロックを取得できなかったスレッドは           そのロックが開放されるまで待機

Page 30: 共有メモリマシン 上での 並列計算プログラミング

プログラム例 1#include <cilk-lib.h>

Cilk_lockvar mylock;

{

Cilk_lock_init(mylock);

Cilk_lock(mylock);

/* critical section

(atomic に実行したいコード ) */

Cilk_unlock(mylock);

}

Page 31: 共有メモリマシン 上での 並列計算プログラミング

プログラム例 2#include <cilk-lib.h>

Cilk_lockvar mylock;

cilk int foo (void) {

int x = 0;

Cilk_lock_init(mylock);

spawn bar(&x);

Cilk_lock(mylock);

x = x + 1;

Cilk_unlock(mylock);

sync;

return (x); }

cilk void bar (int *px)

{

Cilk_lock (mylock);

*px = *px + 1;

Cilk_unlock(mylock);

return;

}

Page 32: 共有メモリマシン 上での 並列計算プログラミング

Inlets

spawn の返り値に使える操作というものが制限されている

そのために spawn の返り値を操作するための特殊な機構

Page 33: 共有メモリマシン 上での 並列計算プログラミング

spawn に対する制限 (1/2)

spawn の返り値に対して許されている操作は

=    *=   /= %= += -=

&= ^= |= <<= >>= のみ y += spawn f (x);

Page 34: 共有メモリマシン 上での 並列計算プログラミング

spawn に対する制限 (2/2)

以下のような操作は許されていないz = spawn f (x) + spawn g (y)

ただし h は C の関数h (spawn f (x));

Page 35: 共有メモリマシン 上での 並列計算プログラミング

Inlet spawn の返り値を処理する特殊な関数

Cilk procedure 内で定義される spawn の返り値を渡すことができる

cilk int f (int x) {

inlet int g (int y) {

}

z = g (spawn h())

}

Page 36: 共有メモリマシン 上での 並列計算プログラミング

プログラム例cilk int fib (int n) {

int x = 0;

inlet void summer (int result) {

x += result;

}

if (n < 2) return n;

summer (spawn fib (n-1));

summer (spawn fib (n-2));

sync;

return (x);

}

Page 37: 共有メモリマシン 上での 並列計算プログラミング

注意点 (1/2)

inlet 中で spawn や sync を呼び出すことはできない

cilk int f (int x) {

inlet int g (int y) {

z = spawn h();

}

z = g (spawn h())

}

Page 38: 共有メモリマシン 上での 並列計算プログラミング

注意点 (2/2)

Implicit atomicity spawn の呼び出したスレッドと同じスレ

ッドが inlet 内を処理するcilk int fib (int n) {

inlet void summer (int result) {

x += result;

}

summer (spawn fib (n-1));

summer (spawn fib (n-2));

}

x へのアクセスはatomic であることが保障されている

Page 39: 共有メモリマシン 上での 並列計算プログラミング

Aborting

spawn した Cilk procedure を中断させる機構 探索の枝狩りなどの目的に使用する

Page 40: 共有メモリマシン 上での 並列計算プログラミング

Abort inlet 内に abort プリミティンブをいれる

cilk int f (int n) {

inlet void g (int x) {

...

abort;

}

}

Page 41: 共有メモリマシン 上での 並列計算プログラミング

プログラム例cilk void search(int n) {

inlet void catch() {

if ( 解が発見された ) { abort; }

}

for (x in 探索空間 ) {

catch (spawn search (x));

}

}

Page 42: 共有メモリマシン 上での 並列計算プログラミング

注意点 abort が呼ばれた時点でまだ spawn

されていないタスクは中断されない

cilk void foo(int n) {

inlet void bar() {

abort;

}

bar (spawn baz(17));

spawn baz(28);

}

(3) abort を呼び出す

(1) baz(17) をspawn

(4) baz(28) をspawn

(2) baz(17) が終了

Page 43: 共有メモリマシン 上での 並列計算プログラミング

Timer

wall-clock time を返す関数

Cilk_time を秒に変換する関数

Cilk_time

t = Cilk_get_wall_time()

sec = Cilk_time_sec(t)

Page 44: 共有メモリマシン 上での 並列計算プログラミング

プログラム例: n-queens (1/8)

N×N のチェスボード上で以下の条件を満たす N 個の Queen の配置を求める[ 条件 ]Queen 同士は互いを取れない

Q

Q

Q

Q

Q

Q

Q

Q

Page 45: 共有メモリマシン 上での 並列計算プログラミング

プログラム例: n-queens (2/8)

#include <stdlib.h>#include <stdio.h>#include <string.h>#include <cilk.h>#include <cilk-lib.h>

Page 46: 共有メモリマシン 上での 並列計算プログラミング

プログラム例: n-queens (3/8)

int safe(char *config, int i, int j) { int r, s; for (r = 0; r < i; r++) { s = config[r]; if (j==s || i-r==j-s || i-r==s-j) { return 0; } } return 1;}

Page 47: 共有メモリマシン 上での 並列計算プログラミング

プログラム例: n-queens (4/8)

cilk char *nqueens(char *config, int n, int i) { char *new_config; char *done = NULL; int j;

inlet void catch(char *res) { if (res != NULL) { if (done == NULL) { done = res; } abort; } }

Page 48: 共有メモリマシン 上での 並列計算プログラミング

プログラム例: n-queens (5/8)

if (i==n) { char *result;

/* put this good solution in heap, and return a pointer to it */ result = malloc(n*sizeof(char)); memcpy(result, config, n*sizeof(char)); return result; }

Page 49: 共有メモリマシン 上での 並列計算プログラミング

プログラム例: n-queens (6/8)

/* try each possible position for queen <i> */ for (j=0; j<n; j++) { new_config = Cilk_alloca((i + 1) * sizeof(char)); memcpy(new_config, config, i*sizeof(char)); if (safe(new_config, i, j)) { new_config[i] = j; catch(spawn nqueens(new_config, n, i+1)); } if (done != NULL) { break; } } sync;

return done; }…

Page 50: 共有メモリマシン 上での 並列計算プログラミング

プログラム例: n-queens (7/8)

cilk int main(int argc, char *argv[]) { int n; char *config; char *result;

n = atoi(argv[1]); config = Cilk_alloca(n*sizeof(char));

result = spawn nqueens(config, n, 0); sync;

Page 51: 共有メモリマシン 上での 並列計算プログラミング

プログラム例: n-queens (8/8)

if (result != NULL) { int i; printf("Solution: "); for (i=0; i<n; i++) { printf(“%2d\n”, result[i]); } } else { printf(“No solutions!\n”); } return 0;}

Page 52: 共有メモリマシン 上での 並列計算プログラミング

実装の概要

Page 53: 共有メモリマシン 上での 並列計算プログラミング

実装の概要 work-stealing による負荷分散

idle なプロセッサはランダムに選んだプロセッサからタスクを盗む

Page 54: 共有メモリマシン 上での 並列計算プログラミング

実装の概要 work-stealing による負荷分散

idle なプロセッサはランダムに選んだプロセッサからタスクを盗む

Page 55: 共有メモリマシン 上での 並列計算プログラミング

実装の概要 work-stealing による負荷分散

idle なプロセッサはランダムに選んだプロセッサからタスクを盗む

Page 56: 共有メモリマシン 上での 並列計算プログラミング

参考文献 Cilk 5.3.2 Reference Manual

Supercomputing Technologies Group MIT Laboratory for Computer Science

http://supertech.lcs.mit.edu/cilk 2001

Page 57: 共有メモリマシン 上での 並列計算プログラミング

コンパイル方法

foo.cilkcilk2c

Cilk runtime system

gcc ldfoo.c foo.o foo