CliMA / CliMA/ClimaCore.jl

Make empty field broadcasting a no-op

Open
#1,277 0 comments 0 reactions 0 assignees View on GitHub
enhancement
Dominant language
Julia
Stars
117
Forks
19
Avg merge
3d 4h
Merged PRs (30d)
41

Description

**Is your feature request related to a problem? Please describe.**
Broadcasting over empty fields currently traverses the field and, unless there are sensible operations that we can perform with empty fields, it would be nice if these expressions short circuited to no-ops.

Here is a MWE showing that the cost is not nothing:

```julia
using Revise
import ClimaCore.Geometry as Geometry
import ClimaCore.Spaces as Spaces
import ClimaCore.Domains as Domains
import ClimaCore.Meshes as Meshes
import ClimaCore.Topologies as Topologies
import ClimaComms
import ClimaCore

function FieldFromNamedTuple(space, nt::NamedTuple)
cmv(z) = nt
return cmv.(Fields.coordinate_field(space))
end

function big_space(
::Type{FT};
helem = 16,
Nq = 5,
zelem = 100,
context = ClimaComms.SingletonCommsContext(),
) where {FT}
radius = FT(128)
zlim = (0, 1)
vertdomain = Domains.IntervalDomain(
Geometry.ZPoint{FT}(zlim[1]),
Geometry.ZPoint{FT}(zlim[2]);
boundary_tags = (:bottom, :top),
)
vertmesh = Meshes.IntervalMesh(vertdomain, nelems = zelem)
vtopology = Topologies.IntervalTopology(context, vertmesh)
vspace = Spaces.CenterFiniteDifferenceSpace(vtopology)

hdomain = Domains.SphereDomain(radius)
hmesh = Meshes.EquiangularCubedSphere(hdomain, helem)
htopology = Topologies.Topology2D(context, hmesh)
quad = Spaces.Quadratures.GLL{Nq}()
hspace = Spaces.SpectralElementSpace2D(htopology, quad)
return Spaces.ExtrudedFiniteDifferenceSpace(hspace, vspace)
end

space = big_space(Float64);
x = FieldFromNamedTuple(space, (;));
y = FieldFromNamedTuple(space, (;));
function do_nothing(x, y)
return nothing
end

function copy_to(x, y)
@. x = y
return nothing
end
using BenchmarkTools
@btime copy_to(x, y)
@btime do_nothing(x, y)
```

The cost is small, but I don't see why we can't skip these extra traversals. In addition, this also yields significantly less codegen:

```julia
julia> IntrospectionTools.@code_summary copy_to(x, y)
------------------------------------ Code summary
[ Info: `n_instructions` = 0
[ Info: `n_inbounds` = 124
[ Info: `n_jl_calls` = 0
[ Info: length(code_native): 8537
[ Info: length(code_llvm): 132005
[ Info: length(code_llvm)/length(code_native): 15.462691812111983
------------------------------------

julia> IntrospectionTools.@code_summary do_nothing(x, y)
------------------------------------ Code summary
[ Info: `n_instructions` = 0
[ Info: `n_inbounds` = 0
[ Info: `n_jl_calls` = 0
[ Info: length(code_native): 403
[ Info: length(code_llvm): 1134
[ Info: length(code_llvm)/length(code_native): 2.8138957816377173
------------------------------------
```

Contributor guide

No contributing guide indexed for this repository

Research direction

Start by running the provided Julia MWE and comparing `copy_to(x, y)` with `do_nothing(x, y)`, especially the `@. x = y` operation on empty NamedTuples. Trace the broadcasting path used by `copy_to`; done means empty-field broadcasting becomes a no-op without traversing the field or generating the unnecessary code shown in the issue.

Written by the indexing model from the issue text.

Assessment

Tech stack
julia
Domain
performance
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.