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

Slides:



Advertisements
Similar presentations
プロセスの生成とコマンドの実行 プロセスの生成とコマンドの実行 プロセス生成のシステムコール プロセス生成のシステムコール プロセス生成のプログラム例 プロセス生成のプログラム例 プログラム実行のシステムコール プログラム実行のシステムコール 子プロセスの終了を待つシステムコール 子プロセスの終了を待つシステムコール.
Advertisements

連続系アルゴリズム演習 第2回 OpenMPによる課題.
クラスタの構成技術と クラスタによる並列処理
情報基礎演習B 後半第5回 担当 岩村 TA 谷本君.
数理情報工学演習第一C プログラミング演習 (第3回 ) 2014/04/21
システムプログラミング 第5回 情報工学科 篠埜 功 ヒアドキュメント レポート課題 main関数の引数 usageメッセージ
第2回ネットワークプログラミング 中村 修.
プログラミング論 I 関数の再帰呼び出し
システムプログラミング 第11回 シグナル 情報工学科  篠埜 功.
OSとコマンド OS:コンピュータを使うための基本プログラム コマンド:OS上で使用できる命令 OS本体であるカーネルの内部コマンド
多数の遊休PC上での 分散ゲーム木探索 導入 ゲーム木探索 ⇒遊休PCを利用して高速化 例)コンピュータ将棋における次手の計算
プログラミング論 II 電卓,逆ポーランド記法電卓
プログラミング演習Ⅰ 課題2 10進数と2進数 2回目.
システムプログラミング 第11回 シグナル 情報工学科  篠埜 功.
コンパイラの解析 (2) GCJのデータ構造 - 1.
データ構造とプログラミング技法 (第2回) ー線形構造ー.
コンパイラの解析 (4) 例外処理.
プログラミング2 関数
プログラミング論 ファイル入出力
データ構造とアルゴリズム (第2回) ー線形構造ー.
関数の定義.
第10回関数 Ⅱ (ローカル変数とスコープ).
マルチスレッド処理 マルチプロセス処理について
プログラミング 4 記憶の割り付け.
2005年度 データ構造とアルゴリズム 第3回 「C言語の復習:再帰的データ構造」
プログラミング2 関数の再帰呼び出し
知能情報工学演習I 第12回(後半第6回) 課題の回答
メモリの準備 メモリには、その準備の方法で2種類ある。 静的変数: コンパイル時にすでにメモリのサイズがわかっているもの。 普通の変数宣言
プログラミング入門2 第11回 情報工学科 篠埜 功.
プログラミング入門2 第11回 情報工学科 篠埜 功.
復習 前回の関数のまとめ(1) 関数はmain()関数または他の関数から呼び出されて実行される.
高度プログラミング演習 (08).
プログラミング論 ファイル入出力
演習1の解答例の解説 2006年11月8日 海谷 治彦.
関数の再帰呼び出しとは ハノイの塔 リダイレクト レポート課題
岩村雅一 知能情報工学演習I 第12回(C言語第6回) 岩村雅一
配列変数とポインタ 静的確保と動的確保 ポインタ配列 2次元配列 時間計測 第1回レポートの課題
演習0 func0, func1, func2を作成せよ. main()関数の中で,func0()を呼び出しを実行せよ.
プログラミング言語論 第六回 理工学部 情報システム工学科 新田直也.
B演習(言語処理系演習)第2回 田浦.
Virtualizing a Multiprocessor Machine on a Network of Computers
プログラミング基礎a 第6回 C言語によるプログラミング入門 配列と文字列(その2)
15.1 文字列処理の基本 15.2 文字列処理用ライブラリ関数
アルゴリズムとプログラミング (Algorithms and Programming)
マイグレーションを支援する分散集合オブジェクト
千代浩司 高エネルギー加速器研究機構 素粒子原子核研究所
千代浩司 高エネルギー加速器研究機構 素粒子原子核研究所
プログラミング入門2 第6回 関数 情報工学科 篠埜 功.
「マイグレーションを支援する分散集合オブジェクト」
11.1 標準ライブラリ関数 11.2 関数呼び出しのオーバーヘッド 11.3 大域変数 11.4 プロトタイプ宣言 11.5 関数引数
ネットワーク・プログラミング デバイスドライバと環境変数.
第5回 プログラミングⅡ 第5回
モジュール分割.
Cilk-NOW 米澤研究室 金田憲二 “Adaptive and Reliable Parallel Computing on Networks of Workstations” Robert D. Blumofe (Univ. of Texas) Philip A. Lisiecki (MIT)
プログラミング 4 文字列.
岩村雅一 知能情報工学演習I 第12回(後半第6回) 岩村雅一
プログラミング2 関数の再帰呼び出し
プログラミング入門2 第6回 関数 情報工学科 篠埜 功.
11: 動的メモリ確保 C プログラミング入門 基幹2 (月4) Linux にログインし、以下の講義ページ を開いておくこと
プログラミング演習I 2003年6月11日(第9回) 木村巌.
システムプログラミング 第11回 シグナル 情報工学科  篠埜 功.
情報処理Ⅱ 2005年11月25日(金).
全体ミーティング(9/15) 村田雅之.
プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。)
15.1 文字列処理の基本 15.2 文字列処理用ライブラリ関数
情報処理Ⅱ 小テスト 2005年2月1日(火).
千代浩司 高エネルギー加速器研究機構 素粒子原子核研究所
計算技術研究会 第5回 C言語勉強会 関数(function)を使う
プログラミング演習I 補講用課題
12: コマンドライン引数 C プログラミング入門 基幹2 (月4) Linux にログインし、以下の講義ページ を開いておくこと
Presentation transcript:

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

