diff --git a/dev/.documenter-siteinfo.json b/dev/.documenter-siteinfo.json index d22c51d..6808757 100644 --- a/dev/.documenter-siteinfo.json +++ b/dev/.documenter-siteinfo.json @@ -1 +1 @@ -{"documenter":{"julia_version":"1.10.5","generation_timestamp":"2024-09-12T05:30:23","documenter_version":"1.7.0"}} \ No newline at end of file +{"documenter":{"julia_version":"1.10.5","generation_timestamp":"2024-09-12T09:27:43","documenter_version":"1.7.0"}} \ No newline at end of file diff --git a/dev/LEQ/index.html b/dev/LEQ/index.html index bb333cf..a81226f 100644 --- a/dev/LEQ/index.html +++ b/dev/LEQ/index.html @@ -14,4 +14,4 @@ var myIframe = document.getElementById("notebook"); iFrameResize({log:true}, myIframe); }); - + diff --git a/dev/asp/index.html b/dev/asp/index.html index 6ea7507..008ef1b 100644 --- a/dev/asp/index.html +++ b/dev/asp/index.html @@ -14,4 +14,4 @@ var myIframe = document.getElementById("notebook"); iFrameResize({log:true}, myIframe); }); - + diff --git a/dev/getting_started_with_julia/index.html b/dev/getting_started_with_julia/index.html index 73ec815..62d0ca6 100644 --- a/dev/getting_started_with_julia/index.html +++ b/dev/getting_started_with_julia/index.html @@ -15,4 +15,4 @@ DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" MPI = "da04e1cc-30fd-572f-bb4f-1f8673147195"

Copy the contents of previous code block into a file called Project.toml and place it in an empty folder named newproject. It is important that the file is named Project.toml. You can create a new folder from the REPL with

julia> mkdir("newproject")

To install all the packages registered in this file you need to activate the folder containing your Project.toml file

(@v1.10) pkg> activate newproject

and then instantiating it

(newproject) pkg> instantiate

The instantiate command will download and install all listed packages and their dependencies in just one click.

Getting help in package mode

You can get help about a particular package operator by writing help in front of it

(@v1.10) pkg> help activate

You can get an overview of all package commands by typing help alone

(@v1.10) pkg> help

Package operations in Julia code

In some situations it is required to use package commands in Julia code, e.g., to automatize installation and deployment of Julia applications. This can be done using the Pkg package. For instance

julia> using Pkg
 julia> Pkg.status()

is equivalent to calling status in package mode.

(@v1.10) pkg> status

Creating you own package

In many situations, it is useful to create your own package, for instance, when working with a large code base, when you want to reduce compilation latency using Revise.jl, or if you want to eventually register your package and share it with others.

The simplest way of generating a package (called MyPackage) is as follows. Open Julia, go to package mode, and type

(@v1.10) pkg> generate MyPackage

This will crate a minimal package consisting of a new folder MyPackage with two files:

Tip

This approach only generates a very minimal package. To create a more sophisticated package skeleton (including unit testing, code coverage, readme file, licence, etc.) use PkgTemplates.jl or BestieTemplate.jl. The later one is developed in Amsterdam at the Netherlands eScience Center.

You can add dependencies to the package by activating the MyPackage folder in package mode and adding new dependencies as always:

(@v1.10) pkg> activate MyPackage
 (MyPackage) pkg> add MPI

This will add MPI to your package dependencies.

Using your own package

To use your package you first need to add it to a package environment of your choice. This is done by changing to package mode and typing develop followed by the path to the folder containing the package. For instance:

(@v1.10) pkg> develop MyPackage
Note

You do not need to "develop" your package if you activated the package folder MyPackage.

Now, we can go back to standard Julia mode and use it as any other package:

using MyPackage
-MyPackage.greet()

Here, we just called the example function defined in MyPackage/src/MyPackage.jl.

Conclusion

We have learned the basics of how to work with Julia, including how to run serial and parallel code, and how to manage, create, and use Julia packages. This knowledge will allow you to follow the course effectively! If you want to further dig into the topics we have covered here, you can take a look at the following links:

