diff --git a/dev/LEQ/index.html b/dev/LEQ/index.html index eb05c33..4a68218 100644 --- a/dev/LEQ/index.html +++ b/dev/LEQ/index.html @@ -1,5 +1,5 @@ -- · XM_40017
+- · XM_40017
Tip
    @@ -14,4 +14,4 @@ var myIframe = document.getElementById("notebook"); iFrameResize({log:true}, myIframe); }); -
+
diff --git a/dev/LEQ_src/index.html b/dev/LEQ_src/index.html index 8617eab..b425a44 100644 --- a/dev/LEQ_src/index.html +++ b/dev/LEQ_src/index.html @@ -7333,7 +7333,8 @@ a.anchor-link { if (!diagrams.length) { return; } - const mermaid = (await import("https://cdnjs.cloudflare.com/ajax/libs/mermaid/10.2.3/mermaid.esm.min.mjs")).default; + const mermaid = (await import("https://cdnjs.cloudflare.com/ajax/libs/mermaid/10.3.1/mermaid.esm.min.mjs")).default; + const parser = new DOMParser(); mermaid.initialize({ maxTextSize: 100000, @@ -7349,39 +7350,52 @@ a.anchor-link { let _nextMermaidId = 0; function makeMermaidImage(svg) { - const img = document.createElement('img'); - const maxWidth = svg.match(/max-width: (\d+)/); - if (maxWidth && maxWidth[1]) { - const width = parseInt(maxWidth[1]); - if (width && !Number.isNaN(width) && Number.isFinite(width)) { - img.width = width; - } + const img = document.createElement("img"); + const doc = parser.parseFromString(svg, "image/svg+xml"); + const svgEl = doc.querySelector("svg"); + const { maxWidth } = svgEl?.style || {}; + const firstTitle = doc.querySelector("title"); + const firstDesc = doc.querySelector("desc"); + + img.setAttribute("src", `data:image/svg+xml,${encodeURIComponent(svg)}`); + if (maxWidth) { + img.width = parseInt(maxWidth); } - img.setAttribute('src', `data:image/svg+xml,${encodeURIComponent(svg)}`); - return img; + if (firstTitle) { + img.setAttribute("alt", firstTitle.textContent); + } + if (firstDesc) { + const caption = document.createElement("figcaption"); + caption.className = "sr-only"; + caption.textContent = firstDesc.textContent; + return [img, caption]; + } + return [img]; } async function makeMermaidError(text) { - let errorMessage = ''; + let errorMessage = ""; try { await mermaid.parse(text); } catch (err) { errorMessage = `${err}`; } - const result = document.createElement('details'); - const summary = document.createElement('summary'); - const pre = document.createElement('pre'); - const code = document.createElement('code'); + const result = document.createElement("details"); + result.className = 'jp-RenderedMermaid-Details'; + const summary = document.createElement("summary"); + summary.className = 'jp-RenderedMermaid-Summary'; + const pre = document.createElement("pre"); + const code = document.createElement("code"); code.innerText = text; pre.appendChild(code); summary.appendChild(pre); result.appendChild(summary); - const warning = document.createElement('pre'); + const warning = document.createElement("pre"); warning.innerText = errorMessage; result.appendChild(warning); - return result; + return [result]; } async function renderOneMarmaid(src) { @@ -7391,30 +7405,41 @@ a.anchor-link { const el = document.createElement("div"); el.style.visibility = "hidden"; document.body.appendChild(el); - let result = null; + let results = null; + let output = null; try { const { svg } = await mermaid.render(id, raw, el); - result = makeMermaidImage(svg); + results = makeMermaidImage(svg); + output = document.createElement("figure"); + results.map(output.appendChild, output); } catch (err) { parent.classList.add("jp-mod-warning"); - result = await makeMermaidError(raw); + results = await makeMermaidError(raw); + output = results[0]; } finally { el.remove(); } parent.classList.add("jp-RenderedMermaid"); - parent.appendChild(result); + parent.appendChild(output); } void Promise.all([...diagrams].map(renderOneMarmaid)); }); diff --git a/dev/asp.ipynb b/dev/asp.ipynb index db011b2..b2c7466 100644 --- a/dev/asp.ipynb +++ b/dev/asp.ipynb @@ -65,33 +65,22 @@ "source": [ "### Floyd's sequential algoritm\n", "\n", - "The ASP problem can be solved with the [Floyd–Warshall algorithm](https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm). A sequential implementation of this algorithm is given in this function." + "The ASP problem can be solved with the [Floyd–Warshall algorithm](https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm). A sequential implementation of this algorithm is given in the following function:" ] }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "id": "4fe447c5", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "floyd! (generic function with 1 method)" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "function floyd!(C)\n", " n = size(C,1)\n", " @assert size(C,2) == n\n", " for k in 1:n\n", - " for i in 1:n\n", - " for j in 1:n\n", + " for j in 1:n\n", + " for i in 1:n\n", " @inbounds C[i,j] = min(C[i,j],C[i,k]+C[k,j])\n", " end\n", " end\n", @@ -110,25 +99,10 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "860e537c", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "4×4 Matrix{Int64}:\n", - " 0 9 6 1\n", - " 2 0 8 3\n", - " 5 3 0 6\n", - " 10 8 5 0" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "inf = 1000\n", "C = [\n", @@ -154,8 +128,8 @@ "```julia\n", "n = size(C,1)\n", "for k in 1:n\n", - " for i in 1:n\n", - " for j in 1:n\n", + " for j in 1:n\n", + " for i in 1:n\n", " C[i,j] = min(C[i,j],C[i,k]+C[k,j])\n", " end\n", " end\n", @@ -248,6 +222,69 @@ "" ] }, + { + "cell_type": "markdown", + "id": "c7027ac3", + "metadata": {}, + "source": [ + "### Serial performance\n", + "\n", + "This algorithm is memory bound, meaning that the main cost is in getting and setting data from the input matrix `C`. In this situations, the order in which we traverse the entries of matrix `C` has a significant performance impact.\n", + "\n", + "The following function computes the same result as for the previous function `floyd!`, but the nesting of loops over i and j is changed.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "75cac17e", + "metadata": {}, + "outputs": [], + "source": [ + "function floyd2!(C)\n", + " n = size(C,1)\n", + " @assert size(C,2) == n\n", + " for k in 1:n\n", + " for i in 1:n\n", + " for j in 1:n\n", + " @inbounds C[i,j] = min(C[i,j],C[i,k]+C[k,j])\n", + " end\n", + " end\n", + " end\n", + " C\n", + "end" + ] + }, + { + "cell_type": "markdown", + "id": "399385e8", + "metadata": {}, + "source": [ + " Compare the performance of both implementations (run the cell several times)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "907bc8c9", + "metadata": {}, + "outputs": [], + "source": [ + "n = 1000\n", + "C = rand(n,n)\n", + "@time floyd!(C)\n", + "C = rand(n,n)\n", + "@time floyd2!(C);" + ] + }, + { + "cell_type": "markdown", + "id": "ad811b10", + "metadata": {}, + "source": [ + "The performance difference is significant. Matrices in Julia are stored in memory in column-major order (like in Fortran, unlike in C). It means that it is more efficient to access the data also in column-major order (like in function `floyd!`). See this section of [Julia's performance tips](https://docs.julialang.org/en/v1/manual/performance-tips/#man-performance-column-major) if you are interested in further details." + ] + }, { "cell_type": "markdown", "id": "0c95ea88", @@ -264,8 +301,8 @@ "```julia\n", "n = size(C,1)\n", "for k in 1:n\n", - " for i in 1:n\n", - " for j in 1:n\n", + " for j in 1:n\n", + " for i in 1:n\n", " C[i,j] = min(C[i,j],C[i,k]+C[k,j])\n", " end\n", " end\n", @@ -401,8 +438,12 @@ "source": [ "- Each process updates $N^2/P$ entries per iteration\n", "- 1 process broadcasts a message of length $N$ to $P-1$ processes per iteration\n", + "- The send cost in this process is $O(N P)$ per iteration (if we use send/receive instead of broadcast)\n", "- $P-1$ processes receive one message of length $N$ per iteration\n", - "- The receive/computation ration is $O(P/N)$ which would be small if $P< threshold\n", - " C[i,j] = rand(mincost:maxcost)\n", - " end\n", - " end\n", - " C[j,j] = 0\n", - " end\n", - " C\n", - "end" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3116096c", - "metadata": {}, - "outputs": [], - "source": [ - "rand_distance_table(10)" + "## Parallel Implementation\n" ] }, { @@ -511,7 +509,9 @@ "id": "680e56cf", "metadata": {}, "source": [ - "### Code" + "### Code\n", + "\n", + "We split the code in two functions. The first function is called on the main process (the process running this notebook). It splits the input matrix into blocks of rows. Then, we call `floyd_worker!` (see below) remotely on each worker using the corresponding block of rows.\n" ] }, { @@ -534,6 +534,14 @@ "end" ] }, + { + "cell_type": "markdown", + "id": "9fc3be11", + "metadata": {}, + "source": [ + "The second function is the one run on the workers. Note that we considered MPI for communication in this case." + ] + }, { "cell_type": "code", "execution_count": null, @@ -560,8 +568,8 @@ " else\n", " MPI.Recv!(C_k,comm,source=MPI.ANY_SOURCE,tag=0)\n", " end\n", - " for i in 1:m\n", - " for j in 1:n\n", + " for j in 1:n\n", + " for i in 1:m\n", " @inbounds Cw[i,j] = min(Cw[i,j],Cw[i,k]+C_k[j])\n", " end\n", " end\n", @@ -570,6 +578,39 @@ "end" ] }, + { + "cell_type": "markdown", + "id": "c624722a", + "metadata": {}, + "source": [ + "### Testing the implementation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "09937668", + "metadata": {}, + "outputs": [], + "source": [ + "function rand_distance_table(n)\n", + " threshold = 0.4\n", + " mincost = 3\n", + " maxcost = 10\n", + " infinity = 10000*maxcost\n", + " C = fill(infinity,n,n)\n", + " for j in 1:n\n", + " for i in 1:n\n", + " if rand() > threshold\n", + " C[i,j] = rand(mincost:maxcost)\n", + " end\n", + " end\n", + " C[j,j] = 0\n", + " end\n", + " C\n", + "end" + ] + }, { "cell_type": "code", "execution_count": null, @@ -654,21 +695,25 @@ "- Use synchronous send MPI_SSEND (less efficient). Note that the blocking send MPI_SEND used above does not guarantee that the message was received.\n", "- Barrier at the end of each iteration over $k$ (simple solution, but synchronization overhead)\n", "- Order incoming messages (buffering and extra user code needed)\n", - "- Use a specific rank id instead of `MPI.ANY_SOURCE` (one needs to know which are the rows owned by the other ranks)" + "- Use a specific rank id instead of `MPI.ANY_SOURCE` or use `MPI.Bcast!` (one needs to know which are the rows owned by the other ranks)" ] }, { - "cell_type": "code", - "execution_count": null, - "id": "db2b586f", + "cell_type": "markdown", + "id": "c789dc7a", "metadata": {}, - "outputs": [], - "source": [] + "source": [ + "# License\n", + "\n", + "\n", + "\n", + "This notebook is part of the course [Programming Large Scale Parallel Systems](https://www.francescverdugo.com/XM_40017) at Vrije Universiteit Amsterdam and may be used under a [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) license." + ] } ], "metadata": { "kernelspec": { - "display_name": "Julia 1.9.1", + "display_name": "Julia 1.9.0", "language": "julia", "name": "julia-1.9" }, @@ -676,7 +721,7 @@ "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", - "version": "1.9.1" + "version": "1.9.0" } }, "nbformat": 4, diff --git a/dev/asp/index.html b/dev/asp/index.html index 4c3f7c2..65da9e5 100644 --- a/dev/asp/index.html +++ b/dev/asp/index.html @@ -1,5 +1,5 @@ -- · XM_40017
+All pairs of shortest paths · XM_40017
Tip
    @@ -14,4 +14,4 @@ var myIframe = document.getElementById("notebook"); iFrameResize({log:true}, myIframe); }); -
+
diff --git a/dev/asp_src/index.html b/dev/asp_src/index.html index ed5a49b..1bdd7f2 100644 --- a/dev/asp_src/index.html +++ b/dev/asp_src/index.html @@ -7333,7 +7333,8 @@ a.anchor-link { if (!diagrams.length) { return; } - const mermaid = (await import("https://cdnjs.cloudflare.com/ajax/libs/mermaid/10.2.3/mermaid.esm.min.mjs")).default; + const mermaid = (await import("https://cdnjs.cloudflare.com/ajax/libs/mermaid/10.3.1/mermaid.esm.min.mjs")).default; + const parser = new DOMParser(); mermaid.initialize({ maxTextSize: 100000, @@ -7349,39 +7350,52 @@ a.anchor-link { let _nextMermaidId = 0; function makeMermaidImage(svg) { - const img = document.createElement('img'); - const maxWidth = svg.match(/max-width: (\d+)/); - if (maxWidth && maxWidth[1]) { - const width = parseInt(maxWidth[1]); - if (width && !Number.isNaN(width) && Number.isFinite(width)) { - img.width = width; - } + const img = document.createElement("img"); + const doc = parser.parseFromString(svg, "image/svg+xml"); + const svgEl = doc.querySelector("svg"); + const { maxWidth } = svgEl?.style || {}; + const firstTitle = doc.querySelector("title"); + const firstDesc = doc.querySelector("desc"); + + img.setAttribute("src", `data:image/svg+xml,${encodeURIComponent(svg)}`); + if (maxWidth) { + img.width = parseInt(maxWidth); } - img.setAttribute('src', `data:image/svg+xml,${encodeURIComponent(svg)}`); - return img; + if (firstTitle) { + img.setAttribute("alt", firstTitle.textContent); + } + if (firstDesc) { + const caption = document.createElement("figcaption"); + caption.className = "sr-only"; + caption.textContent = firstDesc.textContent; + return [img, caption]; + } + return [img]; } async function makeMermaidError(text) { - let errorMessage = ''; + let errorMessage = ""; try { await mermaid.parse(text); } catch (err) { errorMessage = `${err}`; } - const result = document.createElement('details'); - const summary = document.createElement('summary'); - const pre = document.createElement('pre'); - const code = document.createElement('code'); + const result = document.createElement("details"); + result.className = 'jp-RenderedMermaid-Details'; + const summary = document.createElement("summary"); + summary.className = 'jp-RenderedMermaid-Summary'; + const pre = document.createElement("pre"); + const code = document.createElement("code"); code.innerText = text; pre.appendChild(code); summary.appendChild(pre); result.appendChild(summary); - const warning = document.createElement('pre'); + const warning = document.createElement("pre"); warning.innerText = errorMessage; result.appendChild(warning); - return result; + return [result]; } async function renderOneMarmaid(src) { @@ -7391,30 +7405,41 @@ a.anchor-link { const el = document.createElement("div"); el.style.visibility = "hidden"; document.body.appendChild(el); - let result = null; + let results = null; + let output = null; try { const { svg } = await mermaid.render(id, raw, el); - result = makeMermaidImage(svg); + results = makeMermaidImage(svg); + output = document.createElement("figure"); + results.map(output.appendChild, output); } catch (err) { parent.classList.add("jp-mod-warning"); - result = await makeMermaidError(raw); + results = await makeMermaidError(raw); + output = results[0]; } finally { el.remove(); } parent.classList.add("jp-RenderedMermaid"); - parent.appendChild(result); + parent.appendChild(output); } void Promise.all([...diagrams].map(renderOneMarmaid)); }); @@ -7500,24 +7540,24 @@ a.anchor-link {
-
+
-
+
-
+ +
+
+ +
+ +
+
-
+
+
diff --git a/dev/index.html b/dev/index.html index 1250f3e..3918dfd 100644 --- a/dev/index.html +++ b/dev/index.html @@ -1,5 +1,5 @@ -Home · XM_40017

Programming Large-Scale Parallel Systems (XM_40017)

Welcome to the interactive lecture notes of the Programming Large-Scale Parallel Systems course at VU Amsterdam!

What

This page contains part of the course material of the Programming Large-Scale Parallel Systems course at VU Amsterdam. We provide several lecture notes in jupyter notebook format, which will help you to learn how to design, analyze, and program parallel algorithms on multi-node computing systems. Further information about the course is found in the study guide (click here) and our Canvas page (for registered students).

Note

Material will be added incrementally to the website as the course advances.

Warning

This page will eventually contain only a part of the course material. The rest will be available on Canvas. In particular, the material in this public webpage does not fully cover all topics in the final exam.

How to use this page

You have two main ways of studying the notebooks:

  • Download the notebooks and run them locally on your computer (recommended). At each notebook page you will find a green box with links to download the notebook.
  • You also have the static version of the notebooks displayed in this webpage for quick reference.

How to run the notebooks locally

To run a notebook locally follow these steps:

  • Install Julia (if not done already). More information in Getting started.
  • Download the notebook.
  • Launch Julia. More information in Getting started.
  • Execute these commands in the Julia command line:
julia> using Pkg
+Home · XM_40017

Programming Large-Scale Parallel Systems (XM_40017)

Welcome to the interactive lecture notes of the Programming Large-Scale Parallel Systems course at VU Amsterdam!

What

This page contains part of the course material of the Programming Large-Scale Parallel Systems course at VU Amsterdam. We provide several lecture notes in jupyter notebook format, which will help you to learn how to design, analyze, and program parallel algorithms on multi-node computing systems. Further information about the course is found in the study guide (click here) and our Canvas page (for registered students).

Note

Material will be added incrementally to the website as the course advances.

Warning

This page will eventually contain only a part of the course material. The rest will be available on Canvas. In particular, the material in this public webpage does not fully cover all topics in the final exam.

How to use this page

You have two main ways of studying the notebooks:

  • Download the notebooks and run them locally on your computer (recommended). At each notebook page you will find a green box with links to download the notebook.
  • You also have the static version of the notebooks displayed in this webpage for quick reference.

How to run the notebooks locally

To run a notebook locally follow these steps:

  • Install Julia (if not done already). More information in Getting started.
  • Download the notebook.
  • Launch Julia. More information in Getting started.
  • Execute these commands in the Julia command line:
julia> using Pkg
 julia> Pkg.add("IJulia")
 julia> using IJulia
-julia> notebook()
  • These commands will open a jupyter in your web browser. Navigate in jupyter to the notebook file you have downloaded and open it.

Authors

This material is created by Francesc Verdugo with the help of Gelieza Kötterheinrich. Part of the notebooks are based on the course slides by Henri Bal.

License

All material on this page that is original to this course may be used under a CC BY 4.0 license.

Acknowledgment

This page was created with the support of the Faculty of Science of Vrije Universiteit Amsterdam in the framework of the project "Interactive lecture notes and exercises for the Programming Large-Scale Parallel Systems course" funded by the "Innovation budget BETA 2023 Studievoorschotmiddelen (SVM) towards Activated Blended Learning".

+julia> notebook()
  • These commands will open a jupyter in your web browser. Navigate in jupyter to the notebook file you have downloaded and open it.

Authors

This material is created by Francesc Verdugo with the help of Gelieza Kötterheinrich. Part of the notebooks are based on the course slides by Henri Bal.

License

All material on this page that is original to this course may be used under a CC BY 4.0 license.

Acknowledgment

This page was created with the support of the Faculty of Science of Vrije Universiteit Amsterdam in the framework of the project "Interactive lecture notes and exercises for the Programming Large-Scale Parallel Systems course" funded by the "Innovation budget BETA 2023 Studievoorschotmiddelen (SVM) towards Activated Blended Learning".

diff --git a/dev/jacobi_2D/index.html b/dev/jacobi_2D/index.html index 7e606a1..e49cce7 100644 --- a/dev/jacobi_2D/index.html +++ b/dev/jacobi_2D/index.html @@ -1,5 +1,5 @@ -- · XM_40017
+- · XM_40017
Tip
    @@ -14,4 +14,4 @@ var myIframe = document.getElementById("notebook"); iFrameResize({log:true}, myIframe); }); -
+
diff --git a/dev/jacobi_2D_src/index.html b/dev/jacobi_2D_src/index.html index 67081a3..9d258b0 100644 --- a/dev/jacobi_2D_src/index.html +++ b/dev/jacobi_2D_src/index.html @@ -7333,7 +7333,8 @@ a.anchor-link { if (!diagrams.length) { return; } - const mermaid = (await import("https://cdnjs.cloudflare.com/ajax/libs/mermaid/10.2.3/mermaid.esm.min.mjs")).default; + const mermaid = (await import("https://cdnjs.cloudflare.com/ajax/libs/mermaid/10.3.1/mermaid.esm.min.mjs")).default; + const parser = new DOMParser(); mermaid.initialize({ maxTextSize: 100000, @@ -7349,39 +7350,52 @@ a.anchor-link { let _nextMermaidId = 0; function makeMermaidImage(svg) { - const img = document.createElement('img'); - const maxWidth = svg.match(/max-width: (\d+)/); - if (maxWidth && maxWidth[1]) { - const width = parseInt(maxWidth[1]); - if (width && !Number.isNaN(width) && Number.isFinite(width)) { - img.width = width; - } + const img = document.createElement("img"); + const doc = parser.parseFromString(svg, "image/svg+xml"); + const svgEl = doc.querySelector("svg"); + const { maxWidth } = svgEl?.style || {}; + const firstTitle = doc.querySelector("title"); + const firstDesc = doc.querySelector("desc"); + + img.setAttribute("src", `data:image/svg+xml,${encodeURIComponent(svg)}`); + if (maxWidth) { + img.width = parseInt(maxWidth); } - img.setAttribute('src', `data:image/svg+xml,${encodeURIComponent(svg)}`); - return img; + if (firstTitle) { + img.setAttribute("alt", firstTitle.textContent); + } + if (firstDesc) { + const caption = document.createElement("figcaption"); + caption.className = "sr-only"; + caption.textContent = firstDesc.textContent; + return [img, caption]; + } + return [img]; } async function makeMermaidError(text) { - let errorMessage = ''; + let errorMessage = ""; try { await mermaid.parse(text); } catch (err) { errorMessage = `${err}`; } - const result = document.createElement('details'); - const summary = document.createElement('summary'); - const pre = document.createElement('pre'); - const code = document.createElement('code'); + const result = document.createElement("details"); + result.className = 'jp-RenderedMermaid-Details'; + const summary = document.createElement("summary"); + summary.className = 'jp-RenderedMermaid-Summary'; + const pre = document.createElement("pre"); + const code = document.createElement("code"); code.innerText = text; pre.appendChild(code); summary.appendChild(pre); result.appendChild(summary); - const warning = document.createElement('pre'); + const warning = document.createElement("pre"); warning.innerText = errorMessage; result.appendChild(warning); - return result; + return [result]; } async function renderOneMarmaid(src) { @@ -7391,30 +7405,41 @@ a.anchor-link { const el = document.createElement("div"); el.style.visibility = "hidden"; document.body.appendChild(el); - let result = null; + let results = null; + let output = null; try { const { svg } = await mermaid.render(id, raw, el); - result = makeMermaidImage(svg); + results = makeMermaidImage(svg); + output = document.createElement("figure"); + results.map(output.appendChild, output); } catch (err) { parent.classList.add("jp-mod-warning"); - result = await makeMermaidError(raw); + results = await makeMermaidError(raw); + output = results[0]; } finally { el.remove(); } parent.classList.add("jp-RenderedMermaid"); - parent.appendChild(result); + parent.appendChild(output); } void Promise.all([...diagrams].map(renderOneMarmaid)); }); diff --git a/dev/jacobi_method.ipynb b/dev/jacobi_method.ipynb index 5db4dff..2b68002 100644 --- a/dev/jacobi_method.ipynb +++ b/dev/jacobi_method.ipynb @@ -62,8 +62,7 @@ "gauss_seidel_1_check(answer) = answer_checker(answer,\"c\")\n", "jacobi_1_check(answer) = answer_checker(answer, \"d\")\n", "jacobi_2_check(answer) = answer_checker(answer, \"b\")\n", - "jacobi_3_check(answer) = answer_checker(answer, \"c\")\n", - "jacobi_4_check(anwswer) = answer_checker(answer, \"d\")" + "jacobi_3_check(answer) = answer_checker(answer, \"c\")" ] }, { @@ -332,13 +331,333 @@ "id": "513f1f7e", "metadata": {}, "source": [ - "### Efficiency\n", + "### Communication overhead\n", "- We update $N/P$ entries in each process at each iteration, where $N$ is the total length of the vector and $P$ the number of processes\n", "- We need to get remote entries from 2 neighbors (2 messages per iteration)\n", "- We need to communicate 1 entry per message\n", "- Communication/computation ration is $O(P/N)$ (potentially scalable if $P<\n", + "\n", + "
" + ] + }, + { + "cell_type": "markdown", + "id": "0148f9b3", + "metadata": {}, + "source": [ + "Thus, the algorithm is usually implemented following two main phases at each iteration Jacobi:\n", + "\n", + "1. Fill the ghost entries with communications\n", + "2. Do the Jacobi update sequentially at each process" + ] + }, + { + "attachments": { + "fig15.png": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA6gAAAFACAYAAACxyVHuAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAewgAAHsIBbtB1PgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAACAASURBVHic7N15fFT19f/x12cmIQFkE1wANxBFrTu4b1itimQC2mKrtfrtRtXazbbWrmJba+1m7S5fv9Wqrbb5VWBugFatpe4buGvdFVcU2cISSOZ+fn+cO2QyTCAsmXszeT8fj/vIvXPv3Dm5M3PnnvvZ3DXXXOMRERERERERiVkq7gBEREREREREQAmqiIiIiIiIJERV0fLJzrlX4whEREREREREehbv/W7AP/PL7RJU59yrU6ZMeb7cQYmIiIiIiEjPM23aNLxv6xZJVXxFREREREQkEZSgioiIiIiISCIoQRUREREREZFEUIIqIiIiIiIiiaAEVURERERERBJBCaqIiIiIiIgkghJUERERERERSQQlqCIiIiIiIpIISlBFREREREQkEZSgioiIiIiISCIoQRUREREREZFEUIIqIiIiIiIiiaAEVURERERERBKhKu4ARDbGe+8aGxsvizuODbnuuusOWLhw4SCAhQsXvvbiiy++EndMRXYBRkbzy4H5McZSSn/g4ILlu4FcTLGUdPjhhx+dTqerAE455ZSnDjzwwEVxx9QR59yDdXV1s8rxWtls9nPOueHleK3NMXv27BFPPPHErgArV65c8thjjz0ed0xFBgEHFCzPjSmODRlXMP84sCSmODpyAHYcARYAL8cYy3pGjBixy7Bhw0YCbLvttsunTJmStPNvO+l0+vJTTz11TVe/ThAEewFndfXrbK7m5ub0L3/5y2Pyy88+++z8xYsXL48zphIOxn4/wT73C2KMpZQRwK7R/FLgsRhjWc/gwYMH7rXXXgfmly+55JK5MYazUWEY3jBx4sQX446jHJSgSuJddtllbsyYMd+NO44NeeGFF3jyySfzi8dsaNuEmBB3ABuRuGP4wAMPrJsfN25c4uIr5L3/LVCWBBX4DDC2TK+1yd577z3uvffewofq44qlkxL92SL58SXOK6+8wiuv2D3LUaNGQcLPv9XV1T8HujxB9d6Pds4l+re96NyR9M9+0uMDyMQdQKH333+/3XschuExqVRyK5em0+l7gR6RoCb3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" + } + }, + "cell_type": "markdown", + "id": "baccd833", + "metadata": {}, + "source": [ + "
\n", + "\n", + "
" + ] + }, + { + "cell_type": "markdown", + "id": "8ed4129c", + "metadata": {}, + "source": [ + "### Code\n", + "\n", + "\n", + "Take a look at the implementation below and try to understand it. Note that we have used MPIClustermanagers and Distributed just to run the MPI code on the notebook. When running it on a cluster, MPIClustermanagers and Distributed are not needed.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e15082fb", + "metadata": {}, + "outputs": [], + "source": [ + "] add MPI MPIClusterManagers" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a66cbf9a", + "metadata": {}, + "outputs": [], + "source": [ + "using MPIClusterManagers \n", + "using Distributed" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e0d63c6b", + "metadata": {}, + "outputs": [], + "source": [ + "if procs() == workers()\n", + " nw = 3\n", + " manager = MPIWorkerManager(nw)\n", + " addprocs(manager)\n", + "end" + ] + }, + { + "cell_type": "markdown", + "id": "d7fb9177", + "metadata": {}, + "source": [ + "First, we implement the function to be called on the MPI ranks." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d39c7bb2", + "metadata": { + "code_folding": [] + }, + "outputs": [], + "source": [ + "@everywhere workers() begin\n", + " using MPI\n", + " comm = MPI.Comm_dup(MPI.COMM_WORLD)\n", + " function jacobi_mpi(n,niters)\n", + " nranks = MPI.Comm_size(comm)\n", + " rank = MPI.Comm_rank(comm)\n", + " if mod(n,nranks) != 0\n", + " println(\"n must be a multiple of nranks\")\n", + " MPI.Abort(comm,1)\n", + " end\n", + " n_own = div(n,nranks)\n", + " u = zeros(n_own+2)\n", + " u[1] = -1\n", + " u[end] = 1\n", + " u_new = copy(u)\n", + " for t in 1:niters\n", + " reqs = MPI.Request[]\n", + " if rank != 0\n", + " neig_rank = rank-1\n", + " req = MPI.Isend(view(u,2:2),comm,dest=neig_rank,tag=0)\n", + " push!(reqs,req)\n", + " req = MPI.Irecv!(view(u,1:1),comm,source=neig_rank,tag=0)\n", + " push!(reqs,req)\n", + " end\n", + " if rank != (nranks-1)\n", + " neig_rank = rank+1\n", + " s = n_own+1\n", + " r = n_own+2\n", + " req = MPI.Isend(view(u,s:s),comm,dest=neig_rank,tag=0)\n", + " push!(reqs,req)\n", + " req = MPI.Irecv!(view(u,r:r),comm,source=neig_rank,tag=0)\n", + " push!(reqs,req)\n", + " end\n", + " MPI.Waitall(reqs)\n", + " for i in 2:(n_own+1)\n", + " u_new[i] = 0.5*(u[i-1]+u[i+1])\n", + " end\n", + " u, u_new = u_new, u\n", + " end\n", + " return u\n", + " end\n", + "end" + ] + }, + { + "cell_type": "markdown", + "id": "6eab32d0", + "metadata": {}, + "source": [ + "In order to check the result, we will compare it against the serial implementation. To this end, we need to define the serial implementation also in the workers." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f1a8db8f", + "metadata": {}, + "outputs": [], + "source": [ + "@everywhere workers() function jacobi(n,niters)\n", + " u = zeros(n+2)\n", + " u[1] = -1\n", + " u[end] = 1\n", + " u_new = copy(u)\n", + " for t in 1:niters\n", + " for i in 2:(n+1)\n", + " u_new[i] = 0.5*(u[i-1]+u[i+1])\n", + " end\n", + " u, u_new = u_new, u\n", + " end\n", + " u\n", + "end" + ] + }, + { + "cell_type": "markdown", + "id": "d2b04c67", + "metadata": {}, + "source": [ + "Finally, we call the parallel function on the workers, gather the results on the root rank, and compare against the sequential solution." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "68851107", + "metadata": { + "code_folding": [] + }, + "outputs": [], + "source": [ + "@everywhere workers() begin\n", + " # Call jacobi in parallel\n", + " niters = 10\n", + " load = 4\n", + " nranks = MPI.Comm_size(comm)\n", + " n = load*nranks\n", + " u = jacobi_mpi(n,niters)\n", + " # Gather results in root process and check\n", + " rank = MPI.Comm_rank(comm)\n", + " n_own = div(n,nranks)\n", + " if rank == 0\n", + " results = zeros(n+2)\n", + " results[1] = -1\n", + " results[n+2] = 1\n", + " rcv = view(results, 2:n+1)\n", + " else\n", + " rcv = nothing\n", + " end\n", + " MPI.Gather!(view(u,2:n_own+1),rcv,comm;root=0)\n", + " if rank == 0\n", + " @show results ≈ jacobi(n,niters)\n", + " end \n", + "end" + ] + }, + { + "cell_type": "markdown", + "id": "eff25246", + "metadata": {}, + "source": [ + "
\n", + "Question: In function jacobi_mpi, how many messages per iteration are sent from a process away from the boundary?\n", + "
\n", + "\n", + " a) 1\n", + " b) 2\n", + " c) 3\n", + " d) 4\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "98bd9b5e", + "metadata": {}, + "outputs": [], + "source": [ + "answer = \"x\" # replace x with a, b, c or d\n", + "jacobi_2_check(answer)" + ] + }, + { + "cell_type": "markdown", + "id": "075dd6d8", + "metadata": {}, + "source": [ + "
\n", + "Question: At the end of function jacobi_mpi ...\n", + "
\n", + "\n", + " a) each rank holds the complete solution.\n", + " b) only the root process holds the solution. \n", + " c) the values of the ghost cells of u are not consistent with the neighbors\n", + " d) the ghost cells of u contain the initial values -1 and 1 in all ranks" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c3b58002", + "metadata": {}, + "outputs": [], + "source": [ + "answer = \"x\" # replace x with a, b, c or d\n", + "jacobi_3_check(answer)" + ] + }, + { + "cell_type": "markdown", + "id": "c9aa2901", + "metadata": {}, + "source": [ + "### Latency hiding\n", + "\n", + "Can our implementation above be improved? Note that we only need communications to update the values at the boundary of the portion owned by each process. The other values (the one in green in the figure below) can be updated without communications. This provides the opportunity of overlapping the computation of the interior values (green cells in the figure) with the communication of the ghost values. This technique is called latency hiding, since we are hiding communication latency by overlapping it with communication that we need to do anyway.\n", + "\n", + "The modification of the implementation above to include latency hiding is leaved as an exercise (see below).\n" + ] + }, + { + "attachments": { + "fig16.png": { + "image/png": "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" + } + }, + "cell_type": "markdown", + "id": "7d66b1a2", + "metadata": {}, + "source": [ + "
\n", + "\n", + "
\n" + ] + }, { "cell_type": "markdown", "id": "9d4de5a9", @@ -497,7 +816,7 @@ "source": [ "### 1D block partition\n", "\n", - "The following figure shows the portion of vector `u_new` is updated at each iteration by a particular process (CPU 3) left picture, and which entries of `u` are needed to update this data, right picture. We use analogous figures for the other partitions below.\n" + "The following figure shows the portion of vector `u_new` that is updated at each iteration by a particular process (CPU 3) left picture, and which entries of `u` are needed to update this data, right picture. We use analogous figures for the other partitions below.\n" ] }, { @@ -594,6 +913,20 @@ "- Communication/computation ratio is $O(1)$" ] }, + { + "cell_type": "markdown", + "id": "3d0693a7", + "metadata": {}, + "source": [ + "### Summary\n", + "\n", + "|Partition | Messages
per iteration | Communication
per worker | Computation
per worker | Ratio communication/
computation |\n", + "|---|---|---|---|---|\n", + "| 1d block | 2 | O(N) | N²/P | O(P/N) |\n", + "| 2d block | 4 | O(N/√P) | N²/P | O(√P/N) |\n", + "| 2d cyclic | 4 |O(N²/P) | N²/P | O(1) |" + ] + }, { "cell_type": "markdown", "id": "850b1848", @@ -601,6 +934,8 @@ "source": [ "### Which partition is the best one?\n", "\n", + "\n", + "\n", "- Both 1d and 2d block partitions are potentially scalable if $P<\n", - "\n", - "" - ] - }, - { - "cell_type": "markdown", - "id": "0148f9b3", - "metadata": {}, - "source": [ - "Thus, the algorithm is usually implemented following two main phases at each iteration Jacobi:\n", - "\n", - "1. Fill the ghost entries with communications\n", - "2. Do the Jacobi update sequentially at each process" - ] - }, - { - "attachments": { - "fig15.png": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAA6gAAAFACAYAAACxyVHuAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAewgAAHsIBbtB1PgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAACAASURBVHic7N15fFT19f/x12cmIQFkE1wANxBFrTu4b1itimQC2mKrtfrtRtXazbbWrmJba+1m7S5fv9Wqrbb5VWBugFatpe4buGvdFVcU2cISSOZ+fn+cO2QyTCAsmXszeT8fj/vIvXPv3Dm5M3PnnvvZ3DXXXOMRERERERERiVkq7gBEREREREREQAmqiIiIiIiIJERV0fLJzrlX4whEREREREREehbv/W7AP/PL7RJU59yrU6ZMeb7cQYmIiIiIiEjPM23aNLxv6xZJVXxFREREREQkEZSgioiIiIiISCIoQRUREREREZFEUIIqIiIiIiIiiaAEVURERERERBJBCaqIiIiIiIgkghJUERERERERSQQlqCIiIiIiIpIISlBFREREREQkEZSgioiIiIiISCIoQRUREREREZFEUIIqIiIiIiIiiaAEVURERERERBKhKu4ARDbGe+8aGxsvizuODbnuuusOWLhw4SCAhQsXvvbiiy++EndMRXYBRkbzy4H5McZSSn/g4ILlu4FcTLGUdPjhhx+dTqerAE455ZSnDjzwwEVxx9QR59yDdXV1s8rxWtls9nPOueHleK3NMXv27BFPPPHErgArV65c8thjjz0ed0xFBgEHFCzPjSmODRlXMP84sCSmODpyAHYcARYAL8cYy3pGjBixy7Bhw0YCbLvttsunTJmStPNvO+l0+vJTTz11TVe/ThAEewFndfXrbK7m5ub0L3/5y2Pyy88+++z8xYsXL48zphIOxn4/wT73C2KMpZQRwK7R/FLgsRhjWc/gwYMH7rXXXgfmly+55JK5MYazUWEY3jBx4sQX446jHJSgSuJddtllbsyYMd+NO44NeeGFF3jyySfzi8dsaNuEmBB3ABuRuGP4wAMPrJsfN25c4uIr5L3/LVCWBBX4DDC2TK+1yd577z3uvffewofq44qlkxL92SL58SXOK6+8wiuv2D3LUaNGQcLPv9XV1T8HujxB9d6Pds4l+re96NyR9M9+0uMDyMQdQKH333+/3XschuExqVRyK5em0+l7gR6RoCb3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" - } - }, - "cell_type": "markdown", - "id": "baccd833", - "metadata": {}, - "source": [ - "
\n", - "\n", - "
" - ] - }, - { - "cell_type": "markdown", - "id": "8ed4129c", - "metadata": {}, - "source": [ - "### Code\n", - "\n", - "\n", - "Take a look at the implementation below and try to understand it. Note that we have used MPIClustermanagers and Distributed just to run the MPI code on the notebook. When running it on a cluster, MPIClustermanagers and Distributed are not needed.\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e15082fb", - "metadata": {}, - "outputs": [], - "source": [ - "] add MPI MPIClusterManagers" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a66cbf9a", - "metadata": {}, - "outputs": [], - "source": [ - "using MPIClusterManagers \n", - "using Distributed" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e0d63c6b", - "metadata": {}, - "outputs": [], - "source": [ - "if procs() == workers()\n", - " nw = 3\n", - " manager = MPIWorkerManager(nw)\n", - " addprocs(manager)\n", - "end" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a0923606", - "metadata": {}, - "outputs": [], - "source": [ - "# Test cell, remove me\n", - "u = [-1, 0, 0, 0, 0, 1]\n", - "view(u, 6:6)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "68851107", - "metadata": { - "code_folding": [] - }, - "outputs": [], - "source": [ - "@mpi_do manager begin\n", - " using MPI\n", - " comm = MPI.Comm_dup(MPI.COMM_WORLD)\n", - " nw = MPI.Comm_size(comm)\n", - " iw = MPI.Comm_rank(comm)+1\n", - " function jacobi_mpi(n,niters)\n", - " if mod(n,nw) != 0\n", - " println(\"n must be a multiple of nw\")\n", - " MPI.Abort(comm,1)\n", - " end\n", - " n_own = div(n,nw)\n", - " u = zeros(n_own+2)\n", - " u[1] = -1\n", - " u[end] = 1\n", - " u_new = copy(u)\n", - " for t in 1:niters\n", - " reqs = MPI.Request[]\n", - " # Exchange cell values with neighbors\n", - " if iw != 1\n", - " neig_rank = (iw-1)-1\n", - " req = MPI.Isend(view(u,2:2),comm,dest=neig_rank,tag=0)\n", - " push!(reqs,req)\n", - " req = MPI.Irecv!(view(u,1:1),comm,source=neig_rank,tag=0)\n", - " push!(reqs,req)\n", - " end\n", - " if iw != nw\n", - " neig_rank = (iw+1)-1\n", - " s = n_own+1\n", - " r = n_own+2\n", - " req = MPI.Isend(view(u,s:s),comm,dest=neig_rank,tag=0)\n", - " push!(reqs,req)\n", - " req = MPI.Irecv!(view(u,r:r),comm,source=neig_rank,tag=0)\n", - " push!(reqs,req)\n", - " end\n", - " MPI.Waitall(reqs)\n", - " for i in 2:(n_own+1)\n", - " u_new[i] = 0.5*(u[i-1]+u[i+1])\n", - " end\n", - " u, u_new = u_new, u\n", - " end\n", - " u\n", - " @show u\n", - " # Gather results in root process\n", - " results = zeros(n+2)\n", - " results[1] = -1\n", - " results[n+2] = 1\n", - " MPI.Gather!(view(u,2:n_own+1), view(results, 2:n+1), root=0, comm)\n", - " if iw == 1\n", - " @show results\n", - " end \n", - " end\n", - " niters = 100\n", - " load = 4\n", - " n = load*nw\n", - " jacobi_mpi(n,niters)\n", - "end" - ] - }, - { - "cell_type": "markdown", - "id": "eff25246", - "metadata": {}, - "source": [ - "
\n", - "Question: How many messages per iteration are sent from a process away from the boundary?\n", - "
\n", - "\n", - " a) 1\n", - " b) 2\n", - " c) 3\n", - " d) 4\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "98bd9b5e", - "metadata": {}, - "outputs": [], - "source": [ - "answer = \"x\" # replace x with a, b, c or d\n", - "jacobi_2_check(answer)" - ] - }, - { - "cell_type": "markdown", - "id": "075dd6d8", - "metadata": {}, - "source": [ - "
\n", - "Question: After the end of the for-loop (line 43), ...\n", - "
\n", - "\n", - " a) each worker holds the complete solution.\n", - " b) the root process holds the solution. \n", - " c) the ghost cells contain redundant values. \n", - " d) all ghost cells contain the initial values -1 and 1. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c3b58002", - "metadata": {}, - "outputs": [], - "source": [ - "answer = \"x\" # replace x with a, b, c or d\n", - "jacobi_3_check(answer)" - ] - }, - { - "cell_type": "markdown", - "id": "4537661d", - "metadata": {}, - "source": [ - "
\n", - "Question: In line 35 of the code, we wait for all receive and send requests. Is it possible to instead wait for just the receive requests?\n", - "
\n", - "\n", - " \n", - " a) No, because the send buffer might be overwritten if we don't wait for send requests.\n", - " b) No, because MPI does not allow an asynchronous send without a Wait().\n", - " c) Yes, because each send has a matching receive, so all requests are done when the receive requests return. \n", - " d) Yes, because there are no writes to the send buffer in this iteration." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e16ea5eb", - "metadata": {}, - "outputs": [], - "source": [ - "answer = \"x\" # replace x with a, b, c or d.\n", - "jacobi_4_check(answer)" - ] - }, - { - "cell_type": "markdown", - "id": "c9aa2901", - "metadata": {}, - "source": [ - "### Latency hiding\n", - "\n", - "Can our implementation above be improved? Note that we only need communications to update the values at the boundary of the portion owned by each process. The other values (the one in green in the figure below) can be updated without communications. This provides the opportunity of overlapping the computation of the interior values (green cells in the figure) with the communication of the ghost values. This technique is called latency hiding, since we are hiding communication latency by overlapping it with communications that we need to do anyway.\n", - "\n", - "The modification of the implementation above to include latency hiding is leaved as an exercise (see below).\n" - ] - }, - { - "attachments": { - "fig16.png": { - "image/png": "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" - } - }, - "cell_type": "markdown", - "id": "7d66b1a2", - "metadata": {}, - "source": [ - "
\n", - "\n", - "
\n" - ] - }, { "cell_type": "markdown", "id": "47643bf6", @@ -917,72 +959,7 @@ "source": [ "### Exercise 1\n", "\n", - "Transform the following parallel implementation of the 1d Jacobi method (it is copied from above) to use latency hiding (overlap between computation of interior values and communication)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "66db180d", - "metadata": {}, - "outputs": [], - "source": [ - "@mpi_do manager begin\n", - " using MPI\n", - " comm = MPI.Comm_dup(MPI.COMM_WORLD)\n", - " nw = MPI.Comm_size(comm)\n", - " iw = MPI.Comm_rank(comm)+1\n", - " function jacobi_mpi(n,niters)\n", - " if mod(n,nw) != 0\n", - " println(\"n must be a multiple of nw\")\n", - " MPI.Abort(comm,1)\n", - " end\n", - " n_own = div(n,nw)\n", - " u = zeros(n_own+2)\n", - " u[1] = -1\n", - " u[end] = 1\n", - " u_new = copy(u)\n", - " for t in 1:niters\n", - " reqs = MPI.Request[]\n", - " # Exchange cell values with neighbors\n", - " if iw != 1\n", - " neig_rank = (iw-1)-1\n", - " req = MPI.Isend(view(u,2:2),comm,dest=neig_rank,tag=0)\n", - " push!(reqs,req)\n", - " req = MPI.Irecv!(view(u,1:1),comm,source=neig_rank,tag=0)\n", - " push!(reqs,req)\n", - " end\n", - " if iw != nw\n", - " neig_rank = (iw+1)-1\n", - " s = n_own+1\n", - " r = n_own+2\n", - " req = MPI.Isend(view(u,s:s),comm,dest=neig_rank,tag=0)\n", - " push!(reqs,req)\n", - " req = MPI.Irecv!(view(u,r:r),comm,source=neig_rank,tag=0)\n", - " push!(reqs,req)\n", - " end\n", - " MPI.Waitall(reqs)\n", - " for i in 2:(n_own+1)\n", - " u_new[i] = 0.5*(u[i-1]+u[i+1])\n", - " end\n", - " u, u_new = u_new, u\n", - " end\n", - " u\n", - " @show u\n", - " # Gather results in root process\n", - " results = zeros(n+2)\n", - " results[1] = -1\n", - " results[n+2] = 1\n", - " MPI.Gather!(view(u,2:n_own+1), view(results, 2:n+1), root=0, comm)\n", - " if iw == 1\n", - " @show results\n", - " end \n", - " end\n", - " niters = 100\n", - " load = 4\n", - " n = load*nw\n", - " jacobi_mpi(n,niters)\n", - "end" + "Transform the parallel implementation of the 1d Jacobi method (function `jacopi_mpi`) to use latency hiding (overlap between computation of interior values and communication)." ] }, { @@ -992,18 +969,10 @@ "source": [ "# License\n", "\n", - "TODO: replace link to website\n", "\n", - "This notebook is part of the course [Programming Large Scale Parallel Systems](http://localhost:8000/) at Vrije Universiteit Amsterdam and may be used under a [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) license." + "\n", + "This notebook is part of the course [Programming Large Scale Parallel Systems](https://www.francescverdugo.com/XM_40017) at Vrije Universiteit Amsterdam and may be used under a [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) license." ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3d72ff47", - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/dev/jacobi_method/index.html b/dev/jacobi_method/index.html index 7840fc6..39e61df 100644 --- a/dev/jacobi_method/index.html +++ b/dev/jacobi_method/index.html @@ -1,5 +1,5 @@ -- · XM_40017
+Jacobi method · XM_40017
Tip
    @@ -14,4 +14,4 @@ var myIframe = document.getElementById("notebook"); iFrameResize({log:true}, myIframe); }); -
