-
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 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 |
ba077ff
to
34bf23f
Compare
Broadcasted
objects
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 |
cd7e940
to
93ec15f
Compare
Broadcasted
objectsBroadcasted
objects
9e5b5bb
to
540752b
Compare
Passing Atmos build: https://buildkite.com/clima/climaatmos-ci/builds/23646 |
a843e8f
to
0062410
Compare
`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.
Warning You have reached your daily quota limit. As a reminder, free tier users are limited to 5 requests per day. Please wait up to 24 hours and I will start processing your requests again! |
5 similar comments
Warning You have reached your daily quota limit. As a reminder, free tier users are limited to 5 requests per day. Please wait up to 24 hours and I will start processing your requests again! |
Warning You have reached your daily quota limit. As a reminder, free tier users are limited to 5 requests per day. Please wait up to 24 hours and I will start processing your requests again! |
Warning You have reached your daily quota limit. As a reminder, free tier users are limited to 5 requests per day. Please wait up to 24 hours and I will start processing your requests again! |
Warning You have reached your daily quota limit. As a reminder, free tier users are limited to 5 requests per day. Please wait up to 24 hours and I will start processing your requests again! |
Warning You have reached your daily quota limit. As a reminder, free tier users are limited to 5 requests per day. Please wait up to 24 hours and I will start processing your requests again! |
out_field = variable.compute!(nothing, Y, p, t) | ||
else | ||
out_or_broadcasted = variable.compute(Y, p, t) | ||
if out_or_broadcasted isa Base.Broadcast.Broadcasted |
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.
if out_or_broadcasted isa Base.Broadcast.Broadcasted | |
if out_or_broadcasted isa Base.AbstractBroadcasted |
I think this may work more generally (e.g., in case the broadcasted is a ClimaCore stencil broadcasted)
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 left one more comment (to use Base.AbstractBroadcasted
instead of Base.Broadcast.Broadcasted
, as it's a bit more general). I think we're good to merge after that. Thanks for taking this on, I think this will be a nice upgrade! 🚀
This PR adds support for specifying diagnostics with a
compute
function instead ofcompute!
.compute(state, cache, time)
can return either aField
or aBase.Broadcast.Broadcasted
object (obtained with@lazy
) and are now the recommended way to specify diagnostics.compute!
is still supported to preserve existing code.Closes #5