Skip to content

Commit dfad5b3

Browse files
authored
Merge pull request #202 from omlins/ad_deferred
AD: throw error if gpu compiler incompatible argument
2 parents 8d29055 + 39ae275 commit dfad5b3

5 files changed

Lines changed: 40 additions & 33 deletions

File tree

README.md

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,31 @@ A particularity of ParallelStencil is that it enables writing a single high-leve
1616
Beyond traditional high-performance computing, ParallelStencil supports automatic differentiation of architecture-agnostic parallel kernels relying on [Enzyme.jl], enabling both high-level and generic syntax for maximal flexibility.
1717

1818
## Contents
19-
* [Parallelization and optimization with one macro call](#parallelization-with-one-macro-call)
20-
* [Stencil computations with math-close notation](#stencil-computations-with-math-close-notation)
21-
* [50-lines example deployable on GPU and CPU](#50-lines-example-deployable-on-GPU-and-CPU)
22-
* [50-lines multi-xPU example](#50-lines-multi-xpu-example)
23-
* [Seamless interoperability with communication packages and hiding communication](#seamless-interoperability-with-communication-packages-and-hiding-communication)
24-
* [Support for architecture-agnostic low level kernel programming](#support-for-architecture-agnostic-low-level-kernel-programming)
25-
* [Support for logical arrays of small arrays / structs](#support-for-logical-arrays-of-small-arrays--structs)
26-
* [Support for automatic differentiation of architecture-agnostic parallel kernels](#support-for-automatic-differentiation-of-architecture-agnostic-parallel-kernels)
27-
* [Module documentation callable from the Julia REPL / IJulia](#module-documentation-callable-from-the-julia-repl--ijulia)
28-
* [Concise single/multi-xPU miniapps](#concise-singlemulti-xpu-miniapps)
29-
* [Dependencies](#dependencies)
30-
* [Installation](#installation)
31-
* [Questions, comments and discussions](#questions-comments-and-discussions)
32-
* [Your contributions](#your-contributions)
33-
* [References](#references)
19+
- [Contents](#contents)
20+
- [Parallelization and optimization with one macro call](#parallelization-and-optimization-with-one-macro-call)
21+
- [Stencil computations with math-close notation](#stencil-computations-with-math-close-notation)
22+
- [50-lines example deployable on GPU and CPU](#50-lines-example-deployable-on-gpu-and-cpu)
23+
- [50-lines multi-xPU example](#50-lines-multi-xpu-example)
24+
- [Seamless interoperability with communication packages and hiding communication](#seamless-interoperability-with-communication-packages-and-hiding-communication)
25+
- [Support for architecture-agnostic low level kernel programming](#support-for-architecture-agnostic-low-level-kernel-programming)
26+
- [Support for logical arrays of small arrays / structs](#support-for-logical-arrays-of-small-arrays--structs)
27+
- [Support for automatic differentiation of architecture-agnostic parallel kernels](#support-for-automatic-differentiation-of-architecture-agnostic-parallel-kernels)
28+
- [Module documentation callable from the Julia REPL / IJulia](#module-documentation-callable-from-the-julia-repl--ijulia)
29+
- [Concise single/multi-xPU miniapps](#concise-singlemulti-xpu-miniapps)
30+
- [Performance metric](#performance-metric)
31+
- [Miniapp content](#miniapp-content)
32+
- [Thermo-mechanical convection 2-D app](#thermo-mechanical-convection-2-d-app)
33+
- [Viscous Stokes 2-D app](#viscous-stokes-2-d-app)
34+
- [Viscous Stokes 3-D app](#viscous-stokes-3-d-app)
35+
- [Acoustic wave 2-D app](#acoustic-wave-2-d-app)
36+
- [Acoustic wave 3-D app](#acoustic-wave-3-d-app)
37+
- [Scalar porosity waves 2-D app](#scalar-porosity-waves-2-d-app)
38+
- [Hydro-mechanical porosity waves 2-D app](#hydro-mechanical-porosity-waves-2-d-app)
39+
- [Dependencies](#dependencies)
40+
- [Installation](#installation)
41+
- [Questions, comments and discussions](#questions-comments-and-discussions)
42+
- [Your contributions](#your-contributions)
43+
- [References](#references)
3444

3545
## Parallelization and optimization with one macro call
3646
A simple call to `@parallel` is enough to parallelize and optimize a function and to launch it. The package used underneath for parallelization is defined in a call to `@init_parallel_stencil` beforehand. Supported are [CUDA.jl], [AMDGPU.jl] and [Metal.jl] for running on GPU and [Base.Threads] for CPU. The following example outlines how to run parallel computations on a GPU using the native kernel programming capabilities of [CUDA.jl] underneath (omitted lines are represented with `#(...)`, omitted arguments with `...`):
@@ -318,7 +328,7 @@ import ParallelStencil.AD
318328
using Enzyme
319329
#(...)
320330
@parallel f!(A, B, a) # normal call of f!
321-
@parallel configcall=f!(A, B, a) AD.autodiff_deferred!(Enzyme.Reverse, f!, DuplicatedNoNeed(A, Ā), DuplicatedNoNeed(B, B̄), Const(a)) # call to the gradient of f!, differentiated with respect to A and B
331+
@parallel configcall=f!(A, B, a) AD.autodiff_deferred!(Enzyme.Reverse, f!, DuplicatedNoNeed(A, Ā), DuplicatedNoNeed(B, B̄), a) # call to the gradient of f!, differentiated with respect to A and B
322332
```
323333
The submodule `ParallelStencil.AD` contains GPU-compatible wrappers of Enzyme functions (returning always `nothing` as required by the backend packages [CUDA.jl] and [AMDGPU.jl]); the wrapper `AD.autodiff_deferred!` maps, e.g., `Enzyme.autodiff_deferred`. The keyword argument `configcall` makes it trivial to call these generic functions for automatic differentiation with the right launch parameters.
324334

src/AD.jl

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ Provides GPU-compatible wrappers for automatic differentiation functions of the
77
import ParallelStencil.AD
88
99
# Functions
10-
- `autodiff_deferred!`: wraps function `Enzyme.autodiff_deferred`, and supports the same arguments. Additionally, it promotes all arguments that are not `Enzyme.Annotation` to `Enzyme.Const` and automatically inserts the return type activity as 3rd argument if omitted; as a result, the function can be called also as, e.g., `autodiff_deferred!(Enzyme.Reverse, f!,...)`, besides the fully explicit form, e.g., `autodiff_deferred!(Enzyme.Reverse, Enzyme.Const(f!), Enzyme.Const,...)`.
11-
- `autodiff_deferred_thunk!`: wraps function `Enzyme.autodiff_deferred_thunk`, and supports the same arguments. Additionally, it applies the same argument promotion and return type activity insertion as `autodiff_deferred!` (see above).
10+
- `autodiff_deferred!`: wraps function `Enzyme.autodiff_deferred`, and supports the same arguments, with the exception of the return type activity (3rd argument) which must be omitted and will be automatically inserted (inserting it explicitly will raise a GPU compiler error when targeting a GPU). Additionally, it promotes all arguments that are not `Enzyme.Annotation` to `Enzyme.Const`. As a result, the function can be conveniently called as, e.g., `autodiff_deferred!(Enzyme.Reverse, f!,...)`, instead of the fully explicit form, e.g., `autodiff_deferred!(Enzyme.Reverse, Enzyme.Const(f!), Enzyme.Const,...)` (which is not supported).
11+
- `autodiff_deferred_thunk!`: wraps function `Enzyme.autodiff_deferred_thunk`, in the same way as `autodiff_deferred!` wraps `Enzyme.autodiff_deferred` (see above).
12+
1213
1314
# Examples
1415
const USE_GPU = true
@@ -36,7 +37,7 @@ Provides GPU-compatible wrappers for automatic differentiation functions of the
3637
3738
@info "running on CPU/GPU"
3839
@parallel f!(A, B, a) # normal call of f!
39-
@parallel configcall=f!(A, B, a) AD.autodiff_deferred!(Enzyme.Reverse, f!, Duplicated(A, Ā), DuplicatedNoNeed(B, B̄), Const(a)) # automatic differentiation of f!
40+
@parallel configcall=f!(A, B, a) AD.autodiff_deferred!(Enzyme.Reverse, f!, Duplicated(A, Ā), DuplicatedNoNeed(B, B̄), a) # automatic differentiation of f!
4041
4142
return
4243
end

src/ParallelKernel/EnzymeExt/AD.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ Provides GPU-compatible wrappers for automatic differentiation functions of the
77
import ParallelKernel.AD
88
99
# Functions
10-
- `autodiff_deferred!`: wraps function `Enzyme.autodiff_deferred`, and supports the same arguments. Additionally, it promotes all arguments that are not `Enzyme.Annotation` to `Enzyme.Const` and automatically inserts the return type activity as 3rd argument if omitted; as a result, the function can be called also as, e.g., `autodiff_deferred!(Enzyme.Reverse, f!,...)`, besides the fully explicit form, e.g., `autodiff_deferred!(Enzyme.Reverse, Enzyme.Const(f!), Enzyme.Const,...)`.
11-
- `autodiff_deferred_thunk!`: wraps function `Enzyme.autodiff_deferred_thunk`, and supports the same arguments. Additionally, it applies the same argument promotion and return type activity insertion as `autodiff_deferred!` (see above).
10+
- `autodiff_deferred!`: wraps function `Enzyme.autodiff_deferred`, and supports the same arguments, with the exception of the return type activity (3rd argument) which must be omitted and will be automatically inserted (inserting it explicitly will raise a GPU compiler error when targeting a GPU). Additionally, it promotes all arguments that are not `Enzyme.Annotation` to `Enzyme.Const`. As a result, the function can be conveniently called as, e.g., `autodiff_deferred!(Enzyme.Reverse, f!,...)`, instead of the fully explicit form, e.g., `autodiff_deferred!(Enzyme.Reverse, Enzyme.Const(f!), Enzyme.Const,...)` (which is not supported).
11+
- `autodiff_deferred_thunk!`: wraps function `Enzyme.autodiff_deferred_thunk`, in the same way as `autodiff_deferred!` wraps `Enzyme.autodiff_deferred` (see above).
1212
1313
To see a description of a function type `?<functionname>`.
1414
"""

src/ParallelKernel/EnzymeExt/autodiff_gpu.jl

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import ParallelStencil
22
import ParallelStencil: PKG_THREADS, PKG_POLYESTER
3+
using ParallelStencil.ParallelKernel.Exceptions
34
import Enzyme
45

56
# NOTE: package specific initialization of Enzyme could be done as follows (not needed in the currently supported versions of Enzyme)
@@ -27,9 +28,7 @@ end
2728

2829

2930
function ParallelStencil.ParallelKernel.AD.autodiff_deferred!(mode, f, ::Type{T}, args::Vararg{Any,N}) where {T<:Enzyme.Annotation, N} # NOTE: minimal specialization is required to avoid overwriting the default method
30-
f = promote_to_const(f)[1]
31-
args = promote_to_const(args...)
32-
Enzyme.autodiff_deferred(mode, f, T, args...)
31+
@ArgumentError("AD.autodiff_deferred!: explicit insertion of the return type activity (third argument) is not supported as not GPU compiler compatible; call without it instead.")
3332
return
3433
end
3534

@@ -42,9 +41,7 @@ end
4241

4342

4443
function ParallelStencil.ParallelKernel.AD.autodiff_deferred_thunk!(mode, f, ::Type{T}, args::Vararg{Any,N}) where {T<:Enzyme.Annotation, N} # NOTE: minimal specialization is required to avoid overwriting the default method
45-
f = promote_to_const(f)[1]
46-
args = promote_to_const(args...)
47-
Enzyme.autodiff_deferred_thunk(mode, f, T, args...)
44+
@ArgumentError("AD.autodiff_deferred_thunk!: explicit insertion of the return type activity (third argument) is not supported as not GPU compiler compatible; call without it instead.")
4845
return
4946
end
5047

test/ParallelKernel/test_parallel.jl

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -140,15 +140,14 @@ eval(:(
140140
@test Array(B̄) B̄_ref
141141
= @ones(N)
142142
= @ones(N)
143-
@parallel configcall=f!(A, B, a) AD.autodiff_deferred!(Enzyme.Reverse, f!, Const, DuplicatedNoNeed(A, Ā), DuplicatedNoNeed(B, B̄), Const(a)) # NOTE: f! is automatically promoted to Const(f!)
144-
@test Array(Ā) Ā_ref
145-
@test Array(B̄) B̄_ref
146-
= @ones(N)
147-
= @ones(N)
148-
@parallel configcall=f!(A, B, a) AD.autodiff_deferred!(Enzyme.Reverse, Const(f!), Const, DuplicatedNoNeed(A, Ā), DuplicatedNoNeed(B, B̄), Const(a)) # NOTE: no automatic promotion or insertion here.
143+
@parallel configcall=f!(A, B, a) AD.autodiff_deferred!(Enzyme.Reverse, f!, DuplicatedNoNeed(A, Ā), DuplicatedNoNeed(B, B̄), a) # NOTE: f! and a are automatically promoted to Const(f!) and Const(a) and the return type Const is inserted.
149144
@test Array(Ā) Ā_ref
150145
@test Array(B̄) B̄_ref
151146
end;
147+
@testset "AD.autodiff_deferred! (GPU compiler error)" begin
148+
@test_throws Exception @parallel configcall=f!(A, B, a) AD.autodiff_deferred!(Enzyme.Reverse, f!, Const, DuplicatedNoNeed(A, Ā), DuplicatedNoNeed(B, B̄), Const(a)) # NOTE: f! is automatically promoted to Const(f!)
149+
@test_throws Exception @parallel configcall=f!(A, B, a) AD.autodiff_deferred!(Enzyme.Reverse, Const(f!), Const, DuplicatedNoNeed(A, Ā), DuplicatedNoNeed(B, B̄), Const(a)) # NOTE: no automatic promotion or insertion here.
150+
end;
152151
@testset "@parallel ∇ (numerical)" begin
153152
= @ones(N)
154153
= @ones(N)

0 commit comments

Comments
 (0)