Skip to content

Commit abb3b93

Browse files
committed
Update Lab1 DAXPY and Select Exercise numbers to start at 1
1 parent d843181 commit abb3b93

File tree

15 files changed

+293
-296
lines changed

15 files changed

+293
-296
lines changed

README.md

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,9 @@ C++ HPC Tutorial
66
### Pre-requisites
77

88
To build the container locally, a properly configured container runtime is required.
9-
Both Docker and Singularity are supported.
9+
Both Docker and Singularity containers are supported.
1010

11-
Building the container requires the Docker or Singularity container descriptions.
12-
This project uses [HPC Container Maker] to generate these descriptions from a single portable container description.
13-
[HPPCM] is a Python application.
14-
Running it requires Python, and it can be installed using Python's package manager `pip`:
11+
The containers are generated from a single single description at [`/ci/recipe.py`](./ci/recipe.py) using the [HPC Container Maker][HPCCM] Python application, which requires a Python installation and can be installed with `pip`:
1512

1613
```
1714
pip3 install --user hpccm
@@ -32,7 +29,7 @@ PATH=$PATH:$PYTHONPATH
3229

3330
### Building container and serving Jupyter Notebooks
3431

35-
To build the container and start the Jupter notebook webserver locally here are the instructions for `Docker` and `Singularity`.
32+
To build the container and start the Jupter notebook webserver locally here are the instructions for `Docker` and `Singularity`. The Jupyter notebook webserver provides an URL that can be used to connect to it from a webbrowser. When running it on a cluster, one might need to use SSH port forwarding to forward a local port to the compute node.
3633

3734
[HPCCM]:
3835

labs/lab1_daxpy/daxpy.ipynb

Lines changed: 46 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,13 @@
112112
"cell_type": "markdown",
113113
"metadata": {},
114114
"source": [
115-
"## Exercise 0: from raw DAXPY loop to serial C++ transform algorithm\n",
115+
"## Exercise 1: from raw DAXPY loop to serial C++ transform algorithm\n",
116116
"\n",
117117
"The goal of this first exercise is to re-write the raw DAXPY loop using the C++ standard library `transform` algorithms (see the documentation of [transform] to pick the right overload - number (3)).\n",
118118
"\n",
119119
"[transform]: https://en.cppreference.com/w/cpp/algorithm/transform\n",
120120
"\n",
121-
"A template for the solution is provided in [exercise0.cpp]. The `TODO`s indicate the parts of the template that must be completed.\n",
121+
"A template for the solution is provided in [exercise1.cpp]. The `TODO`s indicate the parts of the template that must be completed.\n",
122122
"To complete this first exercise, the `daxpy` function needs to be rewritten to use the C++ standatd library algorithms and this will require adding some headers:\n",
123123
"\n",
124124
"```c++\n",
@@ -133,7 +133,7 @@
133133
"}\n",
134134
"```\n",
135135
"\n",
136-
"[exercise0.cpp]: ./exercise0.cpp\n",
136+
"[exercise1.cpp]: ./exercise1.cpp\n",
137137
"\n",
138138
"The example compiles and runs as provided, but it produces incorrect results due to the incomplete `daxpy` implementation.\n",
139139
"Once you fix it, the following blocks should compile and run correctly:\n"
@@ -145,7 +145,7 @@
145145
"metadata": {},
146146
"outputs": [],
147147
"source": [
148-
"!g++ -std=c++20 -Ofast -march=native -DNDEBUG -o daxpy exercise0.cpp\n",
148+
"!g++ -std=c++20 -Ofast -march=native -DNDEBUG -o daxpy exercise1.cpp\n",
149149
"!./daxpy 1000000"
150150
]
151151
},
@@ -155,7 +155,7 @@
155155
"metadata": {},
156156
"outputs": [],
157157
"source": [
158-
"!clang++ -std=c++20 -Ofast -march=native -DNDEBUG -o daxpy exercise0.cpp\n",
158+
"!clang++ -std=c++20 -Ofast -march=native -DNDEBUG -o daxpy exercise1.cpp\n",
159159
"!./daxpy 1000000"
160160
]
161161
},
@@ -165,25 +165,25 @@
165165
"metadata": {},
166166
"outputs": [],
167167
"source": [
168-
"!nvc++ -std=c++20 -O4 -fast -march=native -Mllvm-fast -DNDEBUG -o daxpy exercise0.cpp\n",
168+
"!nvc++ -std=c++20 -O4 -fast -march=native -Mllvm-fast -DNDEBUG -o daxpy exercise1.cpp\n",
169169
"!./daxpy 1000000"
170170
]
171171
},
172172
{
173173
"cell_type": "markdown",
174174
"metadata": {},
175175
"source": [
176-
"### Solutions Exercise 0\n",
176+
"### Solutions Exercise 1\n",
177177
"\n",
178178
"The solutions for each example are available in the [`solutions/`] sub-directory.\n",
179179
"\n",
180180
"[`solutions/`]: ./solutions\n",
181181
"\n",
182-
"The solution for this first exercise is in [`solutions/exercise0.cpp`].\n",
182+
"The solution for this first exercise is in [`solutions/exercise1.cpp`].\n",
183183
"\n",
184-
"[`solutions/exercise0.cpp`]: ./solutions/exercise0.cpp\n",
184+
"[`solutions/exercise1.cpp`]: ./solutions/exercise1.cpp\n",
185185
"\n",
186-
"The following blocks compile and run the solutions for Exercise 0 using different compilers."
186+
"The following blocks compile and run the solutions for Exercise 1 using different compilers."
187187
]
188188
},
189189
{
@@ -192,7 +192,7 @@
192192
"metadata": {},
193193
"outputs": [],
194194
"source": [
195-
"!g++ -std=c++17 -Ofast -march=native -DNDEBUG -o daxpy solutions/exercise0.cpp\n",
195+
"!g++ -std=c++17 -Ofast -march=native -DNDEBUG -o daxpy solutions/exercise1.cpp\n",
196196
"!./daxpy 1000000"
197197
]
198198
},
@@ -202,7 +202,7 @@
202202
"metadata": {},
203203
"outputs": [],
204204
"source": [
205-
"!clang++ -std=c++17 -Ofast -march=native -DNDEBUG -o daxpy solutions/exercise0.cpp\n",
205+
"!clang++ -std=c++17 -Ofast -march=native -DNDEBUG -o daxpy solutions/exercise1.cpp\n",
206206
"!./daxpy 1000000"
207207
]
208208
},
@@ -212,20 +212,20 @@
212212
"metadata": {},
213213
"outputs": [],
214214
"source": [
215-
"!nvc++ -std=c++17 -O4 -fast -march=native -Mllvm-fast -DNDEBUG -o daxpy solutions/exercise0.cpp\n",
215+
"!nvc++ -std=c++17 -O4 -fast -march=native -Mllvm-fast -DNDEBUG -o daxpy solutions/exercise1.cpp\n",
216216
"!./daxpy 1000000"
217217
]
218218
},
219219
{
220220
"cell_type": "markdown",
221221
"metadata": {},
222222
"source": [
223-
"# Exercise 1\n",
223+
"# Exercise 2: from raw initialization to `std::fill_n` and `std::for_each_n`\n",
224224
"\n",
225-
"In Exercise 2 we will parallelize `daxpy` to allow it to run on accelerator devices like a GPUs.\n",
225+
"In Exercise 3 we will parallelize `daxpy` to allow it to run on accelerator devices like a GPUs.\n",
226226
"When doing so, it is important to avoid unnecessary memory migrations across devices.\n",
227227
"\n",
228-
"The goal of this exercise is to initialize the memory using the standard library algorithms, so that when we parallelize the initialization in Exercise 2, it will happen on the accelerator device itself.\n",
228+
"The goal of this exercise is to initialize the memory using the standard library algorithms, so that when we parallelize the initialization in Exercise 3, it will happen on the accelerator device itself.\n",
229229
"\n",
230230
"Since we need to initialize two vectors - `x` and `y` - lets use a different approach to initialize each:\n",
231231
"\n",
@@ -236,9 +236,7 @@
236236
"[for_each_n]: https://en.cppreference.com/w/cpp/algorithm/for_each_n \n",
237237
"[iota_view]: https://en.cppreference.com/w/cpp/ranges/iota_view\n",
238238
"\n",
239-
"* `std::for_each_n` algorithms with `std::views::iota` for ind (see [for_each\n",
240-
"\n",
241-
"A template for the solution is provided in [exercise1.cpp]. The `TODO`s indicate the parts of the template that must be completed.\n",
239+
"A template for the solution is provided in [exercise2.cpp]. The `TODO`s indicate the parts of the template that must be completed.\n",
242240
"To complete this first exercise, the `initialize` function needs to be rewritten to use the C++ standatd library algorithms and this will require adding some headers for accessing `std::views::iota`:\n",
243241
"\n",
244242
"```c++\n",
@@ -253,7 +251,7 @@
253251
"}\n",
254252
"```\n",
255253
"\n",
256-
"[exercise1.cpp]: ./exercise1.cpp\n",
254+
"[exercise2.cpp]: ./exercise2.cpp\n",
257255
"\n",
258256
"The example compiles and runs as provided, but it produces incorrect results due to the incomplete `initialize` implementation.\n",
259257
"In the compilation commands below, the C++ standard version is now C++20, to enable the use of `views::iota`.\n",
@@ -267,7 +265,7 @@
267265
"metadata": {},
268266
"outputs": [],
269267
"source": [
270-
"!g++ -std=c++20 -Ofast -march=native -DNDEBUG -o daxpy exercise1.cpp\n",
268+
"!g++ -std=c++20 -Ofast -march=native -DNDEBUG -o daxpy exercise2.cpp\n",
271269
"!./daxpy 1000000"
272270
]
273271
},
@@ -277,7 +275,7 @@
277275
"metadata": {},
278276
"outputs": [],
279277
"source": [
280-
"!clang++ -std=c++20 -Ofast -march=native -DNDEBUG -isystem/usr/local/range-v3/include -o daxpy exercise1.cpp\n",
278+
"!clang++ -std=c++20 -Ofast -march=native -DNDEBUG -isystem/usr/local/range-v3/include -o daxpy exercise2.cpp\n",
281279
"!./daxpy 1000000"
282280
]
283281
},
@@ -287,19 +285,19 @@
287285
"metadata": {},
288286
"outputs": [],
289287
"source": [
290-
"!nvc++ -std=c++20 -O4 -fast -march=native -Mllvm-fast -o daxpy exercise1.cpp\n",
288+
"!nvc++ -std=c++20 -O4 -fast -march=native -Mllvm-fast -DNDEBUG -o daxpy exercise2.cpp\n",
291289
"!./daxpy 1000000"
292290
]
293291
},
294292
{
295293
"cell_type": "markdown",
296294
"metadata": {},
297295
"source": [
298-
"### Solutions Exercise 1\n",
296+
"### Solutions Exercise 2\n",
299297
"\n",
300-
"The solution for this exercise is in [`solutions/exercise1.cpp`].\n",
298+
"The solution for this exercise is in [`solutions/exercise2.cpp`].\n",
301299
"\n",
302-
"[`solutions/exercise1.cpp`]: ./solutions/exercise1.cpp\n",
300+
"[`solutions/exercise2.cpp`]: ./solutions/exercise2.cpp\n",
303301
"\n",
304302
"The following compiles and runs the solutions for Exercise 1 using different compilers."
305303
]
@@ -311,7 +309,7 @@
311309
"outputs": [],
312310
"source": [
313311
"# Using iota range for initialize \n",
314-
"!g++ -std=c++20 -Ofast -march=native -DNDEBUG -o daxpy solutions/exercise1.cpp\n",
312+
"!g++ -std=c++20 -Ofast -march=native -DNDEBUG -o daxpy solutions/exercise2.cpp\n",
315313
"!./daxpy 1000000"
316314
]
317315
},
@@ -321,7 +319,7 @@
321319
"metadata": {},
322320
"outputs": [],
323321
"source": [
324-
"!clang++ -std=c++20 -Ofast -march=native -DNDEBUG -o daxpy solutions/exercise1.cpp\n",
322+
"!clang++ -std=c++20 -Ofast -march=native -DNDEBUG -o daxpy solutions/exercise2.cpp\n",
325323
"!./daxpy 1000000"
326324
]
327325
},
@@ -331,19 +329,19 @@
331329
"metadata": {},
332330
"outputs": [],
333331
"source": [
334-
"!nvc++ -std=c++20 -O4 -fast -march=native -Mllvm-fast -o daxpy solutions/exercise1.cpp\n",
332+
"!nvc++ -std=c++20 -O4 -fast -march=native -Mllvm-fast -DNDEBUG -o daxpy solutions/exercise2.cpp\n",
335333
"!./daxpy 1000000"
336334
]
337335
},
338336
{
339337
"cell_type": "markdown",
340338
"metadata": {},
341339
"source": [
342-
"## Exercise 2: parallelizing DAXPY using C++ parallel algorithms\n",
340+
"## Exercise 3: parallelizing DAXPY and Initialization using C++ parallel algorithms\n",
343341
"\n",
344342
"The goal of this final exercise in this section is to parallelize the `initialize` and `daxpy` functions to compute the results in parallel using CPUs or GPUs.\n",
345343
"\n",
346-
"A template for the solution is provided in [exercise2.cpp].\n",
344+
"A template for the solution is provided in [exercise3.cpp].\n",
347345
"\n",
348346
"```c++\n",
349347
"#include <ranges>\n",
@@ -368,7 +366,7 @@
368366
"}\n",
369367
"```\n",
370368
"\n",
371-
"[exercise2.cpp]: ./exercise2.cpp\n",
369+
"[exercise3.cpp]: ./exercise3.cpp\n",
372370
"\n",
373371
"Compiling with support for the parallel algorithms requires:\n",
374372
"* `g++` and `clang++`: link against Intel TBB with `-ltbb`\n",
@@ -387,7 +385,7 @@
387385
"metadata": {},
388386
"outputs": [],
389387
"source": [
390-
"!g++ -std=c++20 -Ofast -march=native -DNDEBUG -o daxpy exercise2.cpp -ltbb\n",
388+
"!g++ -std=c++20 -Ofast -march=native -DNDEBUG -o daxpy exercise3.cpp -ltbb\n",
391389
"!./daxpy 1000000"
392390
]
393391
},
@@ -397,7 +395,7 @@
397395
"metadata": {},
398396
"outputs": [],
399397
"source": [
400-
"!clang++ -std=c++20 -Ofast -march=native -DNDEBUG -o daxpy exercise2.cpp -ltbb\n",
398+
"!clang++ -std=c++20 -Ofast -march=native -DNDEBUG -o daxpy exercise3.cpp -ltbb\n",
401399
"!./daxpy 1000000"
402400
]
403401
},
@@ -407,7 +405,7 @@
407405
"metadata": {},
408406
"outputs": [],
409407
"source": [
410-
"!nvc++ -stdpar=multicore -std=c++20 -O4 -fast -march=native -Mllvm-fast -o daxpy exercise2.cpp\n",
408+
"!nvc++ -stdpar=multicore -std=c++20 -O4 -fast -march=native -Mllvm-fast -DNDEBUG -o daxpy exercise3.cpp\n",
411409
"!./daxpy 1000000"
412410
]
413411
},
@@ -417,23 +415,25 @@
417415
"metadata": {},
418416
"outputs": [],
419417
"source": [
420-
"!nvc++ -stdpar=gpu -std=c++20 -O4 -fast -march=native -Mllvm-fast -o daxpy exercise2.cpp\n",
418+
"!nvc++ -stdpar=gpu -std=c++20 -O4 -fast -march=native -Mllvm-fast -DNDEBUG -o daxpy exercise3.cpp\n",
421419
"!./daxpy 1000000"
422420
]
423421
},
424422
{
425423
"cell_type": "markdown",
426-
"metadata": {},
424+
"metadata": {
425+
"tags": []
426+
},
427427
"source": [
428-
"### Solutions for Exercise 2\n",
428+
"### Solutions for Exercise 3\n",
429429
"\n",
430-
"The solution for this exercise is in [`solutions/exercise2.cpp`].\n",
430+
"The solution for this exercise is in [`solutions/exercise3.cpp`].\n",
431431
"\n",
432-
"[`solutions/exercise2.cpp`]: ./solutions/exercise2.cpp\n",
432+
"[`solutions/exercise3.cpp`]: ./solutions/exercise3.cpp\n",
433433
"\n",
434-
"The following blocks compile and run the solutions for Exercise 2 using different compilers on the CPU.\n",
434+
"The following blocks compile and run the solutions for Exercise 3 using different compilers on the CPU.\n",
435435
"\n",
436-
"The last block compiles and runs the solution for Exercise 2 on the GPU. If you get an error, make sure that the lambda captures are captiruing scalars by value, and that when capturing a vector to access its data, one captures a pointer to its data by value as well using `[x = x.data()]`."
436+
"The last block compiles and runs the solution for Exercise 3 on the GPU. If you get an error, make sure that the lambda captures are captiruing scalars by value, and that when capturing a vector to access its data, one captures a pointer to its data by value as well using `[x = x.data()]`."
437437
]
438438
},
439439
{
@@ -442,7 +442,7 @@
442442
"metadata": {},
443443
"outputs": [],
444444
"source": [
445-
"!g++ -std=c++20 -Ofast -march=native -DNDEBUG -o daxpy solutions/exercise2.cpp -ltbb\n",
445+
"!g++ -std=c++20 -Ofast -march=native -DNDEBUG -o daxpy solutions/exercise3.cpp -ltbb\n",
446446
"!./daxpy 1000000"
447447
]
448448
},
@@ -452,7 +452,7 @@
452452
"metadata": {},
453453
"outputs": [],
454454
"source": [
455-
"!clang++ -std=c++20 -Ofast -march=native -DNDEBUG -o daxpy solutions/exercise2.cpp -ltbb\n",
455+
"!clang++ -std=c++20 -Ofast -march=native -DNDEBUG -o daxpy solutions/exercise3.cpp -ltbb\n",
456456
"!./daxpy 1000000"
457457
]
458458
},
@@ -462,7 +462,7 @@
462462
"metadata": {},
463463
"outputs": [],
464464
"source": [
465-
"!nvc++ -stdpar=multicore -std=c++20 -O4 -fast -march=native -Mllvm-fast -o daxpy solutions/exercise2.cpp\n",
465+
"!nvc++ -stdpar=multicore -std=c++20 -O4 -fast -march=native -Mllvm-fast -DNDEBUG -o daxpy solutions/exercise3.cpp\n",
466466
"!./daxpy 1000000"
467467
]
468468
},
@@ -472,7 +472,7 @@
472472
"metadata": {},
473473
"outputs": [],
474474
"source": [
475-
"!nvc++ -stdpar=gpu -std=c++20 -O4 -fast -march=native -Mllvm-fast -o daxpy solutions/exercise2.cpp\n",
475+
"!nvc++ -stdpar=gpu -std=c++20 -O4 -fast -march=native -Mllvm-fast -DNDEBUG -o daxpy solutions/exercise3.cpp\n",
476476
"!./daxpy 1000000"
477477
]
478478
}