+
diff --git a/dev/jacobi_method_src/index.html b/dev/jacobi_method_src/index.html index 7ebaed6..2415915 100644 --- a/dev/jacobi_method_src/index.html +++ b/dev/jacobi_method_src/index.html @@ -7333,7 +7333,8 @@ a.anchor-link { if (!diagrams.length) { return; } - const mermaid = (await import("https://cdnjs.cloudflare.com/ajax/libs/mermaid/10.2.3/mermaid.esm.min.mjs")).default; + const mermaid = (await import("https://cdnjs.cloudflare.com/ajax/libs/mermaid/10.3.1/mermaid.esm.min.mjs")).default; + const parser = new DOMParser(); mermaid.initialize({ maxTextSize: 100000, @@ -7349,39 +7350,52 @@ a.anchor-link { let _nextMermaidId = 0; function makeMermaidImage(svg) { - const img = document.createElement('img'); - const maxWidth = svg.match(/max-width: (\d+)/); - if (maxWidth && maxWidth[1]) { - const width = parseInt(maxWidth[1]); - if (width && !Number.isNaN(width) && Number.isFinite(width)) { - img.width = width; - } + const img = document.createElement("img"); + const doc = parser.parseFromString(svg, "image/svg+xml"); + const svgEl = doc.querySelector("svg"); + const { maxWidth } = svgEl?.style || {}; + const firstTitle = doc.querySelector("title"); + const firstDesc = doc.querySelector("desc"); + + img.setAttribute("src", `data:image/svg+xml,${encodeURIComponent(svg)}`); + if (maxWidth) { + img.width = parseInt(maxWidth); } - img.setAttribute('src', `data:image/svg+xml,${encodeURIComponent(svg)}`); - return img; + if (firstTitle) { + img.setAttribute("alt", firstTitle.textContent); + } + if (firstDesc) { + const caption = document.createElement("figcaption"); + caption.className = "sr-only"; + caption.textContent = firstDesc.textContent; + return [img, caption]; + } + return [img]; } async function makeMermaidError(text) { - let errorMessage = ''; + let errorMessage = ""; try { await mermaid.parse(text); } catch (err) { errorMessage = `${err}`; } - const result = document.createElement('details'); - const summary = document.createElement('summary'); - const pre = document.createElement('pre'); - const code = document.createElement('code'); + const result = document.createElement("details"); + result.className = 'jp-RenderedMermaid-Details'; + const summary = document.createElement("summary"); + summary.className = 'jp-RenderedMermaid-Summary'; + const pre = document.createElement("pre"); + const code = document.createElement("code"); code.innerText = text; pre.appendChild(code); summary.appendChild(pre); result.appendChild(summary); - const warning = document.createElement('pre'); + const warning = document.createElement("pre"); warning.innerText = errorMessage; result.appendChild(warning); - return result; + return [result]; } async function renderOneMarmaid(src) { @@ -7391,30 +7405,41 @@ a.anchor-link { const el = document.createElement("div"); el.style.visibility = "hidden"; document.body.appendChild(el); - let result = null; + let results = null; + let output = null; try { const { svg } = await mermaid.render(id, raw, el); - result = makeMermaidImage(svg); + results = makeMermaidImage(svg); + output = document.createElement("figure"); + results.map(output.appendChild, output); } catch (err) { parent.classList.add("jp-mod-warning"); - result = await makeMermaidError(raw); + results = await makeMermaidError(raw); + output = results[0]; } finally { el.remove(); } parent.classList.add("jp-RenderedMermaid"); - parent.appendChild(result); + parent.appendChild(output); } void Promise.all([...diagrams].map(renderOneMarmaid)); }); @@ -7510,7 +7550,6 @@ a.anchor-link { jacobi_1_check(answer) = answer_checker(answer, "d") jacobi_2_check(answer) = answer_checker(answer, "b") jacobi_3_check(answer) = answer_checker(answer, "c") -jacobi_4_check(anwswer) = answer_checker(answer, "d") @@ -7808,7 +7847,7 @@ d) The inner, but not the outer + + + + + + + + + + + + + + - - - - - - - - - - - - -