背景 速く計算ができると色々うれしいはず 一つ一つのプロセッサはまだまだ遅い 並列に計算することで高速化 1個のプロセッサで1000時間かかる計算を、1000個のプロセッサを使って1時間で!!!

どうやって並列計算をするのか 並列計算機を手に入れなければいけない プログラムを記述しなければいけない ※当然、実現したい計算の種類によって 最適な手段は異なる

並列計算機の種類 共有メモリマシン クラスタ 例)SunFire15K ネットワークでつながった数百~数千台の計算機 例)IBM BladeCenter 例)Sun V210 x 128

並列計算を記述する方法 普通の言語 自動並列化コンパイラ 並列プログラミング言語 例)C/Java + スレッド/通信ライブラリ とても大変 ユーザは並列計算を意識しないで済む 性能などの面で問題がある 並列プログラミング言語 例)Cilk、 Linda、KLIC、Stackthreads、… 簡便に高性能な並列計算を実現可能

今回取りあげるのは Cilk言語 90年代後半にMITで研究・開発 C言語にいくつかのキーワードを追加 共有メモリマシン上で動作 再帰関数などは結構簡単に並列化 例)チェスの次手の探索

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

フィボナッチの並列化

フィボナッチ数を計算する 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; }

並列に計算できる箇所は? fib (3); fib (2); fib (4); fib (3); fib (5); fib (4); データ依存がない fib (1); fib (0);

並列に計算できる箇所は? この2つの関数の呼び出しは 並列に実行できる #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つの関数の呼び出しは 並列に実行できる

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; }

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

cilk spawnやsyncを呼び出す関数の先頭につける識別子 cilk int f() { … } ※以降この識別子のついた関数をcilk procedureと呼ぶ

f (x)の終了を待たずにg ()も実行する spawn 並列関数呼び出し 関数の終了を待たずに呼び出し元が実行を続ける spawn f (x); g (); f (x)の終了を待たずにg ()も実行する

sync spawnした関数の終了を待つ y = spawn f (x); … sync; printf (“%d”, y);

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

実行 --nprocで計算機のプロセッサ数を指定 例)64プロセッサ上でのfib (32)の計算 $ filename --nproc n args $ ./fib --nproc 64 32 ※fib (32)の計算はSunFire 15K上で   約55倍のスピードアップ

プロファイリング (1/2) 以下のオプションをつけてコンパイル 以下のオプションをつけて実行 --cilk-profile --cilk-critical-path 以下のオプションをつけて実行 --stats level