labs/lab1_daxpy/exercise1.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,23 +27,23 @@
2727
#include <limits>
2828
#include <string>
2929
#include <vector>
30-
#include <algorithm>
3130
// TODO: add C++ standard library includes as necessary
3231
// #include <...>
3332

3433
/// Intialize vectors `x` and `y`: raw loop sequential version
3534
void initialize(std::vector<double> &x, std::vector<double> &y) {
3635
assert(x.size() == y.size());
37-
// TODO: Initialize `x` using SEQUENTIAL std::for_each_n algorithm with std::views::iota
38-
// TODO: Initialize `y` using SEQUENTIAL std::fill_n algorithm
36+
for (std::size_t i = 0; i < x.size(); ++i) {
37+
x[i] = (double)i;
38+
y[i] = 2.;
39+
}
3940
}
4041

41-
/// DAXPY: AX + Y: raw loop sequential version
42+
/// DAXPY: AX + Y: sequential algorithm version
4243
void daxpy(double a, std::vector<double> const &x, std::vector<double> &y) {
4344
assert(x.size() == y.size());
44-
// DONE: Implement using SEQUENTIAL transform algorithm
45-
std::transform(x.begin(), x.end(), y.begin(), y.begin(),
46-
[&](double x, double y) { return a * x + y; });
45+
// TODO: Implement using SEQUENTIAL transform algorithm
46+
// ...
4747
}
4848

4949
// Check solution
@@ -99,4 +99,4 @@ bool check(double a, std::vector<double> const &y) {
9999
return false;
100100
}
101101
return true;
102-
}
102+
}

0 commit comments

Comments
 (0)