-
Notifications
You must be signed in to change notification settings - Fork 2
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
Add @assign, add support for Broadcasted
objects
#64
base: main
Are you sure you want to change the base?
Conversation
Could we instead use |
Yes, my goal is to eventually allow for kernel fusion (which is what I meant with "pathway for future improvement"). However, I don't know how to use Is it just a matter of adding Maybe this is a good opportunity to add some user documentation to |
I'm happy to add more docs to Using LazyBroadcast, using LazyBroadcast: @lazy
compute_ta(state, cache, time) = @lazy @. state.ta and the result could later be used as |
Thank you! I got something to work and I managed to cluster all the
As for documentation: I am looking at LazyBroadcasts.jl and all the docs I see is the readme which does not mention This is what I think could be improved in the readme:
Here are few things I tried to get the code to work: julia> import LazyBroadcast: @lazy
julia> compute_ta(state, cache, time) = @lazy @. state.ta
ERROR: LoadError: Invalid expression given to materialize_args
Stacktrace:
[1] error(s::String)
@ Base ./error.jl:35
[2] materialize_args(expr::Expr)
@ LazyBroadcast ~/.julia/packages/LazyBroadcast/SVKU8/src/utils.jl:8
[3] transform(e::Expr)
@ LazyBroadcast ~/.julia/packages/LazyBroadcast/SVKU8/src/LazyBroadcast.jl:30 [4] _lazy_broadcasted(expr::Expr)
@ LazyBroadcast ~/.julia/packages/LazyBroadcast/SVKU8/src/LazyBroadcast.jl:43 [5] var"@lazy"(__source__::LineNumberNode, __module__::Module, expr::Any)
@ LazyBroadcast ~/.julia/packages/LazyBroadcast/SVKU8/src/LazyBroadcast.jl:54in expression starting at REPL[17]:1
julia> compute_ta(state, cache, time) = @lazy @. state
ERROR: LoadError: type Symbol has no field args
Stacktrace:
[1] getproperty(x::Symbol, f::Symbol)
@ Base ./Base.jl:37
[2] code_info(expr::Expr)
@ LazyBroadcast ~/.julia/packages/LazyBroadcast/SVKU8/src/code_lowered_single_expression.jl:10
[3] code_lowered_single_expression(expr::Expr)
@ LazyBroadcast ~/.julia/packages/LazyBroadcast/SVKU8/src/code_lowered_single_expression.jl:12
[4] transform(e::Expr)
@ LazyBroadcast ~/.julia/packages/LazyBroadcast/SVKU8/src/LazyBroadcast.jl:29 [5] _lazy_broadcasted(expr::Expr)
@ LazyBroadcast ~/.julia/packages/LazyBroadcast/SVKU8/src/LazyBroadcast.jl:43 [6] var"@lazy"(__source__::LineNumberNode, __module__::Module, expr::Any)
@ LazyBroadcast ~/.julia/packages/LazyBroadcast/SVKU8/src/LazyBroadcast.jl:54in expression starting at REPL[18]:1 I also found that these do not work: julia> a, b = [1], [2]
julia> @lazy a .= b
Expr
head: Symbol .=
args: Array{Any}((2,))
1: Symbol a
2: Symbol b
dump(expr) = nothing
Expr
head: Symbol .=
args: Array{Any}((2,))
1: Symbol a
2: Symbol b
dump(expr) = nothing
ERROR: LoadError: Uncaught edge case
Stacktrace:
[1] error(s::String)
@ Base ./error.jl:35
[2] check_restrictions(expr::Expr)
@ LazyBroadcast ~/.julia/packages/LazyBroadcast/SVKU8/src/utils.jl:48
[3] _lazy_broadcasted(expr::Expr)
@ LazyBroadcast ~/.julia/packages/LazyBroadcast/SVKU8/src/LazyBroadcast.jl:42 [4] var"@lazy"(__source__::LineNumberNode, __module__::Module, expr::Any)
@ LazyBroadcast ~/.julia/packages/LazyBroadcast/SVKU8/src/LazyBroadcast.jl:54in expression starting at REPL[12]:1
julia> @lazy @dot a = b
Expr
head: Symbol macrocall
args: Array{Any}((3,))
1: Symbol @dot
2: LineNumberNode
line: Int64 1
file: Symbol REPL[19]
3: Expr
head: Symbol =
args: Array{Any}((2,))
1: Symbol a
2: Symbol b
dump(expr) = nothing
Expr
head: Symbol macrocall
args: Array{Any}((3,))
1: Symbol @dot
2: LineNumberNode
line: Int64 1
file: Symbol REPL[19]
3: Expr
head: Symbol =
args: Array{Any}((2,))
1: Symbol a
2: Symbol b
dump(expr) = nothing
ERROR: LoadError: Uncaught edge case
Stacktrace:
[1] error(s::String)
@ Base ./error.jl:35
[2] check_restrictions(expr::Expr)
@ LazyBroadcast ~/.julia/packages/LazyBroadcast/SVKU8/src/utils.jl:48
[3] _lazy_broadcasted(expr::Expr)
@ LazyBroadcast ~/.julia/packages/LazyBroadcast/SVKU8/src/LazyBroadcast.jl:42 [4] var"@lazy"(__source__::LineNumberNode, __module__::Module, expr::Any)
@ LazyBroadcast ~/.julia/packages/LazyBroadcast/SVKU8/src/LazyBroadcast.jl:54in expression starting at REPL[19]:1 Eventually I found that it works with From here, I think I understand that the correct function to write is compute_ta(out, state, cache, time) = @lazy @. out = state.ta This seems to work in my integration test case. |
Great question. That's safe to do so long the data passed into the broadcasted objects point to the same memory. That said, it's actually very cheap to do this because all it's doing is making an instance of a struct with a bunch of pointers, so I recommend we reconstruct the object every time to be safe.
We may be able to use
Yeah, the
Yeah, I agree on all of these points. LazyBroadcast.jl was born because it was originally a bunch of utilities in MultiBroadcastFusion.jl, and I realized that they were more generally useful, so I split those utilities off into a separate package. I hadn't fully thought out the use-cases, and if/what pieces could be made more flexible (like the broken examples you showed below), so I wasn't sure how to best document things. I'll open an issue with these points.
Yeah, this is a bit technical I think, and it does seem that there are some sharp edges (I didn't expect that last example to fail). It might be easier to discuss some of this over zoom. One tricky aspect of this is that, for example,
Yeah, this will work, and that's how I'd expect it be used. There might be something we can do to remove needing |
storage[diag] = | ||
Base.Broadcast.materialize(broadcasted_expressions[diag]) |
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.
storage[diag] = | |
Base.Broadcast.materialize(broadcasted_expressions[diag]) | |
Base.Broadcast.materialize!(storage[diag], out_or_broadcasted_expr) |
This is where we can use the mutating version of materialize
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 think this would fail because storage[diag]
does not exist at this point.
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.
Ah, sorry, I wrote a message earlier but must not have hit comment
. Can we then check if isnothing(storage[diag])
and conditionally call materialize!
? materialize
will always allocate a new field
f86e803
to
ba077ff
Compare
Broadcasted
objects
`LazyBroadcast.jl` provides a way to return an unevaluated function. This is useful in two cases: 1. reduce code verbosity to handle the `isnothing(out)` case 2. allow clustering all the broadcasted expressions in a single place In turn, 2. is useful because it is the first step in fusing different broadcasted calls. This commit adds support for such functions.
Passing ClimaAtmos build: https://buildkite.com/clima/climaatmos-ci/builds/20044 I did not change the EDMF and radiation diagnostics because they are much more complex. The allocation flame graphs are failing because I added more for loops. |
Nice! Do we still need |
I am not sure. Does Fields.array2field(
cache.radiation.rrtmgp_model.face_sw_flux_dn,
axes(state.f),
) ? |
For something like that, we don't even need x = Fields.array2field(
cache.radiation.rrtmgp_model.face_sw_flux_dn,
axes(state.f),
)
bc = Base.broadcasted(identity, x) |
In fact, any diagnostic that simply returns a field, could just wrap it in |
Waiting for |
This PR does two things:
@assign
macro to help reducing code verbosity for packages that useClimaDiagnostics
.compute
functions that returnBase.Broadcast.Broadcasted
objects.Closes #5