プロファイリング (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

言語の詳細

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

Storage Allocation (1/2) Stack memoryへの割り当て Cilk procedure内では C関数内では ※関数がreturnする時に自動的に開放される ptr = Cilk_alloca(size); ptr = alloca(size);

Storage Allocation (2/2) Heap memoryへの割り当て 通常のCと同じ ptr = malloc(size); free(ptr);

Locking Cilkは相互排他ロックを提供する スレッド間で共有されるデータへのatomicなアクセスを可能にする

Data raceの例 (1/2) foo()が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; }

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; } (2) xをread (= 0) (1) xをread (= 0) (3) xへwrite (= 1) (4) xへwrite (= 1) (5) 1をreturn

API (1/2) 型 ロックを初期化する関数 ロックを取得する関数 ロックを開放する関数 Cilk_lockvar Cilk_lock_init(l) Cilk_lock (l) Cilk_unlock(l)

API (2/2) ロックを取得できるのは同時に一つの  スレッド ロックを取得できなかったスレッドは           そのロックが開放されるまで待機

プログラム例1 #include <cilk-lib.h> Cilk_lockvar mylock; { Cilk_lock_init(mylock); Cilk_lock(mylock); /* critical section (atomicに実行したいコード) */ Cilk_unlock(mylock); }

プログラム例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; }

Inlets spawnの返り値に使える操作というものが制限されている そのためにspawnの返り値を操作するための特殊な機構

spawnに対する制限 (1/2) spawnの返り値に対して許されている操作は = *= /= %= += -= =    *=   /= %= += -= &= ^= |= <<= >>=  のみ y += spawn f (x); 旨い

spawnに対する制限 (2/2) 以下のような操作は許されていない z = spawn f (x) + spawn g (y) h (spawn f (x)); ただしhはCの関数

Inlet spawnの返り値を処理する特殊な関数 Cilk procedure内で定義される spawnの返り値を渡すことができる cilk int f (int x) { inlet int g (int y) { … } z = g (spawn h())

プログラム例 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);

注意点 (1/2) inlet中でspawnやsyncを呼び出すことはできない cilk int f (int x) { inlet int g (int y) { z = spawn h(); } z = g (spawn h())

注意点 (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であることが保障されている

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

Abort inlet内にabortプリミティンブをいれる cilk int f (int n) { inlet void g (int x) { ... abort; } …

プログラム例 cilk void search(int n) { inlet void catch() { if (解が発見された) { abort; } … } for (x in 探索空間) { catch (spawn search (x));

注意点 abortが呼ばれた時点でまだspawnされていないタスクは中断されない (3) abortを呼び出す cilk void foo(int n) { inlet void bar() { abort; } bar (spawn baz(17)); spawn baz(28); (3) abortを呼び出す (1) baz(17)をspawn (2) baz(17)が終了 (4) baz(28)をspawn

Timer 型 wall-clock timeを返す関数 Cilk_timeを秒に変換する関数 Cilk_time t = Cilk_get_wall_time() sec = Cilk_time_sec(t)

プログラム例:n-queens (1/8) N×Nのチェスボード上で以下の条件を満たすN個のQueenの配置を求める

プログラム例:n-queens (2/8) #include <stdlib.h> #include <stdio.h> #include <string.h> #include <cilk.h> #include <cilk-lib.h> …

プログラム例: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;

プログラム例: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; }

プログラム例: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; }

プログラム例: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; }

プログラム例: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;

プログラム例: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;

実装の概要

実装の概要 work-stealingによる負荷分散 idleなプロセッサはランダムに選んだプロセッサからタスクを盗む

実装の概要 work-stealingによる負荷分散 idleなプロセッサはランダムに選んだプロセッサからタスクを盗む

実装の概要 work-stealingによる負荷分散 idleなプロセッサはランダムに選んだプロセッサからタスクを盗む

参考文献 Cilk 5.3.2 Reference Manual Supercomputing Technologies Group MIT Laboratory for Computer Science http://supertech.lcs.mit.edu/cilk 2001

コンパイル方法 foo.cilk foo.c foo.o foo cilk2c gcc ld Cilk runtime system