Timing
With TimerOutputs.jl loaded, enable_cache_timers! records the time spent in the cached functions of a package, in sections per function:
lookup fwraps the whole cache lookup, hit or miss;compute fwraps the call of the implementation: nested inlookup fon a miss, and on its own underNoCache;disk f, for functions with a disk cache, wraps the disk lookup after a RAM miss, withcompute fnested in it when the disk misses too.
using MemoizationKit, TimerOutputs
@cached weights(a, b, c) = a + b * c
@cached matrix(n::Int)::Matrix{Float64} = zeros(n, n)
to = TimerOutput()
enable_cache_timers!(@__MODULE__, to) # the timer defaults to TimerOutputs' global one
for i in 1:200
weights(1 + i % 6, 1 + (7i) % 6, 1 + (13i) % 6)
matrix(1 + i % 10)
end
disable_cache_timers!(@__MODULE__)
to────────────────────────────────────────────────────────────────────────────────
Time Allocations ⋯
──────────────────────────────── ───────────────────────
Tot / % measured: 1.47s / 2.5% 83.9MiB / 0.8% ⋯
────────────────── ──────────────────────────────── ───────────────────────
Section ncalls time %tot avg alloc %tot ⋯
────────────────────────────────────────────────────────────────────────────────
lookup ma… 200 23.3ms 63.6% 116μs █████▏ 473KiB 66.2% 2.36 ⋯
└─ comput… 10 2.84μs 0.0% 284ns 3.86KiB 0.5% 3 ⋯
lookup we… 200 13.3ms 36.4% 66.6μs ██▉ 242KiB 33.8% 1.21 ⋯
└─ comput… 6 290ns 0.0% 48.3ns ∅ ∅ ⋯
────────────────────────────────────────────────────────────────────────────────
2 columns omitted
Timing is off by default and adds no overhead while off. Enabling or disabling it recompiles callers and takes effect from the next top-level statement. If a function enables timers and calls cached functions in the same invocation, use invokelatest for those calls. Enabling a package again replaces its timer. Do not enable timers during precompilation.
What counts is the package that owns the function (including its submodules), not where @cached was written; modules outside packages, such as in the REPL, count separately. For instance, if MyPackage adds @cached methods to a function OtherPackage.f, then enable_cache_timers!(OtherPackage) times them, and enable_cache_timers!(MyPackage) does not. A package that wants all of its cached functions timed enables the packages that own them:
function MyPackage.enable_timers!()
enable_cache_timers!(MyPackage, TIMER)
enable_cache_timers!(OtherPackage, TIMER)
end
MyPackage.enable_timers!()
OtherPackage.f(2)
disable_cache_timers!(MyPackage)
disable_cache_timers!(OtherPackage)
TIMER────────────────────────────────────────────────────────────────────────────────
Time Allocations ⋯
──────────────────────────────── ───────────────────────
Tot / % measured: 92.5ms / 14.5% 10.1MiB / 2.3% ⋯
────────────────── ──────────────────────────────── ───────────────────────
Section ncalls time %tot avg alloc %tot ⋯
────────────────────────────────────────────────────────────────────────────────
lookup f 1 13.4ms 100.0% 13.4ms ████████ 240KiB 100.0% 240 ⋯
└─ comput… 1 290ns 0.0% 290ns ∅ ∅ ⋯
────────────────────────────────────────────────────────────────────────────────
2 columns omitted
The labels come from MemoizationKit.instrument_label, "lookup f" and "compute f" by default; overload it to pick your own:
MemoizationKit.instrument_label(::typeof(weights), ::Val{:lookup}) = "cache: weights"
MemoizationKit.instrument_label(weights, Val(:lookup))"cache: weights"