-
-
Notifications
You must be signed in to change notification settings - Fork 76
Trim allocations in dual linear problem #822
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Sorry for not providing a full self-isolated test/example here, I Let me know if I should make one. The issue here was somewhat similar to SciML/OrdinaryDiffEq.jl#2837, but with a bigger ODE (~50x50 Jacobian here, instead of 3x3 in that issue). |
| for i in p | ||
| for j in eachindex(partial_matrix) | ||
| list_cache[i][j] = partial_matrix[j][i] | ||
| @inbounds list_cache[i][j] = partial_matrix[j][i] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are these needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not required, but they gave me a non-negligible speedup, as I saw checkbounds showing up in profiling.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added it so the user should not suffer a performance penalty from library internals. I can remove them if you want to keep it safe.
This function is just shuffling data around. The optimal solution would be to avoid it altogether, but I am not sure if it's easily possible.
src/common.jl
Outdated
| end | ||
|
|
||
| # Dispatch for setting a property to f.(x) without allocating | ||
| function Base.setproperty!(cache::LinearCache, name::Symbol, x::AbstractArray, f::Function) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this used? Also, it's a pun so probably should be changed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it's used here:
| setproperty!(dc.linear_cache, sym, val, nodual_value) # maps nodual_value.(val) without allocating |
Hmm, what do you mean by it's a pun? 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a "trick" to call setproperty! while doing an in-place of the array.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But why use the name of setproperty? It's not actually a setproperty! call
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah that's true. After understanding everything better, I came up with a simpler version that just uses standard setproperty! calls and new in-place nodual_value! and partial_vals! functions.
|
I fixed the tests in The failures seemed related to nested duals, so I added a fallback that reintroduces the old-ish behavior in that case. |
test/forwarddiff_overloads.jl
Outdated
| linu = [ForwardDiff.Dual(0.0, 0.0, 0.0), ForwardDiff.Dual(0.0, 0.0, 0.0), | ||
| ForwardDiff.Dual(0.0, 0.0, 0.0)] | ||
| cache.u = linu | ||
| @test linu == cache.u |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have to move this before the solve! to make this test pass. Is that fine or am I overlooking something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No that's not good.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry this was never a problem, my local state messed up the testing. Removing this.
c091dfe to
b8aec5e
Compare
|
@ChrisRackauckas Refactored to use just standard julia> include("test/forwarddiff_overloads.jl")
Test Passed |
2447ce5 to
b2ec6ff
Compare


I am differentiating ODEs with ForwardDiff in my package.
There are a lot of allocations from
nodual_value(val)andpartial_vals(val)in LinearSolve's ForwardDiff extension. They set some cache field with a new reallocated array every time. This seems unnecessary to me.In this PR I attempt to instead use
map!and a customsetproperty!dispatch to set the elementsnodual_value(val[i])andpartial_vals(val[i])without having to reallocate the arrays. This gives me a much shorter runtime and lower memory usage:Checklist
contributor guidelines, in particular the SciML Style Guide and
COLPRAC.
Additional context
Add any other context about the problem here.