+MyPackage.greet()

Here, we just called the example function defined in MyPackage/src/MyPackage.jl.

Conclusion

We have learned the basics of how to work with Julia, including how to run serial and parallel code, and how to manage, create, and use Julia packages. This knowledge will allow you to follow the course effectively! If you want to further dig into the topics we have covered here, you can take a look at the following links:

diff --git a/dev/index.html b/dev/index.html index a99fded..ab96b41 100644 --- a/dev/index.html +++ b/dev/index.html @@ -2,4 +2,4 @@ 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()

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 5e22ced..af0a4df 100644 --- a/dev/jacobi_2D/index.html +++ b/dev/jacobi_2D/index.html @@ -14,4 +14,4 @@ var myIframe = document.getElementById("notebook"); iFrameResize({log:true}, myIframe); }); - + diff --git a/dev/jacobi_method/index.html b/dev/jacobi_method/index.html index 4a10da9..1a458f3 100644 --- a/dev/jacobi_method/index.html +++ b/dev/jacobi_method/index.html @@ -14,4 +14,4 @@ var myIframe = document.getElementById("notebook"); iFrameResize({log:true}, myIframe); }); - + diff --git a/dev/julia_async.ipynb b/dev/julia_async.ipynb index 0862493..b265bbd 100644 --- a/dev/julia_async.ipynb +++ b/dev/julia_async.ipynb @@ -283,7 +283,7 @@ "metadata": {}, "outputs": [], "source": [ - "fun = () -> compute_π(4_000_000_000)\n", + "fun = () -> @show compute_π(4_000_000_000)\n", "t = Task(fun)" ] }, @@ -359,7 +359,7 @@ "metadata": {}, "outputs": [], "source": [ - "fun = () -> compute_π_yield(3_000_000_000)\n", + "fun = () -> @show compute_π_yield(3_000_000_000)\n", "t = Task(fun)\n", "schedule(t)" ] @@ -729,6 +729,18 @@ "take!(chnl)" ] }, + { + "cell_type": "markdown", + "id": "8a1ef849", + "metadata": {}, + "source": [ + "In summary:\n", + "\n", + "- `put!` will wait for a `take!` if there is not space left in the channel's buffer.\n", + "- `take!` will wait for a `put!` if there is no data to be consumed in the channel.\n", + "- Both `put!` and `take!` will raise an error if the channel is closed." + ] + }, { "cell_type": "markdown", "id": "9ddd66ca", @@ -746,7 +758,7 @@ "metadata": {}, "outputs": [], "source": [ - "t = @elapsed compute_π(100_000_000)" + "t = @elapsed @show compute_π(140_000_000)" ] }, { @@ -772,7 +784,7 @@ "outputs": [], "source": [ "@time for i in 1:10\n", - " compute_π(100_000_000)\n", + " @show compute_π(140_000_000)\n", "end" ] }, @@ -810,7 +822,7 @@ "outputs": [], "source": [ "@time for i in 1:10\n", - " @async compute_π(100_000_000)\n", + " @async @show compute_π(140_000_000)\n", "end" ] }, @@ -847,7 +859,7 @@ "outputs": [], "source": [ "@time @sync for i in 1:10\n", - " @async compute_π(100_000_000)\n", + " @async @show compute_π(140_000_000)\n", "end" ] }, @@ -970,6 +982,22 @@ "" ] }, + { + "cell_type": "markdown", + "id": "dfab0c90", + "metadata": {}, + "source": [ + "## Summary\n", + "\n", + "In order to start \"thinking in parallel\" you first need to be familiar with concepts of asynchronous programming, in particular tasks. In this notebook, we have seen the basics of working with tasks. Some key points to remember:\n", + "\n", + "- How to create, schedule, and fetch from a task.\n", + "- Tasks run asynchronously, but not in parallel. You can have a single core CPU and still be able to work with several tasks.\n", + "- Channels are used to communicate data between tasks.\n", + "- Adding data (`put!`) or taking data (`take!`) from a channel might wait depending on the channel state. Be careful to avoid dead locks.\n", + "\n" + ] + }, { "cell_type": "markdown", "id": "a5d3730b", diff --git a/dev/julia_async/index.html b/dev/julia_async/index.html index 77c0708..e26fe22 100644 --- a/dev/julia_async/index.html +++ b/dev/julia_async/index.html @@ -14,4 +14,4 @@ var myIframe = document.getElementById("notebook"); iFrameResize({log:true}, myIframe); }); - + diff --git a/dev/julia_async_src/index.html b/dev/julia_async_src/index.html index 97cd238..1120cfd 100644 --- a/dev/julia_async_src/index.html +++ b/dev/julia_async_src/index.html @@ -7857,7 +7857,7 @@ a.anchor-link {
In [ ]:
-
fun = () -> compute_π(4_000_000_000)
+
fun = () -> @show compute_π(4_000_000_000)
 t = Task(fun)
 
@@ -7956,7 +7956,7 @@ a.anchor-link { +
diff --git a/dev/julia_distributed_src/index.html b/dev/julia_distributed_src/index.html index c55e207..d24c34e 100644 --- a/dev/julia_distributed_src/index.html +++ b/dev/julia_distributed_src/index.html @@ -7586,25 +7586,25 @@ a.anchor-link { msg = """ We send the matrix (16 entries) and then we receive back the result (1 extra integer). Thus, the total number of transferred integers in 17. """ - display(msg) + println(msg) end function why_q2() msg = """ Even though we only use a single entry of the matrix in the remote worker, the entire matrix is captured and sent to the worker. Thus, we will transfer 17 integers like in Question 1. """ - display(msg) + println(msg) end function why_q3() msg = """ The value of x will still be zero since the worker receives a copy of the matrix and it modifies this copy, not the original one. """ - display(msg) + println(msg) end function why_q4() msg = """ In this case, the code a[2]=2 is executed in the main process. Since the matrix is already in the main process, it is not needed to create and send a copy of it. Thus, the code modifies the original matrix and the value of x will be 2. """ - display(msg) + println(msg) end println("🥳 Well done! ")
@@ -7677,15 +7677,25 @@ a.anchor-link { -
+
+ +
+
@@ -8178,8 +8188,8 @@ bottlenecks. Being aware of the data we are moving when using functions such as
proc = 4
 a = rand(10,10)
 b = rand(10,10)
-ftr = remotecall(+,proc,a,b)
-fetch(ftr);
+ftr = remotecall(+,proc,a,b) # Send
+fetch(ftr); # Receive
 
@@ -8208,8 +8218,8 @@ bottlenecks. Being aware of the data we are moving when using functions such as a = rand(10,10) b = rand(10,10) fun = () -> a+b -ftr = remotecall(fun,proc) -fetch(ftr); +ftr = remotecall(fun,proc) # Send +fetch(ftr); # Receive @@ -8222,7 +8232,7 @@ bottlenecks. Being aware of the data we are moving when using functions such as
-

Data movement with remote channels

Another way of moving data between processes is to use remote channels. Their usage is very similar to conventional channels for moving data between tasks, but there are some important differences. In the next cell, we create a remote channel. Process 4 puts several values and closes the channel. Like for conventional channels, calls to put! are blocking, but next cell is not blocking the master process since the call to put! runs asynchronously on process 4.

+

Data movement with remote channels

Another way of moving data between processes is to use remote channels. Their usage is very similar to conventional channels for moving data between tasks, but there are some important differences. In the next cell, we create a remote channel. Process 4 puts several values and closes the channel. Like for conventional channels, calls to put! might block, but next cell is not blocking the master process since the call to put! runs asynchronously on process 4.

@@ -8388,6 +8398,9 @@ bottlenecks. Being aware of the data we are moving when using functions such as

Remote channels are also iterable

As with conventional channels, remote channels can be iterated. Let's repeat the example above.

+
+Note: In old Julia versions, it was not possible to iterate over remote channels. If the cells below do not work, update Julia to a recent version. +
diff --git a/dev/julia_intro/index.html b/dev/julia_intro/index.html index 1274fdf..87a2952 100644 --- a/dev/julia_intro/index.html +++ b/dev/julia_intro/index.html @@ -14,4 +14,4 @@ var myIframe = document.getElementById("notebook"); iFrameResize({log:true}, myIframe); }); - + diff --git a/dev/julia_jacobi/index.html b/dev/julia_jacobi/index.html index 28d474e..4575da8 100644 --- a/dev/julia_jacobi/index.html +++ b/dev/julia_jacobi/index.html @@ -14,4 +14,4 @@ var myIframe = document.getElementById("notebook"); iFrameResize({log:true}, myIframe); }); - + diff --git a/dev/julia_mpi/index.html b/dev/julia_mpi/index.html index 4dbab50..ad00a4b 100644 --- a/dev/julia_mpi/index.html +++ b/dev/julia_mpi/index.html @@ -14,4 +14,4 @@ var myIframe = document.getElementById("notebook"); iFrameResize({log:true}, myIframe); }); - + diff --git a/dev/julia_tutorial/index.html b/dev/julia_tutorial/index.html index a7d20ab..d665a32 100644 --- a/dev/julia_tutorial/index.html +++ b/dev/julia_tutorial/index.html @@ -14,4 +14,4 @@ var myIframe = document.getElementById("notebook"); iFrameResize({log:true}, myIframe); }); - + diff --git a/dev/matrix_matrix/index.html b/dev/matrix_matrix/index.html index 1fc0f7d..5bccb5b 100644 --- a/dev/matrix_matrix/index.html +++ b/dev/matrix_matrix/index.html @@ -14,4 +14,4 @@ var myIframe = document.getElementById("notebook"); iFrameResize({log:true}, myIframe); }); - + diff --git a/dev/mpi_collectives/index.html b/dev/mpi_collectives/index.html index 4041584..4d56828 100644 --- a/dev/mpi_collectives/index.html +++ b/dev/mpi_collectives/index.html @@ -14,4 +14,4 @@ var myIframe = document.getElementById("notebook"); iFrameResize({log:true}, myIframe); }); - + diff --git a/dev/mpi_tutorial/index.html b/dev/mpi_tutorial/index.html index 45f2f36..72c1027 100644 --- a/dev/mpi_tutorial/index.html +++ b/dev/mpi_tutorial/index.html @@ -14,4 +14,4 @@ var myIframe = document.getElementById("notebook"); iFrameResize({log:true}, myIframe); }); - + diff --git a/dev/notebook-hello/index.html b/dev/notebook-hello/index.html index 07375b1..845ef4a 100644 --- a/dev/notebook-hello/index.html +++ b/dev/notebook-hello/index.html @@ -14,4 +14,4 @@ var myIframe = document.getElementById("notebook"); iFrameResize({log:true}, myIframe); }); - + diff --git a/dev/pdes/index.html b/dev/pdes/index.html index 5a9dc9f..9a3acc7 100644 --- a/dev/pdes/index.html +++ b/dev/pdes/index.html @@ -14,4 +14,4 @@ var myIframe = document.getElementById("notebook"); iFrameResize({log:true}, myIframe); }); - + diff --git a/dev/solutions/index.html b/dev/solutions/index.html index d848c03..47dd132 100644 --- a/dev/solutions/index.html +++ b/dev/solutions/index.html @@ -14,4 +14,4 @@ var myIframe = document.getElementById("notebook"); iFrameResize({log:true}, myIframe); }); - + diff --git a/dev/solutions_for_all_notebooks/index.html b/dev/solutions_for_all_notebooks/index.html index 22f9c1b..5b5a920 100644 --- a/dev/solutions_for_all_notebooks/index.html +++ b/dev/solutions_for_all_notebooks/index.html @@ -172,4 +172,4 @@ end

« Jacobi method
+end diff --git a/dev/tsp/index.html b/dev/tsp/index.html index 8697ae0..78a673f 100644 --- a/dev/tsp/index.html +++ b/dev/tsp/index.html @@ -14,4 +14,4 @@ var myIframe = document.getElementById("notebook"); iFrameResize({log:true}, myIframe); }); - +