Configuration

Default cache settings are read with Preferences.jl from LocalPreferences.toml, next to the active project.

Settings

KeyValuesDefaultMeaning
maxsizeinteger ≥ 010000limit of a function's cache, all signatures together, in entries or bytes (see measure)
measure"count" or "bytes""count"count entries, or measure values with MemoizationKit.cachesize
container"ClockCache" or "LRU""ClockCache"container of the default CacheStyle; only in the [MemoizationKit] section
disktrue or falsetruewhether the disk cache of a function with a DiskCacheStyle is used
disk_patha directory"" (a scratch space)where the disk caches are stored

Where settings come from

Settings are looked up per function, in this order (first match wins):

  1. runtime calls: set_cache_size!;
  2. the function's own section, [<Package>.MemoizationKit.<function>];
  3. the section of the package that owns the function, [<Package>.MemoizationKit];
  4. MemoizationKit's own section, [MemoizationKit];
  5. the built-in defaults above.

The package that owns a function is the package of the module that defines it, parentmodule(typeof(f)). For a function extended by several packages, that is the package that defines the function, not the ones that add cached methods to it.

# LocalPreferences.toml
[MemoizationKit]
maxsize = 10000
container = "LRU"

[MyPackage.MemoizationKit]
maxsize = 50000

[MyPackage.MemoizationKit.expensive]
measure = "bytes"
maxsize = 2_000_000_000

Unknown keys and invalid values are ignored with a warning.

When changes take effect

  • disk and disk_path are read when a function first uses its disk cache in the session.
  • maxsize and measure are read when a function's first cache is created, so a change applies to functions that have not been called yet in the current session, and to every function after a restart.
  • container is a compile-time preference, because it selects the default CacheStyle. Changing it recompiles MemoizationKit on the next start. GlobalCache() and TaskLocalCache() use this container, so CacheStyle methods that return them follow the preference.

Use set_cache_preferences! to write the sections, which merges with what is already there:

using MemoizationKit
set_cache_preferences!(; maxsize = 50_000) # [MemoizationKit]
println(read("LocalPreferences.toml", String))
[MemoizationKit]
maxsize = 50000

For functions defined in your package, use package or function settings:

set_cache_preferences!(MyPackage; measure = "bytes")       # [MyPackage.MemoizationKit]
set_cache_preferences!(MyPackage.expensive; maxsize = 1000) # [MyPackage.MemoizationKit.expensive]
println(read("LocalPreferences.toml", String))
[MemoizationKit]
maxsize = 50000

[MyPackage.MemoizationKit]
measure = "bytes"

    [MyPackage.MemoizationKit.expensive]
    maxsize = 1000

Remove a setting by passing nothing:

set_cache_preferences!(MyPackage.expensive; maxsize = nothing)
println(read("LocalPreferences.toml", String))
[MemoizationKit]
maxsize = 50000

[MyPackage.MemoizationKit]
measure = "bytes"

Measuring sizes

With measure = "bytes", every cached value is measured once, on insertion, by MemoizationKit.cachesize, which defaults to Base.summarysize. That traverses the whole value, which can be slow for large nested values, and counts memory shared between values once per value. Keys and container overhead are excluded; this is a value budget, not a limit on total process memory. Overload it for your own types:

using MemoizationKit

struct MyTensor
    data::Vector{Float64}
end
MemoizationKit.cachesize(t::MyTensor) = sizeof(t.data);

MemoizationKit.cachesize(MyTensor(zeros(10)))

# output

80