Skip to content

Move to KernelAbstractions 0.10 - #5799

Draft
giordano wants to merge 9 commits into
mainfrom
mg/ka-0.10
Draft

giordano wants to merge 9 commits into
mainfrom
mg/ka-0.10

Conversation

@giordano

Copy link
Copy Markdown
Member

No description provided.

@giordano

This comment was marked as resolved.

@giordano

This comment was marked as resolved.

@glwagner

This comment was marked as resolved.

@giordano

This comment was marked as resolved.

Comment thread src/Utils/kernel_launching.jl Outdated
Comment thread .buildkite/pipeline.yml Outdated
@inline kernel_time_step(arch, grid, Δt) = convert(eltype(grid), Δt)

using Adapt: Adapt
using Base: @pure

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👋

giordano and others added 9 commits October 21, 2026 00:21
…ange mapping

The active cells map was implemented by wrapping the kernel function in a
`MappedFunction` and overriding KernelAbstractions 0.9 internals
(`__validindex`, `expand` with the map stored in place of the workitems),
plus `@device_override`s of `__validindex` in the CUDA, AMDGPU and Metal
extensions. KernelAbstractions 0.10 validates work items differently, as
`expand(iterspace, group, item) in ndrange` for iteration spaces with a
custom mapping, so every kernel launched over a map failed to compile on the
POCL CPU backend (a `MethodError` in `in`). The adaptation of the context
also dropped its new launch configuration.

KernelAbstractions 0.10 supports custom mappings in `NDRange` through
`expand`, `in` and `linear_index`, so the map now uses that hook:
`launch!` passes an `IndexMap` as the `ndrange` of the kernel,
`partition` stores it as the `NDRange` mapping, `expand` looks up the index
of each work item, and the context's `ndrange` is a `MappedIndices`
containing every index but the one returned past the end of the map.
The linear index of a mapped work item, its position in the map, is
defined through `NDIteration.linear_index(iterspace, ndrange, groupidx, idx)`
(JuliaGPU/KernelAbstractions.jl#848), KernelAbstractions' hook for custom
`NDRange` mappings, rather than by extending the internal
`__index_Global_Linear`, which KernelAbstractions documents as not to be
extended. KernelAbstractions adapts the mapping and keeps the launch
configuration itself, and the backend overrides are no longer needed. All
the new methods are on Oceananigans types.

The split-explicit substep loops, including the multi-region one, configure
their kernels once with `configure_kernel` and then launch them directly,
many times. They discarded the work size it returns and launched without an
`ndrange`, which with a kernel configured over a map fails ("Can not
partition kernel!"). They now keep the work size and launch with
`ndrange = launch_ndrange(worksize)`, which is `nothing` for the launches
without a map and the `IndexMap` with one.

There was no direct test of launches over a map, so add one checking that
each listed cell is visited exactly once over several workgroups, unlisted
cells aren't touched, and the linear index is the position in the map.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EtLmZUPY4g9hi8aJsM4Wrs
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PrdqyLiieQJGV868Vz4zvt
`convert_to_device(::CPU, args)` adapted kernel arguments to `CPU()`, so
that fields reached CPU kernels as their data and kernels did not
specialize on boundary conditions (#6068). With KernelAbstractions 0.10
CPU kernels run on the POCL backend, which converts every argument with
its own adaptor when launching and compiles the kernel for the converted
types, as on GPUs: kernels no longer specialize on field metadata whether
or not the arguments are converted beforehand.

Converting them beforehand also adapted them twice, and objects already
adapted to `CPU()` are not necessarily adaptable again: a `FieldTimeSeries`
became a `GPUAdaptedFieldTimeSeries`, which KernelAbstractions passed
through with its CPU `Array`, so every kernel taking a `FieldTimeSeries`
(in forcings, boundary conditions, `PrescribedVelocityFields`, ...)
failed to compile. Converting them with the POCL adaptor instead, as
GPUs do with `cudaconvert`, isn't an option: it turns arrays into raw
pointers, and only the arguments passed to the launch are preserved from
garbage collection while the kernel runs.

So `convert_to_device` is now the identity on the CPU, and the `CPU()`
adaptation and its pass-throughs for grids and functions are removed.
The test now checks that the argument types KernelAbstractions compiles
CPU kernels for don't depend on boundary conditions, and that converting
the arguments, which happens at every launch, doesn't allocate.

On a split-explicit hydrostatic model with CATKE on an immersed grid
(32×32×8), allocations (19520 B) and run time (~50 ms) per time step are
unchanged, while the first time step takes ~3.5 s longer (18.4–21.9 s
against 15.0–16.9 s, alternating runs on a loaded machine), as the host
side of the launches is compiled for the unconverted argument types.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EtLmZUPY4g9hi8aJsM4Wrs
In KernelAbstractions 0.10, `ndevices` and `zeros` are owned by
KernelInterface, a separate package that KernelAbstractions loads and
doesn't re-export them from, so accessing them as
`KernelAbstractions.ndevices` and `KernelAbstractions.zeros` failed the
ExplicitImports check that qualified accesses go through the owner.

Add KernelInterface as a dependency, from the same KernelAbstractions
revision as in `test/Project.toml`, and use `KernelInterface.ndevices`
and `KernelInterface.zeros`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EtLmZUPY4g9hi8aJsM4Wrs
With KernelAbstractions 0.10, CPU kernels are launched on the POCL
backend, and every launch allocates, so a time step on the CPU allocates
more in the allocation regression tests.  On the upside, newer CUDA.jl versions
reduced allocations.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EtLmZUPY4g9hi8aJsM4Wrs
Kernels launched over offset index ranges (`KernelParameters`, and the
interior work layouts that exclude peripheral nodes) used a custom
`OffsetStaticSize` ndrange, a subtype of KernelAbstractions'
internal `_Size`. To make KernelAbstractions launch over it, Oceananigans
extended the internal `__ndrange` and `__groupsize` for its contexts,
stored the offsets in the `workitems` slot of the `NDRange`, and
replaced `partition` and `expand` for such kernels.

KernelAbstractions 0.10 supports index ranges in a static ndrange:
`StaticSize((2:5, 1:3))` launches over those indices, with the offsets
as the `NDRange` mapping. Build the work sizes with `StaticSize` of the
ranges instead, and remove `OffsetStaticSize` with the methods
extending KernelAbstractions' internals, and the imports only they used.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EtLmZUPY4g9hi8aJsM4Wrs

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants