Skip to content

Commit dd32060

Browse files
update README and add more resources
1 parent 5deb4ba commit dd32060

File tree

9 files changed

+289
-2
lines changed

9 files changed

+289
-2
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,6 @@
3030
*.exe
3131
*.out
3232
*.app
33+
34+
# Chapel install
35+
*chapel-2.2.0MC

6-pgas-chapel/demo/hello_datapar.chpl

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Data-parallel hello world
2+
3+
/* This program uses Chapel's data parallel features to create a
4+
parallel hello world program that utilizes multiple cores on a
5+
single `locale` (compute node).
6+
*/
7+
8+
9+
//
10+
// The following `configuration constant` indicates the number of
11+
// messages to print out. The default can be overridden on the
12+
// command-line (e.g., ``./hello --numMessages=1000000``).
13+
//
14+
config const numMessages = 30;
15+
16+
//
17+
// Next, we use a data-parallel `forall-loop` to iterate over a
18+
// `range` representing the number of messages to print. By default,
19+
// forall-loops will typically be executed cooperatively by a number
20+
// of tasks proportional to the hardware parallelism on which the loop
21+
// is running. Ranges like ``1..numMessages`` are always local to the
22+
// current task's locale, so this forall-loop will execute using the
23+
// number of local processing units or cores.
24+
//
25+
// Because the messages are printed within a parallel loop, they may
26+
// be displayed in any order. The `writeln()` procedure protects
27+
// against finer-grained interleaving of the messages themselves.
28+
//
29+
forall msg in 1..numMessages do
30+
writeln("Hello, world! (from iteration ", msg, " of ", numMessages, ")");

6-pgas-chapel/demo/hello_module.chpl

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// "Production-grade" hello world
2+
3+
/* This program is conceptually very similar to :ref:`hello.chpl
4+
<primers-hello>`, but it uses a more structured programming style,
5+
explicitly defining a module, a configuration constant, and a
6+
main() procedure.
7+
*/
8+
9+
//
10+
// The following statement declares a module named 'Hello'. If a
11+
// source file contains no module declarations, the filename minus its
12+
// ``.chpl`` extension serves as the module name for the code it
13+
// contains. Thus, 'hello' would be the automatic module name for the
14+
// previous :ref:`hello.chpl <primers-hello>` example.
15+
//
16+
module Hello {
17+
18+
//
19+
// This next statement declares a `configuration constant` named
20+
// `message`. The type is inferred to be a string since the
21+
// initializing expression is a string literal. Users may override
22+
// the default values of configuration constants and variables on the
23+
// executable's command-line. For example, we could change the
24+
// default message for a given run using the command line: ``./hello
25+
// --message="hiya!"``.
26+
//
27+
config const message = "Hello, world!";
28+
29+
30+
// Any top-level code in a module is executed as part of the module's
31+
// initialization when the program begins executing. Thus, in the
32+
// previous one-line :ref:`hello.chpl <primers-hello>`, the presence
33+
// of a `writeln()` at the file scope formed the implicit `hello`
34+
// module's initialization and would be executed at program startup.
35+
// Since there was no explicit `main()` function or any other
36+
// top-level code, that's all that the program would do.
37+
38+
39+
//
40+
// In this program, we define an entry point for the program by
41+
// defining a procedure named `main()`. This will be invoked after
42+
// this module and all the modules it uses are initialized.
43+
//
44+
proc main() {
45+
writeln(message);
46+
}
47+
}

6-pgas-chapel/demo/hello_simple.chpl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// Simple hello world
2+
writeln("Hello, world!"); // print 'Hello, world!' to the console

6-pgas-chapel/demo/hello_taskpar.chpl

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Task-parallel hello world
2+
3+
/* This program uses Chapel's `task parallel` features to express an
4+
explicitly concurrent hello world program that utilizes multiple
5+
cores on a single `locale` (compute node).
6+
*/
7+
8+
9+
//
10+
// First, we specify the number of tasks to create via a `config
11+
// const`. By default, set it to the runtime's estimation of maximum
12+
// parallelism that the current locale ('`here`') is capable of
13+
// executing (``.maxTaskPar``).
14+
//
15+
config const numTasks = here.maxTaskPar;
16+
17+
18+
//
19+
// Next, we create the specified number tasks using a `coforall-loop`.
20+
// This is a parallel loop form that will create a distinct task per
21+
// iteration.
22+
//
23+
// This coforall-loop is iterating over the `range` ``0..#numTasks``
24+
// which represents the first `numTasks` integers starting at 0
25+
// (equivalent to ``0..numTasks-1``). The result will be `numTasks`
26+
// iterations, each of which will be executed as a distinct parallel
27+
// task.
28+
//
29+
// Each iteration prints out a message that is unique based on its
30+
// value of `tid`. Due to the task parallelism, the messages may be
31+
// printed in any order. However, the `writeln()` procedure will
32+
// prevent finer-grained interleaving of the messages themselves.
33+
//
34+
coforall tid in 0..#numTasks do
35+
writeln("Hello, world! (from task ", tid, " of ", numTasks, ")");

6-pgas-chapel/mandelbrot_seq.chpl renamed to 6-pgas-chapel/exercises/mandelbrot.chpl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* Author: Guillaume HELBECQUE (Université du Luxembourg)
3-
* Date: 25/10/2024
3+
* Date: 26/10/2024
44
*
55
* Description:
66
* This sequential program computes a Mandelbrot set of given size and
@@ -92,7 +92,9 @@ proc main() {
9292
compute(im);
9393
timer.stop();
9494

95-
writeln("Serial computational time [s]: ", timer.elapsed());
95+
writeln("Computation of Manderbrot set with ", N, " iterations and ",
96+
height, " x ", width, " resolutions");
97+
writeln("Elapsed time [s]: ", timer.elapsed());
9698

9799
save_image(im);
98100

6-pgas-chapel/exercises/nqueens.chpl

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/*
2+
* Author: Guillaume HELBECQUE (Université du Luxembourg)
3+
* Date: 26/10/2024
4+
*
5+
* Description:
6+
* Sequential backtracking to solve instances of the N-Queens problem in Chapel.
7+
* It serves as a basis for parallel implementations.
8+
*/
9+
10+
use Time;
11+
12+
param INITIAL_CAPACITY = 1024;
13+
param MAX_QUEENS = 20;
14+
15+
config const N = 14;
16+
17+
// pool implementation
18+
record SinglePool {
19+
type eltType;
20+
var dom: domain(1);
21+
var elements: [dom] eltType;
22+
var capacity: int;
23+
var front: int;
24+
var size: int;
25+
26+
proc init(type eltType) {
27+
this.eltType = eltType;
28+
this.dom = {0..#INITIAL_CAPACITY};
29+
this.capacity = INITIAL_CAPACITY;
30+
}
31+
32+
// Insertion to the end of the deque
33+
proc ref pushBack(node: eltType) {
34+
if (this.front + this.size >= this.capacity) {
35+
this.capacity *= 2;
36+
this.dom = {0..#this.capacity};
37+
}
38+
39+
this.elements[this.front + this.size] = node;
40+
this.size += 1;
41+
}
42+
43+
// Removal from the end of the deque
44+
proc ref popBack() {
45+
if (this.size > 0) {
46+
this.size -= 1;
47+
return this.elements[this.front + this.size];
48+
}
49+
50+
var default: eltType;
51+
return default;
52+
}
53+
}
54+
55+
// N-Queens node
56+
record Node {
57+
var depth: uint(8);
58+
var board: MAX_QUEENS*uint(8);
59+
60+
proc init() {};
61+
62+
proc init(const N: int) {
63+
init this;
64+
for i in 0..#N do this.board[i] = i:uint(8);
65+
}
66+
67+
proc init(other: Node) {
68+
this.depth = other.depth;
69+
this.board = other.board;
70+
}
71+
}
72+
73+
// check if placing a queen is safe (i.e., check if all the queens already placed share
74+
// a same diagonal)
75+
proc isSafe(const board, const row, const col)
76+
{
77+
for i in 0..#row {
78+
if (board[i] == col - (row - i) || board[i] == col + (row - i)) {
79+
return false;
80+
}
81+
}
82+
83+
return true;
84+
}
85+
86+
// evaluate a given node (i.e., check its board configuration) and branch it if it is valid
87+
// (i.e., generate its child nodes.)
88+
proc evaluate_and_branch(const parent: Node, ref tree_loc: uint, ref num_sol: uint, ref pool: SinglePool(Node))
89+
{
90+
const depth = parent.depth;
91+
92+
// if the given node is a leaf, then update counter and do nothing
93+
if (depth == N) {
94+
num_sol += 1;
95+
}
96+
// if the given node is not a leaf, then update counter and evaluate/branch it
97+
else {
98+
for j in depth..(N-1) {
99+
if isSafe(parent.board, depth, parent.board[j]) {
100+
var child = new Node(parent);
101+
child.board[depth] <=> child.board[j]; // swap
102+
child.depth += 1;
103+
pool.pushBack(child);
104+
tree_loc += 1;
105+
}
106+
}
107+
}
108+
}
109+
110+
proc main()
111+
{
112+
writeln("Sequential resolution of the ", N, "-Queens instance in Chapel");
113+
114+
// initialization of the root node (the board configuration where no queen is placed)
115+
var root = new Node(N);
116+
117+
// initialization of the pool of nodes (stack -> DFS exploration order)
118+
var pool = new SinglePool(Node);
119+
pool.pushBack(root);
120+
121+
// statistics to check correctness (number of nodes explored and number of solutions found)
122+
var exploredTree: uint = 0;
123+
var exploredSol: uint = 0;
124+
125+
// beginning of the Depth-First tree-Search
126+
var timer: stopwatch;
127+
timer.start();
128+
129+
while pool.size != 0 {
130+
// get a node from the pool
131+
var parent = pool.popBack();
132+
133+
// check the board configuration of the node and branch it if it is valid
134+
evaluate_and_branch(parent, exploredTree, exploredSol, pool);
135+
}
136+
137+
timer.stop();
138+
139+
// outputs
140+
writeln("\nSize of the explored tree: ", exploredTree);
141+
writeln("Number of explored solutions: ", exploredSol);
142+
writeln("Elapsed time: ", timer.elapsed(), " [s]");
143+
144+
return 0;
145+
}

README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,3 +139,26 @@ Suppose you have a shared resources (e.g. a web page) among many readers (e.g. t
139139
### Project Big Graph
140140
141141
The project description is [available here](https://github.com/ptal/parallel-and-grid-computing-uni.lu/tree/main/5-openmp/project/README.md).
142+
143+
## Partitioned Global Address Space (Chapel)
144+
145+
### Mandelbrot set computation (`6-pgas-chapel/mandelbrot_seq.chpl`)
146+
147+
1. Install Chapel on your system using the provided script (it can take some minutes). Command:
148+
```
149+
cd 6-pgas-chapel/
150+
source chapel_install.sh
151+
```
152+
2. Read the introductory file [available here](https://github.com/ptal/parallel-and-grid-computing-uni.lu/tree/main/6-pgas-chapel/exercises/introduction.pdf).
153+
3. Implement a parallel approach where each thread computes a block made of
154+
contiguous lines of the global image. What do you observe in terms of speed-up compared to the sequential version?
155+
4. The goal is to improve the load balancing between threads. Implement a variant of the previous algorithm where each processor computes a block made of alternated lines. More precisely, we will assume that the *k*-th thread (*0 <= k < n*) takes in charge the lines indexed by *k + i n*.
156+
157+
*Hints:*
158+
- *The number of threads `n` can be set in command-line using `CHPL_RT_NUM_THREADS_PER_LOCALE=n`;*
159+
- *Compile using the `--fast` optimization flag: `chpl --fast foo.chpl`;*
160+
- *You can verify that two images are similar using the output of `diff image1 image2`.*
161+
162+
### [Optional⭐] N-Queens
163+
164+
* `6-pgas-chapel/exercises/nqueens.chpl`: Parallelize the N-queens code seen in a previous course using Chapel.

0 commit comments

Comments
 (0)