Skip to content

Commit

Permalink
Merge pull request #93 from LilithHafner/patch-1
Browse files Browse the repository at this point in the history
Remove dynamic dispatch from (General)LazyBufferCache
  • Loading branch information
ChrisRackauckas authored Jan 3, 2024
2 parents 0b194df + 8a0064d commit 6c83dde
Show file tree
Hide file tree
Showing 3 changed files with 12 additions and 19 deletions.
11 changes: 4 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,12 +218,9 @@ A `LazyBufferCache` is a `Dict`-like type for the caches which automatically def
new cache arrays on demand when they are required. The function `f` maps
`size_of_cache = f(size(u))`, which by default creates cache arrays of the same size.

Note that `LazyBufferCache` does cause a dynamic dispatch, though it is type-stable.
This gives it a ~100ns overhead, and thus on very small problems it can reduce
performance, but for any sufficiently sized calculation (e.g. >20 ODEs) this
may not be even measurable. The upside of `LazyBufferCache` is that the user does
not have to worry about potential issues with chunk sizes and such: `LazyBufferCache`
is much easier!
Note that `LazyBufferCache` is type-stable and contains no dynamic dispatch. This gives
it a ~15ns overhead. The upside of `LazyBufferCache` is that the user does not have to
worry about potential issues with chunk sizes and such: `LazyBufferCache` is much easier!

### Example

Expand All @@ -250,7 +247,7 @@ new caches on demand when they are required. The function `f` generates the cach
for the type of `u`, and subsequent indexing reuses that cache if that type of `u` has
already ben seen.

Note that `LazyBufferCache` does cause a dynamic dispatch and its return is not type-inferred.
Note that `GeneralLazyBufferCache`'s return is not type-inferred.
This means it's the slowest of the preallocation methods, but it's the most general.

### Example
Expand Down
13 changes: 5 additions & 8 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,12 +208,9 @@ A `LazyBufferCache` is a `Dict`-like type for the caches, which automatically de
new cache arrays on demand when they are required. The function `f` maps
`size_of_cache = f(size(u))`, which by default creates cache arrays of the same size.

Note that `LazyBufferCache` does cause a dynamic dispatch, though it is type-stable.
This gives it a ~100ns overhead, and thus on very small problems it can reduce
performance, but for any sufficiently sized calculation (e.g. >20 ODEs) this
may not be even measurable. The upside of `LazyBufferCache` is that the user does
not have to worry about potential issues with chunk sizes and such: `LazyBufferCache`
is much easier!
Note that `LazyBufferCache` is type-stable and contains no dynamic dispatch. This gives
it a ~15ns overhead. The upside of `LazyBufferCache` is that the user does not have to
worry about potential issues with chunk sizes and such: `LazyBufferCache` is much easier!

### Example

Expand Down Expand Up @@ -245,7 +242,7 @@ new caches on demand when they are required. The function `f` generates the cach
for the type of `u`, and subsequent indexing reuses that cache if that type of `u` has
already been seen.

Note that `LazyBufferCache` does cause a dynamic dispatch and its return is not type-inferred.
Note that `GeneralLazyBufferCache`'s return is not type-inferred.
This means it's the slowest of the preallocation methods, but it's the most general.

### Example
Expand Down Expand Up @@ -319,7 +316,7 @@ tries to do this with a bump allocator.

- See the [SciML Style Guide](https://github.com/SciML/SciMLStyle) for common coding practices and other style decisions.
- There are a few community forums:

+ The #diffeq-bridged and #sciml-bridged channels in the
[Julia Slack](https://julialang.org/slack/)
+ The #diffeq-bridged and #sciml-bridged channels in the
Expand Down
7 changes: 3 additions & 4 deletions src/PreallocationTools.jl
Original file line number Diff line number Diff line change
Expand Up @@ -204,18 +204,17 @@ same type and size `f(size(u))` (defaulting to the same size), which is allocate
needed and then cached within `b` for subsequent usage.
"""
struct LazyBufferCache{F <: Function}
bufs::Dict # a dictionary mapping types to buffers
bufs::Dict{Any, Any} # a dictionary mapping (type, size) pairs to buffers
sizemap::F
LazyBufferCache(f::F = identity) where {F <: Function} = new{F}(Dict(), f) # start with empty dict
end

# override the [] method
function Base.getindex(b::LazyBufferCache, u::T) where {T <: AbstractArray}
s = b.sizemap(size(u)) # required buffer size
buf = get!(b.bufs, (T, s)) do
get!(b.bufs, (T, s)) do
similar(u, s) # buffer to allocate if it was not found in b.bufs
end::T # declare type since b.bufs dictionary is untyped
return buf
end

# GeneralLazyBufferCache
Expand All @@ -235,7 +234,7 @@ correct using things like function barriers, then this is a general technique th
is sufficiently fast.
"""
struct GeneralLazyBufferCache{F <: Function}
bufs::Dict # a dictionary mapping types to buffers
bufs::Dict{Any, Any} # a dictionary mapping types to buffers
f::F
GeneralLazyBufferCache(f::F = identity) where {F <: Function} = new{F}(Dict(), f) # start with empty dict
end
Expand Down

0 comments on commit 6c83dde

Please sign in to comment.