1
0
Fork 0
mirror of https://gitlab.rlp.net/mobitar/julia_course.git synced 2024-11-16 13:28:10 +00:00

Added performance demos

This commit is contained in:
Mo8it 2022-03-31 03:18:18 +02:00
parent f748185f62
commit 7ad274779b

View file

@ -4,6 +4,12 @@
using Markdown using Markdown
using InteractiveUtils using InteractiveUtils
# ╔═╡ 7a9ccfbc-bd2e-41d0-be5d-dea04b90d397
using BenchmarkTools
# ╔═╡ 8b1dfee2-bd8b-4d23-b9f8-9406002e0eaa
using Random
# ╔═╡ 1fb7d9af-333e-44f2-b693-09ff97937d4c # ╔═╡ 1fb7d9af-333e-44f2-b693-09ff97937d4c
# Oh, no, you found my secret! 😱 # Oh, no, you found my secret! 😱
# Don't change this hidden cell! # Don't change this hidden cell!
@ -135,8 +141,164 @@ If you want syntax highlighting in your REPL, add the package `OhMyREPL` to your
https://kristofferc.github.io/OhMyREPL.jl/latest/installation/ https://kristofferc.github.io/OhMyREPL.jl/latest/installation/
""" """
# ╔═╡ d21771de-272e-4d57-8c76-c75be709ad0a # ╔═╡ 0e53e4ee-16a7-47ef-9992-77cbfd1ed258
md"""
# Benchmarking
"""
# ╔═╡ d86e4a2f-e737-49a4-bc16-a149e81785bd
function normal_for_loop(N)
factorials = zeros(BigInt, N)
for i in 1:N
factorials[i] = factorial(big(i))
end
return
end
# ╔═╡ bc777c73-9573-41c3-8ab5-843335539f96
N = 5000
# ╔═╡ 55d1d616-b6ee-40dd-a0ed-6274a98b1e73
@benchmark normal_for_loop(N)
# ╔═╡ 00c27927-9c72-417a-862f-9b66318d9751
@btime normal_for_loop(N)
# ╔═╡ d21771de-272e-4d57-8c76-c75be709ad0a
md"""
# Multithreading
Julia is built as a modern language with parallel and asynchronous programming in mind.
You can use run Julia code on the GPU, on multiple CPU threads (multithreading) and with multiple processes (multiprocessing).
In this course, only multithreading will be presented.
The easiest way to use multithreading in Julia is by letting a `for` loop run on multiple threads. This can be achieved by only addy the macro `@threads` before the `for` loop.
Before trying to use multithreading, make sure that you launch Julia with multiple threads. To do so, run the following to launch Julia:
julia -t auto
You can append `--project=.` and other arguments to it.
`-t` is an alias to `--threads`. `auto` automatically determins how many threads your PC supports. You can also replace `auto` by the number of threads that you want to use. This number can not be bigger than the number of threads that your computer supports.
"""
# ╔═╡ 2cf5f891-8d8f-477d-8ef1-9b4b9480d477
# Show available number of threads
# If this is 1, then you can not use multithreading!
# If your PC has only one core and one thread, then you can do nothing about it.
# Otherwise, you have to tell Julia how many threads to use with the `-t` argument.
Threads.nthreads()
# ╔═╡ 76866972-0290-4e33-93de-b6128ba11994
md"""
## `@threads`
"""
# ╔═╡ cacc94b4-21e0-410e-acaa-80e37b447f94
function multithreaded_for_loop(N)
factorials = zeros(BigInt, N)
Threads.@threads for i in 1:N
factorials[i] = factorial(big(i))
end
return
end
# ╔═╡ a3029480-bcdc-44f3-b504-8bd3bf3aa14d
@btime multithreaded_for_loop(N)
# ╔═╡ f141dbb4-bdc5-4f16-8d97-fc0a3d5981f2
function shuffle_multithreaded_for_loop(N)
factorials = zeros(BigInt, N)
Threads.@threads for i in shuffle(1:N)
factorials[i] = factorial(big(i))
end
return
end
# ╔═╡ e9dcda88-1eef-4c0a-99b2-12eaec56186b
@btime shuffle_multithreaded_for_loop(N)
# ╔═╡ 009bb2e8-f03e-40f7-a66b-166dc6a1962d
md"""
## Thread safety
"""
# ╔═╡ dd5e5073-be29-47e7-91c5-9e47c35f905c
function thread_unsafe()
N = 100000
var = 0
Threads.@threads for i in 1:N
var += 1
end
return var
end
# ╔═╡ 4554cbf0-36f5-45c6-a966-ad18b1592a60
# Run this cell multiple times.
# The output is random 🤯
thread_unsafe()
# ╔═╡ ec08a80c-8886-4312-9481-5c89951681e1
function thread_unsafe_sum(N)
sum_of_sums = 0
Threads.@threads for i in 1:N
sum_of_sums = sum(1:i)
end
return sum_of_sums
end
# ╔═╡ 3b5d9f7c-1fc9-4e85-8c07-8b5709895a10
N2 = 1000000
# ╔═╡ fbd2423b-aaea-47a7-a3cf-537860e11a93
thread_unsafe_sum(N2)
# ╔═╡ e65ad214-33ba-4d08-81f0-5f98022a9f78
function thread_safe_sum(N)
sums = zeros(Int64, N)
Threads.@threads for i in 1:N
sums[i] = sum(1:i)
end
return sum(sums)
end
# ╔═╡ 8ad3daa6-d221-4ff7-9bc2-8e8a66bdd8c7
@btime thread_safe_sum(N2)
# ╔═╡ 95dffc7f-3393-487e-8521-c96291cdc7bf
typemax(Int64)
# ╔═╡ ebd3a9d9-7a12-4001-9b53-913f664fb1c8
function shuffle_safe_thread_sum(N)
sums = zeros(Int64, N)
Threads.@threads for i in shuffle(1:N)
sums[i] = sum(1:i)
end
return sum(sums)
end
# ╔═╡ ddd2409e-de34-4eb9-a0b7-e10cc6c0ce9f
# This is worse than the version without shuffeling.
# In this case, shuffling is too expensive compared with its benefit
# Especially for multithreading, there is no silver bullet.
# Always benchmark! This is the only method to make sure that an "optimization" indeed an optimization is
@btime shuffle_safe_thread_sum(N2)
# ╔═╡ 09f71a9e-6798-492f-98df-45087d0c4c8b # ╔═╡ 09f71a9e-6798-492f-98df-45087d0c4c8b
md""" md"""
@ -146,15 +308,94 @@ Julia has a focus on high performance. But if you don't pay attention, you might
In this section, tools and tips for performance optimization in Julia are presented. In this section, tools and tips for performance optimization in Julia are presented.
""" """
# ╔═╡ 2a24aebc-0654-4d00-bdab-627a8e1a75f2 # ╔═╡ 6509dddd-ff17-49db-8e5e-fcea1ef0026c
N3 = 1000000
# ╔═╡ 2a24aebc-0654-4d00-bdab-627a8e1a75f2
begin
sin_vals = []
function global_allocating_access(N)
for i in 1:N
push!(sin_vals, sin(i))
end
return
end
@btime global_allocating_access(N3)
end
# ╔═╡ 56058ab1-4ea2-479d-88f9-5da6ac8c39c2
begin
typed_sin_vals = Float64[]
function typed_global_allocating_access(N)
for i in 1:N
push!(typed_sin_vals, sin(i))
end
return
end
@btime typed_global_allocating_access(N3)
end
# ╔═╡ ef164e7c-668a-4312-83f1-687ca7d4c8f9
begin
preallocated_sin_vals = zeros(Float64, N3)
function global_preallocated_access(N)
for i in 1:N
preallocated_sin_vals[i] = sin(i)
end
return
end
@btime global_preallocated_access(N3)
end
# ╔═╡ ebc621b5-3aa3-4cf7-bcdf-e4c5fbb79f50
begin
passed_preallocated_sin_vals = zeros(Float64, N3)
function local_preallocated_access(N, sin_vals)
for i in 1:N
sin_vals[i] = sin(i)
end
return
end
@btime local_preallocated_access(N3, passed_preallocated_sin_vals)
end
# ╔═╡ afcc15de-81e0-484f-80cf-3d805517c6e8
# Here, the difference of preallocation is clearer
begin
passed_sin_vals = Float64[]
function local_access(N, sin_vals)
for i in 1:N
push!(sin_vals, sin(i))
end
return
end
@btime local_access(N3, passed_sin_vals)
end
# ╔═╡ 00000000-0000-0000-0000-000000000001 # ╔═╡ 00000000-0000-0000-0000-000000000001
PLUTO_PROJECT_TOML_CONTENTS = """ PLUTO_PROJECT_TOML_CONTENTS = """
[deps] [deps]
BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
PlutoUI = "7f904dfe-b85e-4ff6-b463-dae2292396a8" PlutoUI = "7f904dfe-b85e-4ff6-b463-dae2292396a8"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
[compat] [compat]
BenchmarkTools = "~1.3.1"
PlutoUI = "~0.7.38" PlutoUI = "~0.7.38"
""" """
@ -180,6 +421,12 @@ uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33"
[[deps.Base64]] [[deps.Base64]]
uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
[[deps.BenchmarkTools]]
deps = ["JSON", "Logging", "Printf", "Profile", "Statistics", "UUIDs"]
git-tree-sha1 = "4c10eee4af024676200bc7752e536f858c6b8f93"
uuid = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
version = "1.3.1"
[[deps.ColorTypes]] [[deps.ColorTypes]]
deps = ["FixedPointNumbers", "Random"] deps = ["FixedPointNumbers", "Random"]
git-tree-sha1 = "024fe24d83e4a5bf5fc80501a314ce0d1aa35597" git-tree-sha1 = "024fe24d83e4a5bf5fc80501a314ce0d1aa35597"
@ -298,6 +545,10 @@ version = "0.7.38"
deps = ["Unicode"] deps = ["Unicode"]
uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7"
[[deps.Profile]]
deps = ["Printf"]
uuid = "9abbd945-dff8-562f-b5e8-e1ebf5ef1b79"
[[deps.REPL]] [[deps.REPL]]
deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"]
uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"
@ -369,9 +620,38 @@ uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0"
# ╟─7f45c502-0909-42df-b93d-384f743df6a9 # ╟─7f45c502-0909-42df-b93d-384f743df6a9
# ╟─f23ad33d-af1d-40c2-9efc-17ef8c4d1fb8 # ╟─f23ad33d-af1d-40c2-9efc-17ef8c4d1fb8
# ╟─6340aec8-6f77-4a30-8815-ce76ddecd6e8 # ╟─6340aec8-6f77-4a30-8815-ce76ddecd6e8
# ╠═d21771de-272e-4d57-8c76-c75be709ad0a # ╠═0e53e4ee-16a7-47ef-9992-77cbfd1ed258
# ╠═7a9ccfbc-bd2e-41d0-be5d-dea04b90d397
# ╠═d86e4a2f-e737-49a4-bc16-a149e81785bd
# ╠═bc777c73-9573-41c3-8ab5-843335539f96
# ╠═55d1d616-b6ee-40dd-a0ed-6274a98b1e73
# ╠═00c27927-9c72-417a-862f-9b66318d9751
# ╟─d21771de-272e-4d57-8c76-c75be709ad0a
# ╠═2cf5f891-8d8f-477d-8ef1-9b4b9480d477
# ╟─76866972-0290-4e33-93de-b6128ba11994
# ╠═cacc94b4-21e0-410e-acaa-80e37b447f94
# ╠═a3029480-bcdc-44f3-b504-8bd3bf3aa14d
# ╠═8b1dfee2-bd8b-4d23-b9f8-9406002e0eaa
# ╠═f141dbb4-bdc5-4f16-8d97-fc0a3d5981f2
# ╠═e9dcda88-1eef-4c0a-99b2-12eaec56186b
# ╠═009bb2e8-f03e-40f7-a66b-166dc6a1962d
# ╠═dd5e5073-be29-47e7-91c5-9e47c35f905c
# ╠═4554cbf0-36f5-45c6-a966-ad18b1592a60
# ╠═ec08a80c-8886-4312-9481-5c89951681e1
# ╠═3b5d9f7c-1fc9-4e85-8c07-8b5709895a10
# ╠═fbd2423b-aaea-47a7-a3cf-537860e11a93
# ╠═e65ad214-33ba-4d08-81f0-5f98022a9f78
# ╠═8ad3daa6-d221-4ff7-9bc2-8e8a66bdd8c7
# ╠═95dffc7f-3393-487e-8521-c96291cdc7bf
# ╠═ebd3a9d9-7a12-4001-9b53-913f664fb1c8
# ╠═ddd2409e-de34-4eb9-a0b7-e10cc6c0ce9f
# ╟─09f71a9e-6798-492f-98df-45087d0c4c8b # ╟─09f71a9e-6798-492f-98df-45087d0c4c8b
# ╠═6509dddd-ff17-49db-8e5e-fcea1ef0026c
# ╠═2a24aebc-0654-4d00-bdab-627a8e1a75f2 # ╠═2a24aebc-0654-4d00-bdab-627a8e1a75f2
# ╠═56058ab1-4ea2-479d-88f9-5da6ac8c39c2
# ╠═ef164e7c-668a-4312-83f1-687ca7d4c8f9
# ╠═ebc621b5-3aa3-4cf7-bcdf-e4c5fbb79f50
# ╠═afcc15de-81e0-484f-80cf-3d805517c6e8
# ╟─1fb7d9af-333e-44f2-b693-09ff97937d4c # ╟─1fb7d9af-333e-44f2-b693-09ff97937d4c
# ╟─00000000-0000-0000-0000-000000000001 # ╟─00000000-0000-0000-0000-000000000001
# ╟─00000000-0000-0000-0000-000000000002 # ╟─00000000-0000-0000-0000-000000000002