C include stdlib h int main int args
フィボナッチ数を計算する Cプログラム #include <stdlib. h> int main (int args, char *argv[]) { #include <stdio. h> int n, result; int fib (int n) { n = atoi(argv[1]); if (n<2) return (n) result = fib (n); int x, y; printf(“Result: %dn”, result); x = fib (n-1); return 0; y = fib (n-2); return (x+y); } }
並列に計算できる箇所は? fib (4); fib (5); fib (3); fib (6); fib (3); fib (4); fib (2); fib (3); fib (2); fib (1); fib (0);
並列に計算できる箇所は? #include <stdlib. h> int main (int args, char *argv[]) { #include <stdio. h> int n, result; int fib (int n) { n = atoi(argv[1]); if (n<2) return (n) result = fib (n); int x, y; printf(“Result: %dn”, result); x = fib (n-1); return 0; y = fib (n-2); return (x+y); } } この 2つの関数の呼び出しは 並列に実行できる
Cilkで記述された 並列フィボナッチ #include <stdlib. h> cilk int main (int args, char *argv[]) { #include <stdio. h> int n, result; #include <cilk. h> n = atoi(argv[1]); cilk int fib (int n) { result = spawn fib (n); if (n<2) return (n) sync; else { printf(“Result: %dn”, result); int x, y; x = spawn fib (n-1); y = spawn fib (n-2); sync; return (x+y); } } return 0; }
プロファイリング (2/2) $ cilk -cilk-profile -cilk-critical-path -O 2 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
言語の詳細 n n n Storage allocation Locking Inlets Aborting Timer (プログラム例:n-queens)
Storage Allocation (1/2) n Stack memoryへの割り当て n Cilk procedure内では n ptr = Cilk_alloca(size); C関数内では ptr = alloca(size); ※関数がreturnする時に自動的に開放される
Storage Allocation (2/2) n Heap memoryへの割り当て n 通常のCと同じ ptr = malloc(size); free(ptr);
Data raceの例 (1/2) n foo()が2を返す(ことを意図した)プログラム cilk int foo (void) { int x = 0; { spawn bar(&x); *px = *px + 1; x = x + 1; return; sync; return (x); } cilk void bar (int *px) }
Data raceの例 (2/2) n 実行によっては、値が正しく更新されない cilk int foo (void) { int x = 0; (1) xをread (= 0) spawn bar(&x); x = x + 1; sync; (4) xへwrite (= 1) return (x); } cilk void bar (int *px) (2) xをread (= 0) { *px = *px + 1; return; (3) xへwrite (= 1) } (5) 1をreturn
プログラム例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 void bar (int *px) cilk int foo (void) { { int x = 0; Cilk_lock (mylock); Cilk_lock_init(mylock); *px = *px + 1; spawn bar(&x); Cilk_unlock(mylock); Cilk_lock(mylock); return; x = x + 1; Cilk_unlock(mylock); sync; return (x); } }
プログラム例 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) n inlet中でspawnやsyncを呼び出すこと はできない cilk int f (int x) { inlet int g (int y) { z = spawn h(); } z = g (spawn h()) }
注意点 (2/2) n Implicit atomicity n spawnの呼び出したスレッドと同じスレッドが inlet内を処理する cilk int fib (int n) { inlet void summer (int result) { x += result; } xへのアクセスはatomicで あることが保障されている summer (spawn fib (n-1)); summer (spawn fib (n-2)); }
Abort n 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)); } }
注意点 n abortが呼ばれた時点でまだspawnされ ていないタスクは中断されない cilk void foo(int n) { (3) abortを呼び出す inlet void bar() { abort; } bar (spawn baz(17)); spawn baz(28); } (1) baz(17)をspawn (2) baz(17)が終了 (4) baz(28)をspawn
Timer n 型 Cilk_time n wall-clock timeを返す関数 t = Cilk_get_wall_time() n Cilk_timeを秒に変換する関数 sec = Cilk_time_sec(t)
プログラム例:n-queens (2/8) #include <stdlib. h> #include <stdio. h> #include <string. 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, 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(“%2 dn”, result[i]); } } else { printf(“No solutions!n”); } return 0;
参考文献 n Cilk 5. 3. 2 Reference Manual n n n Supercomputing Technologies Group MIT Laboratory for Computer Science http: //supertech. lcs. mit. edu/cilk 2001
コンパイル方法 foo. cilk 2 c foo. c gcc foo. o ld foo Cilk runtime system
- Slides: 57