Profiling, Benchmarking & Optimization
Chairmarks.jl is a faster alternative (@b f(x)).
24.1 Timing
Chairmarks.jl is a faster alternative (@b f(x)).
@time sum(rand(10^7)) # time + allocations (first call includes compilation)
@timev f(x) # verbose
@elapsed f(x); @allocated f(x)
@time_imports using DataFrames # load time per package
using BenchmarkTools
@btime sum($x) # $ interpolates to avoid global-variable overhead
@benchmark sort($x) # full statistics (min, median, allocations)
b = @benchmarkable f($x) setup=(x = rand(100)); run(b)24.2 Profiling
using Profile
@profile for _ in 1:100; f(x); end
Profile.print(format=:flat, sortedby=:count)
Profile.clear()
using ProfileView; @profview f(x) # flame graph (also built into the VS Code extension)
@profview_allocs f(x) # allocation profiler (1.8+)
using PProf; pprof() # Google pprof web UI24.3 SIMD, loops & low-level optimization
Check vectorization with @code_llvm mysum(rand(100)) (look for <4 x double>).
function mysum(x)
s = zero(eltype(x))
@inbounds @simd for i in eachindex(x)
s += x[i]
end
s
end
using LoopVectorization # @turbo for aggressive vectorization
@turbo for i in eachindex(x); y[i] = sin(x[i]); end24.4 Memory & allocations
Look for unexpected allocations with @btime or --track-allocation=user.
Reuse buffers, use mul!, ldiv!, broadcasting with .=.
Immutable isbits structs live on the stack / inline in arrays.
GC.gc(), Base.summarysize(obj), varinfo().
Bumper.jl for arena allocation in hot loops.
24.5 Case study: a 100× speed-up
# Slow: global, untyped, allocating
data = rand(10^6)
function slow()
result = []
for x in data
push!(result, x^2)
end
sum(result)
end
# Fast: argument, typed result, no temporaries
fast(data) = sum(abs2, data)
@btime fast($data)