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.83s / 4.2% 83.4MiB / 1.3% ⋯
────────────────── ──────────────────────────────── ───────────────────────
Section ncalls time %tot avg alloc %tot ⋯
────────────────────────────────────────────────────────────────────────────────
lookup ma… 200 48.8ms 63.6% 244μs █████▏ 654KiB 60.7% 3.27 ⋯
└─ comput… 10 3.00μs 0.0% 300ns 3.86KiB 0.4% 3 ⋯
lookup we… 200 28.0ms 36.4% 140μs ██▉ 423KiB 39.3% 2.11 ⋯
└─ comput… 6 330ns 0.0% 55.0ns ∅ ∅ ⋯
────────────────────────────────────────────────────────────────────────────────
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: 110ms / 24.8% 9.92MiB / 4.1% ⋯
────────────────── ──────────────────────────────── ───────────────────────
Section ncalls time %tot avg alloc %tot ⋯
────────────────────────────────────────────────────────────────────────────────
lookup f 1 27.3ms 100.0% 27.3ms ████████ 422KiB 100.0% 422 ⋯
└─ comput… 1 181ns 0.0% 181ns ∅ ∅ ⋯
────────────────────────────────────────────────────────────────────────────────
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"