We will learn
Click on a cell and press Shift + Enter
1+3
4*5
foo() = "Well done!"
foo()
] add BenchmarkTools DataFrames PyCall Conda Test
? print
# ✍️ Exercise 1
function sum_hand(a)
# TODO
end
Next, you can test your solution. You can use the Julia macro @test which is provided in the Test package.
using Test
a = rand(5)
@test sum_hand(a) ≈ sum(a)
In order to track the performance of your code, it is useful to time the execution of single functions. In Julia, the most conventional way of measuring the computation time is the macro @time.
a = rand(10^7);
@time sum_hand(a)
Note that @time also measures the compile time of a function if it's the first call to that function. So make sure to run @time twice on a freshly compiled function in order to get a more meaningful result.
Now in order to benchmark our code, we need to run it several times. To do this we can call our code in a for-loop and gather the runtimes using the Julia macro @elapsed. This measures the runtime of an expression in seconds, just as the @time macro, only @elapsed discards the result of the computation and returns the elapsed time instead.
@elapsed sum_hand(a)
The BenchmarkTools extension package provides useful macros for sampling runtimes automatically.
using BenchmarkTools
First of all, the @benchmark macro runs the code multiple times and gives out a lot of details: the minimum and maximum time, mean time, median time, number of samples taken, memory allocations, etc.
bch_sum_hand = @benchmark sum_hand($a)
For quick sanity checks, one can use the @btime macro, which is a convenience wrapper around @benchmark. It returns only the minimum execution time and memory allocations.
@btime sum_hand($a)
Similar to the @elapsed macro, BenchmarkTool's @belapsed discards the return value of the function and instead returns the minimum runtime in seconds.
@belapsed sum_hand($a)
As opposed to @time and @elapsed, @btime and @belapsed run the code several times and return the minimum runtime, thus eliminating possible compilation times from the measurement.
bch_sum = @benchmark sum($a)
using PyCall
py"""
def sum_py_hand(A):
s = 0.0
for a in A:
s += a
return s
"""
sum_py_hand = py"sum_py_hand"
@test sum(a) ≈ sum_py_hand(a)
bch_sum_py_hand = @benchmark sum_py_hand($a)
using Conda
numpy = pyimport("numpy")
sum_numpy = numpy["sum"]
@test sum_numpy(a) ≈ sum(a)
bch_sum_numpy = @benchmark sum_numpy($a)
timings = [bch_sum_hand,bch_sum,bch_sum_py_hand,bch_sum_numpy]
methods = ["sum_hand","sum","sum_py_hand","sum_numpy"]
using DataFrames
df = DataFrame(method=methods,time=timings)
# ✍️ Exercise 3
function sum_hand_fast(a)
s = 0.0
@simd for ai in a
s += ai
end
s
end
@test sum_hand_fast(a) ≈ sum(a)
@benchmark sum_hand_fast($a)
We will look into the third point in a later section of this course.
function sum_hand(a)
s = 0.0
for ai in a
s += ai
end
s
end
using Statistics
a = rand(10^7)
num_it = 15
runtimes = zeros(num_it)
for i in 1:num_it
runtimes[i] = @elapsed sum_hand(a)
end
@show mean(runtimes)
@show std(runtimes)
@show minimum(runtimes)
@show maximum(runtimes);
# ✍️ Exercise 3
function sum_hand_fast(a)
s = 0.0
@simd for ai in a
s += ai
end
s
end