From 02b6aa51ce863091c4db981936cdf19292e3b7a8 Mon Sep 17 00:00:00 2001 From: Ludovic Raess Date: Mon, 6 Jul 2026 11:14:26 +0200 Subject: [PATCH 01/10] Add missing basics --- docs/make.jl | 6 ++ docs/src/faq.md | 53 ++++++++++++ docs/src/usage/arrays.md | 125 +++++++++++++++++++++++++++ docs/src/usage/kernelabstractions.md | 38 ++++++++ docs/src/usage/multitasking.md | 53 ++++++++++++ src/ROCKernels.jl | 7 ++ 6 files changed, 282 insertions(+) create mode 100644 docs/src/faq.md create mode 100644 docs/src/usage/arrays.md create mode 100644 docs/src/usage/kernelabstractions.md create mode 100644 docs/src/usage/multitasking.md diff --git a/docs/make.jl b/docs/make.jl index 12333ff78..98ed2f987 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -37,6 +37,11 @@ function main() "Installation Tips" => "install_tips.md", "Testing" => "testing.md", ], + "Usage" => [ + "Array Programming" => "usage/arrays.md", + "Tasks, Streams and Multiple GPUs" => "usage/multitasking.md", + "KernelAbstractions" => "usage/kernelabstractions.md", + ], "API" => [ "Devices" => "api/devices.md", "Streams" => "api/streams.md", @@ -48,6 +53,7 @@ function main() "Printing" => "api/printing.md", "Intrinsics" => "api/intrinsics.md", ], + "FAQ" => "faq.md", ], doctest=true, warnonly=[:missing_docs], diff --git a/docs/src/faq.md b/docs/src/faq.md new file mode 100644 index 000000000..900bc2db7 --- /dev/null +++ b/docs/src/faq.md @@ -0,0 +1,53 @@ +# FAQ + +## How do I check that AMDGPU.jl works? + +`AMDGPU.functional()` returns `true` when the ROCm stack is available and a GPU can be used. For a full report of detected devices, libraries and versions, use `AMDGPU.versioninfo()`. + +```julia +using AMDGPU +AMDGPU.functional() # true if AMDGPU.jl can run on this machine +AMDGPU.versioninfo() # detailed diagnostics +``` + +## How should a package depend on AMDGPU.jl? + +AMDGPU.jl loads on any machine, but only works when ROCm and a supported GPU are present. Code that should run with or without a GPU must therefore guard GPU use behind `AMDGPU.functional()` rather than assume it — importing the package is not enough. + +```julia +using AMDGPU + +if AMDGPU.functional() + x = AMDGPU.ones(Float32, 1024) # run on the GPU +else + x = ones(Float32, 1024) # CPU fallback +end +``` + +For a hard requirement of GPU hardware specifically, `has_rocm_gpu()` additionally checks that at least one device is present. For a heavier optional dependency, prefer a [package extension](https://pkgdocs.julialang.org/v1/creating-packages/#Conditional-loading-of-code-in-packages-(Extensions)) that loads only when AMDGPU is available, following the pattern used by the wider Julia GPU ecosystem. + +## Which ROCm libraries are available? + +Individual components are queried with `AMDGPU.functional(component)`, useful when a feature depends on a specific library: + +```julia +AMDGPU.functional(:rocblas) # dense linear algebra (rocBLAS) +AMDGPU.functional(:rocsolver) # factorizations (rocSOLVER) +AMDGPU.functional(:rocsparse) # sparse arrays (rocSPARSE) +AMDGPU.functional(:rocfft) # FFTs (rocFFT) +AMDGPU.functional(:rocrand) # random numbers (rocRAND) +AMDGPU.functional(:MIOpen) # deep-learning primitives (MIOpen) +AMDGPU.functional(:all) # true only if every component is available +``` + +## My GPU is not detected or a library is missing + +Run `AMDGPU.versioninfo()` and check that `hip` and the library you need report as functional. Missing components usually mean the corresponding ROCm package is not installed. See [Installation Info](@ref) for platform-specific setup, including the package list for distributions such as Fedora. + +## How do I control GPU memory usage? + +`ROCArray`s are managed by Julia's garbage collector, and a HIP memory pool caches freed allocations. You can free eagerly, cap usage, and query current usage — see the [Memory Allocation and Intrinsics](@ref) page for `AMDGPU.unsafe_free!`, memory limits, and the caching allocator. + +## Where can I get help? + +Ask on the [Julia Discourse](https://discourse.julialang.org/c/domain/gpu) GPU domain or the `#gpu` channel of the [Julia Slack](https://julialang.org/community/). Bug reports and feature requests are welcome on the [issue tracker](https://github.com/JuliaGPU/AMDGPU.jl/issues). diff --git a/docs/src/usage/arrays.md b/docs/src/usage/arrays.md new file mode 100644 index 000000000..9a46e41c2 --- /dev/null +++ b/docs/src/usage/arrays.md @@ -0,0 +1,125 @@ +```@meta +DocTestSetup = quote + using AMDGPU +end +``` + +# Array Programming + +The `ROCArray` type is the core of AMDGPU.jl. It is a dense, GPU-resident array that implements Julia's `AbstractArray` interface, so most array code written for `Array` works on the GPU with little or no change. This is the recommended, high-level way to use AMDGPU.jl — you rarely need to write kernels by hand. + +## Construction + +Copy an existing array to the device by wrapping it in a `ROCArray`, or build one directly on the device with the familiar constructors: + +```jldoctest arrays +julia> ROCArray([1, 2, 3, 4]) |> Array # move host array to device (shown via Array) +4-element Vector{Int64}: + 1 + 2 + 3 + 4 + +julia> AMDGPU.ones(Float32, 2, 2) |> Array +2×2 Matrix{Float32}: + 1.0 1.0 + 1.0 1.0 +``` + +The device-side constructors mirror `Base`: `AMDGPU.zeros`, `AMDGPU.ones`, `AMDGPU.fill`, `AMDGPU.rand`, `AMDGPU.randn`, and `similar`. All take an optional element type and dimensions. + +## Host ↔ device transfer + +Wrapping a host array in `ROCArray` copies it to the GPU; calling `Array` on a `ROCArray` copies it back: + +```jldoctest arrays +julia> a = ROCArray(Float32[1, 2, 3]); + +julia> Array(a) +3-element Vector{Float32}: + 1.0 + 2.0 + 3.0 +``` + +Transfers are relatively expensive — keep data on the device across as many operations as possible rather than copying back and forth. + +## Broadcasting + +Broadcasting works exactly as on the CPU and fuses into a single kernel, so chained element-wise operations do not allocate intermediate arrays: + +```jldoctest arrays +julia> x = ROCArray(Float32[1, 2, 3]); + +julia> y = ROCArray(Float32[10, 20, 30]); + +julia> Array(@. 2x + y) +3-element Vector{Float32}: + 12.0 + 24.0 + 36.0 +``` + +## Reductions, scans and sorting + +Reductions (`sum`, `prod`, `maximum`, `mapreduce`, …), scans (`cumsum`, `accumulate`), `sort`/`sortperm`, and `reverse` all run on the GPU: + +```jldoctest arrays +julia> sum(ROCArray(1:100)) +5050 + +julia> mapreduce(x -> x^2, +, ROCArray(1:4)) +30 + +julia> Array(cumsum(ROCArray([1, 2, 3, 4]))) +4-element Vector{Int64}: + 1 + 3 + 6 + 10 + +julia> Array(sort(ROCArray([3, 1, 2, 5, 4]))) +5-element Vector{Int64}: + 1 + 2 + 3 + 4 + 5 +``` + +## Scalar indexing + +Reading or writing a single element from the host (`a[i]`) would require a separate GPU transfer per element, which is catastrophically slow. AMDGPU.jl therefore *disallows* scalar indexing by default and throws an error: + +```julia +julia> a = ROCArray([1, 2, 3]); + +julia> a[1] +ERROR: Scalar indexing is disallowed. +``` + +If you genuinely need it (e.g. in a one-off test), opt in explicitly: + +```julia +AMDGPU.allowscalar(true) # globally (discouraged) +AMDGPU.@allowscalar a[1] # for a single expression (preferred) +``` + +Prefer vectorized operations, broadcasting, or a custom kernel instead. See [Kernel Programming](@ref) for writing your own kernels. + +## Views and reshaping + +`view`, `reshape`, `reinterpret`, and adjoint/transpose all work and return lazy wrappers that share the parent's memory — no copy is made: + +```jldoctest arrays +julia> a = ROCArray(reshape(1:6, 2, 3)); + +julia> Array(view(a, :, 2)) +2-element Vector{Int64}: + 3 + 4 +``` + +## Linear algebra + +Matrix multiplication and factorizations dispatch to the vendor libraries (rocBLAS, rocSOLVER). Standard `LinearAlgebra` functions — `*`, `mul!`, `\`, `cholesky`, `lu`, `qr`, `svd` — work directly on `ROCArray`. diff --git a/docs/src/usage/kernelabstractions.md b/docs/src/usage/kernelabstractions.md new file mode 100644 index 000000000..15aeac1cb --- /dev/null +++ b/docs/src/usage/kernelabstractions.md @@ -0,0 +1,38 @@ +# KernelAbstractions + +[KernelAbstractions.jl](https://github.com/JuliaGPU/KernelAbstractions.jl) lets you write a single kernel that runs on CPUs and on all supported GPU backends. AMDGPU.jl provides the `ROCBackend` for it, so KernelAbstractions is the recommended way to write **portable** kernels — code that works unchanged on AMDGPU, CUDA, and others. + +KernelAbstractions is a separate package; add it alongside AMDGPU: + +```julia +using Pkg +Pkg.add("KernelAbstractions") +``` + +Write kernels with the `@kernel` macro and index them with `@index` instead of the AMDGPU-specific `workitemIdx`/`workgroupIdx` intrinsics: + +```julia +using AMDGPU +using KernelAbstractions + +@kernel function vadd!(c, a, b) + i = @index(Global) + c[i] = a[i] + b[i] +end + +a = AMDGPU.ones(Float32, 1024) +b = AMDGPU.ones(Float32, 1024) +c = similar(a) + +backend = ROCBackend() +vadd!(backend, 256)(c, a, b; ndrange = length(c)) +KernelAbstractions.synchronize(backend) +``` + +`ROCBackend()` selects AMDGPU as the execution backend. The `256` is the workgroup size, and `ndrange` is the total number of work items. `get_backend(::ROCArray)` returns a `ROCBackend`, so generic code can obtain the right backend directly from its arrays. + +For the kernel-authoring API (`@kernel`, `@index`, `@localmem`, `@synchronize`, …), see the [KernelAbstractions documentation](https://juliagpu.github.io/KernelAbstractions.jl/stable/). To write AMDGPU-specific kernels with the native intrinsics instead, see [Kernel Programming](@ref). + +```@docs +AMDGPU.ROCBackend +``` diff --git a/docs/src/usage/multitasking.md b/docs/src/usage/multitasking.md new file mode 100644 index 000000000..1fbb06e8d --- /dev/null +++ b/docs/src/usage/multitasking.md @@ -0,0 +1,53 @@ +# Tasks, Streams and Multiple GPUs + +AMDGPU.jl follows a **task-local** execution model: the active device and stream are properties of the current Julia task. Switching either one affects only the task that makes the switch, so concurrent tasks can drive different devices or streams without interfering with each other. This makes ordinary Julia task-based parallelism the natural way to overlap work and to use several GPUs at once. + +## Selecting a device + +All supported GPUs are auto-detected. The device bound to the current task is returned by `AMDGPU.device()`, and `AMDGPU.devices()` lists all of them. Switch the current task's device with `AMDGPU.device!`: + +```julia +AMDGPU.devices() # all detected devices +AMDGPU.device() # device of the current task + +AMDGPU.device!(AMDGPU.devices()[2]) # switch this task to the second device +x = AMDGPU.ones(Float32, 16) # allocated on the second device +``` + +Arrays and kernels use the current task's device, so allocate and launch after switching. See [Devices](@ref) for the full reference and device-property queries. + +## Streams and asynchrony + +Kernel launches and most operations are asynchronous with respect to the host: they are enqueued on a HIP stream and return immediately. Work on the same stream runs in order; work on different streams may overlap. Each task has a default stream, and you pick a stream per launch or per task: + +```julia +stream = AMDGPU.HIPStream() +@roc stream=stream kernel(args...) # launch on a specific stream +AMDGPU.stream!(stream) # or make it the task default +``` + +Because launches are asynchronous, synchronize before reading results back or timing code. `AMDGPU.synchronize()` waits for the current stream, `AMDGPU.@sync` wraps an expression and synchronizes after it, and `AMDGPU.device_synchronize()` waits for the whole device: + +```julia +AMDGPU.@sync @roc groupsize=256 gridsize=n kernel(args...) +``` + +Streams also carry a priority (`:normal`, `:low`, `:high`) to bias scheduling. See [Streams](@ref) for stream priorities, synchronization details, and the blocking-vs-nonblocking preference. + +## Using multiple GPUs + +Because device selection is task-local, drive several GPUs by spawning one task per device. Each task switches to its device, then allocates and launches there: + +```julia +devs = AMDGPU.devices() +@sync for (i, dev) in enumerate(devs) + Threads.@spawn begin + AMDGPU.device!(dev) + a = AMDGPU.ones(Float32, 1024) + b = a .+ i + AMDGPU.synchronize() + end +end +``` + +Data does not move between devices automatically. To share results, copy through the host (`Array(x)` on the source device, then `ROCArray` on the destination) or use peer-to-peer transfers where supported. diff --git a/src/ROCKernels.jl b/src/ROCKernels.jl index 5da8810e1..bd710631a 100644 --- a/src/ROCKernels.jl +++ b/src/ROCKernels.jl @@ -12,6 +12,13 @@ import LLVM using StaticArraysCore: MArray +""" + ROCBackend <: KernelAbstractions.GPU + +KernelAbstractions backend that executes kernels on an AMD GPU via AMDGPU.jl. +Pass `ROCBackend()` to a KernelAbstractions kernel to run it on the GPU, or +obtain it from an array with `KernelAbstractions.get_backend(::ROCArray)`. +""" struct ROCBackend <: KA.GPU end KA.functional(::ROCBackend) = AMDGPU.functional() From 1fb3599392a47145bd9d8c34e9d62ab803dcaedc Mon Sep 17 00:00:00 2001 From: Ludovic Raess Date: Mon, 6 Jul 2026 11:35:31 +0200 Subject: [PATCH 02/10] Add coverage --- docs/make.jl | 7 +++++++ docs/src/libraries/dnn.md | 15 ++++++++++++++ docs/src/libraries/fft.md | 36 ++++++++++++++++++++++++++++++++ docs/src/libraries/linalg.md | 40 ++++++++++++++++++++++++++++++++++++ docs/src/libraries/rand.md | 32 +++++++++++++++++++++++++++++ docs/src/libraries/sparse.md | 35 +++++++++++++++++++++++++++++++ docs/src/usage/arrays.md | 2 +- 7 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 docs/src/libraries/dnn.md create mode 100644 docs/src/libraries/fft.md create mode 100644 docs/src/libraries/linalg.md create mode 100644 docs/src/libraries/rand.md create mode 100644 docs/src/libraries/sparse.md diff --git a/docs/make.jl b/docs/make.jl index 98ed2f987..976b38db4 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -53,6 +53,13 @@ function main() "Printing" => "api/printing.md", "Intrinsics" => "api/intrinsics.md", ], + "Libraries" => [ + "Linear Algebra" => "libraries/linalg.md", + "Sparse Arrays" => "libraries/sparse.md", + "Fourier Transforms" => "libraries/fft.md", + "Random Numbers" => "libraries/rand.md", + "Deep Learning (MIOpen)" => "libraries/dnn.md", + ], "FAQ" => "faq.md", ], doctest=true, diff --git a/docs/src/libraries/dnn.md b/docs/src/libraries/dnn.md new file mode 100644 index 000000000..ffea0d77e --- /dev/null +++ b/docs/src/libraries/dnn.md @@ -0,0 +1,15 @@ +# Deep Learning (MIOpen) + +AMDGPU.jl exposes AMD's [MIOpen](https://github.com/ROCm/MIOpen) deep-learning primitives through the `AMDGPU.MIOpen` submodule: convolutions, pooling, softmax, batch normalization, and activation functions, all operating on `ROCArray`. + +In practice you rarely call these directly. They back the GPU implementations used by [NNlib.jl](https://github.com/FluxML/NNlib.jl) and [Flux.jl](https://github.com/FluxML/Flux.jl), so building and training a model on an AMD GPU with Flux uses MIOpen automatically once your data and parameters are `ROCArray`s. + +Check that MIOpen is available with: + +```julia +using AMDGPU +AMDGPU.functional(:MIOpen) +``` + +If it reports `false`, install the MIOpen ROCm package for your platform (see [Installation Info](@ref)). +``` diff --git a/docs/src/libraries/fft.md b/docs/src/libraries/fft.md new file mode 100644 index 000000000..7f710030a --- /dev/null +++ b/docs/src/libraries/fft.md @@ -0,0 +1,36 @@ +# Fourier Transforms + +AMDGPU.jl implements the [AbstractFFTs.jl](https://github.com/JuliaMath/AbstractFFTs.jl) interface on top of AMD's [rocFFT](https://github.com/ROCm/rocFFT), so `fft`, `ifft`, `rfft`, and the planning API work on `ROCArray` just as they do on the CPU. Load `AbstractFFTs` (or a package that re-exports it, such as `FFTW`) alongside AMDGPU: + +```julia +using AMDGPU +using AbstractFFTs + +x = ROCArray(ComplexF32[1, 2, 3, 4]) +y = fft(x) # forward transform on the GPU +z = ifft(y) # z ≈ x +``` + +Real-to-complex transforms are available through `rfft`: + +```julia +xr = AMDGPU.rand(Float32, 1024) +yr = rfft(xr) # length 513 complex output +``` + +## Plans + +For repeated transforms of the same size, create a plan once and reuse it to amortize setup cost. Both out-of-place and in-place plans are supported: + +```julia +x = ROCArray(rand(ComplexF32, 1024)) + +p = plan_fft(x) # out-of-place +y = p * x + +p! = plan_fft!(x) # in-place, overwrites its argument +p! * x +``` + +Multidimensional transforms and transforms over selected dimensions work as usual, e.g. `fft(x, (1, 2))` for a 2D transform of a higher-dimensional array. +``` diff --git a/docs/src/libraries/linalg.md b/docs/src/libraries/linalg.md new file mode 100644 index 000000000..5bd920ea9 --- /dev/null +++ b/docs/src/libraries/linalg.md @@ -0,0 +1,40 @@ +```@meta +DocTestSetup = quote + using AMDGPU + using LinearAlgebra +end +``` + +# Linear Algebra + +Standard `LinearAlgebra` functions work directly on `ROCArray`, dispatching to AMD's [rocBLAS](https://github.com/ROCm/rocBLAS) (dense BLAS) and [rocSOLVER](https://github.com/ROCm/rocSOLVER) (LAPACK-style factorizations). You write ordinary Julia linear algebra; the GPU libraries are used automatically. + +Supported out of the box on `ROCArray`: + +- Matrix–matrix and matrix–vector products (`*`, `mul!`), including mixed- and low-precision (`Float16`) matmul. +- BLAS level-1 operations: `dot`, `norm`, `axpy!`, `axpby!`, `rmul!`. +- Triangular solves and `\` (linear systems, LU-based). +- Factorizations: `cholesky`, `lu`, `qr`. + +```jldoctest linalg +julia> A = ROCArray(Float32[4 1; 1 3]); + +julia> b = ROCArray(Float32[1, 2]); + +julia> x = A \ b; # solve, LU via rocSOLVER + +julia> Array(A * x) ≈ Array(b) +true + +julia> C = cholesky(A); # Cholesky factorization + +julia> Array(C.U' * C.U) ≈ Array(A) +true +``` + +Element types follow rocBLAS/rocSOLVER: `Float32`, `Float64`, `ComplexF32`, and `ComplexF64` (with `Float16` also supported for matmul). + +## Direct library access + +Lower-level routines are available in the `AMDGPU.rocBLAS` and `AMDGPU.rocSOLVER` submodules for cases the generic interface does not cover — for example singular value decomposition via `AMDGPU.rocSOLVER.gesvd!`, or batched factorizations. The generic `LinearAlgebra.svd`/`svdvals` are **not** GPU-accelerated and fall back to the CPU, so use `gesvd!` directly for on-device SVD. +``` diff --git a/docs/src/libraries/rand.md b/docs/src/libraries/rand.md new file mode 100644 index 000000000..74d705360 --- /dev/null +++ b/docs/src/libraries/rand.md @@ -0,0 +1,32 @@ +# Random Numbers + +AMDGPU.jl generates random numbers on the device through AMD's [rocRAND](https://github.com/ROCm/rocRAND). The quickest way to get a random `ROCArray` is the package-level `rand`/`randn`, which mirror `Base`: + +```julia +using AMDGPU + +AMDGPU.rand(Float32, 1024) # uniform in [0, 1) +AMDGPU.randn(Float32, 8, 8) # standard normal +AMDGPU.rand(Int32, 100) # uniform integers +``` + +The standard `Random` in-place interface works on existing `ROCArray`s and fills them on the GPU: + +```julia +using Random + +a = ROCArray{Float32}(undef, 1024) +Random.rand!(a) +Random.randn!(a) +``` + +## Seeding + +Seed the device generators for reproducible results with `AMDGPU.seed!`: + +```julia +AMDGPU.seed!(1234) +``` + +This seeds both the rocRAND generator (used by `AMDGPU.rand`/`randn`) and the GPUArrays fallback generator, so results are reproducible regardless of which path a given operation takes. +``` diff --git a/docs/src/libraries/sparse.md b/docs/src/libraries/sparse.md new file mode 100644 index 000000000..59523c4f0 --- /dev/null +++ b/docs/src/libraries/sparse.md @@ -0,0 +1,35 @@ +# Sparse Arrays + +AMDGPU.jl wraps AMD's [rocSPARSE](https://github.com/ROCm/rocSPARSE) and stores sparse matrices on the device with the `AMDGPU.rocSPARSE` array types: + +- `ROCSparseMatrixCSR` — compressed sparse row (the usual default for GPU work). +- `ROCSparseMatrixCSC` — compressed sparse column. +- `ROCSparseMatrixCOO` — coordinate format. +- `ROCSparseVector` — sparse vector. + +Construct them by converting a host `SparseMatrixCSC`, and convert back the same way: + +```julia +using AMDGPU, SparseArrays +using AMDGPU.rocSPARSE + +S = sprand(Float32, 1000, 1000, 0.01) +dS = ROCSparseMatrixCSR(S) # upload to the GPU + +SparseMatrixCSC(dS) # download back to the host +``` + +## Operations + +Sparse matrix–vector (SpMV) and matrix–matrix (SpMM) products use the standard `*` operator: + +```julia +x = AMDGPU.rand(Float32, 1000) +y = dS * x # SpMV + +B = AMDGPU.rand(Float32, 1000, 8) +Y = dS * B # SpMM +``` + +Incomplete-factorization preconditioners (`ic0`, `ilu0`) and further sparse routines (conversions between formats, triangular solves, gather/scatter) are available in the `AMDGPU.rocSPARSE` submodule for building iterative solvers on the GPU. +``` diff --git a/docs/src/usage/arrays.md b/docs/src/usage/arrays.md index 9a46e41c2..378d2a0e3 100644 --- a/docs/src/usage/arrays.md +++ b/docs/src/usage/arrays.md @@ -122,4 +122,4 @@ julia> Array(view(a, :, 2)) ## Linear algebra -Matrix multiplication and factorizations dispatch to the vendor libraries (rocBLAS, rocSOLVER). Standard `LinearAlgebra` functions — `*`, `mul!`, `\`, `cholesky`, `lu`, `qr`, `svd` — work directly on `ROCArray`. +Matrix multiplication and factorizations dispatch to the vendor libraries (rocBLAS, rocSOLVER). Standard `LinearAlgebra` functions — `*`, `mul!`, `\`, `cholesky`, `lu`, `qr` — work directly on `ROCArray`. See [Linear Algebra](@ref) for the list of accelerated operations. From f8c247e74d31648294fcb76f04c9792b7d848d85 Mon Sep 17 00:00:00 2001 From: Ludovic Raess Date: Mon, 6 Jul 2026 11:43:55 +0200 Subject: [PATCH 03/10] Add missing bits --- docs/make.jl | 2 ++ docs/src/api/reflection.md | 28 ++++++++++++++++++++++++++++ docs/src/api/system.md | 26 ++++++++++++++++++++++++++ src/utils.jl | 14 ++++++++++++++ 4 files changed, 70 insertions(+) create mode 100644 docs/src/api/reflection.md create mode 100644 docs/src/api/system.md diff --git a/docs/make.jl b/docs/make.jl index 976b38db4..b731e7078 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -44,8 +44,10 @@ function main() ], "API" => [ "Devices" => "api/devices.md", + "System and Configuration" => "api/system.md", "Streams" => "api/streams.md", "Kernel Programming" => "api/kernel_programming.md", + "Reflection" => "api/reflection.md", "Graphs" => "api/graphs.md", "Exceptions" => "api/exceptions.md", "Memory" => "api/memory.md", diff --git a/docs/src/api/reflection.md b/docs/src/api/reflection.md new file mode 100644 index 000000000..5e2696126 --- /dev/null +++ b/docs/src/api/reflection.md @@ -0,0 +1,28 @@ +# Introspection and Reflection + +AMDGPU.jl mirrors Julia's `code_*` reflection tools for GPU kernels, letting you inspect what a kernel lowers to at each compilation stage. This is the main way to debug performance and codegen issues — for example checking that a kernel stays type-stable or that a hot loop vectorizes. + +Each `@device_code_*` macro wraps a kernel launch (`@roc ...`) and prints the corresponding representation instead of running it: + +- `@device_code_lowered` — lowered Julia IR. +- `@device_code_typed` — type-inferred Julia IR (use this to spot type instabilities). +- `@device_code_warntype` — type-inferred IR with instabilities highlighted. +- `@device_code_llvm` — the generated LLVM IR. +- `@device_code_gcn` — the final AMD GCN assembly. +- `@device_code` — dump all of the above into a directory. + +```julia +using AMDGPU + +function vadd!(c, a, b) + i = workitemIdx().x + c[i] = a[i] + b[i] + return +end + +a = AMDGPU.ones(Float32, 16); b = AMDGPU.ones(Float32, 16); c = similar(a) + +@device_code_warntype @roc groupsize=16 vadd!(c, a, b) +``` + +The non-macro forms (`AMDGPU.code_typed`, `AMDGPU.code_llvm`, `AMDGPU.code_gcn`, …) take a function and a tuple of argument types directly, mirroring `Base.code_typed` and friends. These reflection tools are inherited from [GPUCompiler.jl](https://github.com/JuliaGPU/GPUCompiler.jl); see its documentation for the full set of options each macro accepts. diff --git a/docs/src/api/system.md b/docs/src/api/system.md new file mode 100644 index 000000000..fd8474850 --- /dev/null +++ b/docs/src/api/system.md @@ -0,0 +1,26 @@ +# System and Configuration + +## Checking the installation + +`AMDGPU.versioninfo()` prints a full report of detected ROCm libraries, their versions, and the available devices. `AMDGPU.functional()` returns whether AMDGPU.jl can run at all, and `AMDGPU.functional(component)` queries an individual ROCm component (see [FAQ](@ref) for the component list). `has_rocm_gpu()` additionally requires that a GPU device is present. + +```@docs +AMDGPU.versioninfo +AMDGPU.functional +AMDGPU.has_rocm_gpu +``` + +## Configuration preferences + +Several behaviours are configured through [Preferences.jl](https://github.com/JuliaPackaging/Preferences.jl) and persist across sessions (they are written to your project's `LocalPreferences.toml`): + +| Preference | Set via | Effect | +|:--|:--|:--| +| `nonblocking_synchronize` | preference | Use non-blocking stream synchronization (default `true`); disable for slightly lower latency. See [Streams](@ref). | +| `eager_gc` | `AMDGPU.eager_gc!(::Bool)` | Trigger GC before allocations under memory pressure. See [Memory Allocation and Intrinsics](@ref). | +| `hard_memory_limit` | `AMDGPU.hard_memory_limit!("8 GiB")` | Hard cap on GPU memory, checked before every allocation. | +| `soft_memory_limit` | `AMDGPU.soft_memory_limit!("6 GiB")` | Advisory limit for the memory pool. | + +## Debugging kernel launches + +Set the environment variable `HIP_LAUNCH_BLOCKING=1` (or toggle `AMDGPU.LAUNCH_BLOCKING[] = true` at runtime) to make kernel launches synchronous. This makes errors surface at the offending launch rather than at a later synchronization point, which is invaluable when tracking down a crashing or misbehaving kernel. diff --git a/src/utils.jl b/src/utils.jl index 4fab0464f..8c6cbfccd 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -1,3 +1,10 @@ +""" + versioninfo(io::IO=stdout) + +Print a report of the AMDGPU.jl setup: detected ROCm libraries and their +versions, tool paths, and the available GPU devices. Useful as a first +diagnostic when something is missing or not working. +""" function versioninfo(io::IO=stdout) println(io, "AMDGPU versioninfo") _status(st::Bool) = st ? "+" : "-" @@ -102,6 +109,13 @@ function functional(component::Symbol) end end +""" + has_rocm_gpu() -> Bool + +Return `true` if HIP is functional and at least one GPU device is present. +Use this to guard code that specifically requires GPU hardware; for a general +"can AMDGPU.jl run here" check prefer [`AMDGPU.functional`](@ref). +""" has_rocm_gpu() = functional(:hip) && length(devices()) > 0 function print_build_diagnostics() From ca92f74ebd14199461a5c224b31b384f28be8aa4 Mon Sep 17 00:00:00 2001 From: Ludovic Raess Date: Mon, 6 Jul 2026 11:51:31 +0200 Subject: [PATCH 04/10] Add nice to have --- docs/make.jl | 1 + docs/src/index.md | 13 +++++++++++ docs/src/testing.md | 15 +++++++++++++ docs/src/tutorials/custom_structs.md | 33 ++++++++++++++++++++++++++++ 4 files changed, 62 insertions(+) create mode 100644 docs/src/tutorials/custom_structs.md diff --git a/docs/make.jl b/docs/make.jl index b731e7078..60649c5c6 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -32,6 +32,7 @@ function main() "Home" => "index.md", "Tutorials" => [ "Quick Start" => "tutorials/quickstart.md", + "Custom Structs in Kernels" => "tutorials/custom_structs.md", "Performance Tips" => "tutorials/perf.md", "Profiling" => "tutorials/profiling.md", "Installation Tips" => "install_tips.md", diff --git a/docs/src/index.md b/docs/src/index.md index dd1295d1e..4cfb7514d 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -93,6 +93,19 @@ gridsize = cld(length(c), groupsize) @assert (a .+ b) ≈ c ``` +## Feature overview + +| Area | What you get | Learn more | +|:--|:--|:--| +| Arrays | Dense `ROCArray`, broadcasting, reductions, sorting | [Array Programming](usage/arrays.md) | +| Kernels | Native `@roc` kernels and portable [KernelAbstractions](usage/kernelabstractions.md) | [Kernel Programming](api/kernel_programming.md) | +| Multi-GPU | Task-local devices and streams | [Tasks, Streams and Multiple GPUs](usage/multitasking.md) | +| Linear algebra | `*`, `\`, `cholesky`, `lu`, `qr` via rocBLAS/rocSOLVER | [Linear Algebra](libraries/linalg.md) | +| Sparse | CSR/CSC/COO arrays, SpMV/SpMM via rocSPARSE | [Sparse Arrays](libraries/sparse.md) | +| FFT | `fft`/`plan_fft` via rocFFT | [Fourier Transforms](libraries/fft.md) | +| Random | `rand`/`randn` via rocRAND | [Random Numbers](libraries/rand.md) | +| Deep learning | Conv/pooling/softmax via MIOpen (NNlib/Flux) | [Deep Learning (MIOpen)](libraries/dnn.md) | + ## Questions and Contributions Usage questions can be posted on the diff --git a/docs/src/testing.md b/docs/src/testing.md index b7c45e91e..f08271655 100644 --- a/docs/src/testing.md +++ b/docs/src/testing.md @@ -40,3 +40,18 @@ julia> Pkg.test("AMDGPU"; test_args=`gpuarrays`) !!! warning "Large memory tests" Some tests such as HIP and GPUArrays tests may use > 20GB of host RAM. It is recommended to use fewer workers (<= 4) on machines that have < 32Gb of host RAM in case running tests would result in out of memory errors. + +## Building the documentation + +The documentation is built with [Documenter.jl](https://documenter.juliadocs.org) and [DocumenterVitepress.jl](https://github.com/LuxDL/DocumenterVitepress.jl). To build it locally: + +``` +julia --project=docs -e 'using Pkg; Pkg.instantiate()' +julia --project=docs docs/make.jl +julia --project=docs -e 'using LiveServer; serve(dir="docs/build/1")' +``` + +The last command serves the built site locally; open the printed URL in a browser. + +!!! note "Doctests need a GPU" + `make.jl` runs with `doctest=true`, so every ```` ```jldoctest ```` block is executed on a real device. Building the docs therefore requires a functional AMD GPU, and a clean build means all examples still produce their documented output. When writing examples, prefer showing `Array(x)` rather than a raw `ROCArray` so the output does not depend on internal buffer types. diff --git a/docs/src/tutorials/custom_structs.md b/docs/src/tutorials/custom_structs.md new file mode 100644 index 000000000..0069d0b89 --- /dev/null +++ b/docs/src/tutorials/custom_structs.md @@ -0,0 +1,33 @@ +# Using Custom Structs in Kernels + +Kernels often need more than plain arrays — you may want to pass your own struct bundling several arrays and parameters. The difficulty is that a `ROCArray` lives in host memory management, but inside a kernel it must appear as a device array (`ROCDeviceArray`). AMDGPU.jl handles this conversion automatically for arguments to `@roc`, using [Adapt.jl](https://github.com/JuliaGPU/Adapt.jl) to reach *inside* your struct and convert its array fields. + +Declare how your struct should be adapted with `Adapt.@adapt_structure`, then pass an instance to a kernel like any other argument: + +```julia +using AMDGPU, Adapt + +struct Model{A} + weights::A + scale::Float32 +end +Adapt.@adapt_structure Model + +function apply!(out, m) + i = workitemIdx().x + (workgroupIdx().x - 1) * workgroupDim().x + if i <= length(out) + out[i] = m.weights[i] * m.scale + end + return +end + +w = AMDGPU.ones(Float32, 16) +m = Model(w, 3f0) +out = AMDGPU.zeros(Float32, 16) + +@roc groupsize=16 apply!(out, m) # out .== 3.0 +``` + +`@adapt_structure` generates the rule that rebuilds `Model` with each field adapted. When `@roc` launches the kernel it calls `AMDGPU.rocconvert` on `m`, which turns the `weights::ROCArray` field into a `ROCDeviceArray` while leaving `scale` untouched. Inside the kernel `m.weights` is therefore a device array you can index directly. + +The type parameter `A` matters: it lets the struct hold a `ROCArray` on the host and a `ROCDeviceArray` on the device without you writing two types. Keep the remaining fields `isbits` (numbers, tuples, other adapted structs) so the whole struct can be passed to the GPU. From b4c6a019b06a5d8873b2b903bfa6becba5451993 Mon Sep 17 00:00:00 2001 From: Ludovic Raess Date: Mon, 6 Jul 2026 12:06:46 +0200 Subject: [PATCH 05/10] Update --- docs/make.jl | 2 +- docs/src/faq.md | 4 ++++ docs/src/index.md | 2 +- docs/src/install_tips.md | 13 ------------- docs/src/usage/multitasking.md | 2 +- 5 files changed, 7 insertions(+), 16 deletions(-) diff --git a/docs/make.jl b/docs/make.jl index 60649c5c6..a5f03f859 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -40,7 +40,7 @@ function main() ], "Usage" => [ "Array Programming" => "usage/arrays.md", - "Tasks, Streams and Multiple GPUs" => "usage/multitasking.md", + "Tasks and Streams" => "usage/multitasking.md", "KernelAbstractions" => "usage/kernelabstractions.md", ], "API" => [ diff --git a/docs/src/faq.md b/docs/src/faq.md index 900bc2db7..6af6ff262 100644 --- a/docs/src/faq.md +++ b/docs/src/faq.md @@ -44,6 +44,10 @@ AMDGPU.functional(:all) # true only if every component is available Run `AMDGPU.versioninfo()` and check that `hip` and the library you need report as functional. Missing components usually mean the corresponding ROCm package is not installed. See [Installation Info](@ref) for platform-specific setup, including the package list for distributions such as Fedora. +## I'm on Arch Linux and ROCm isn't working + +For the last few ROCm releases, users have reported problems with the distro-provided ROCm builds and associated tools ([#770](https://github.com/JuliaGPU/AMDGPU.jl/issues/770), [#696](https://github.com/JuliaGPU/AMDGPU.jl/issues/696), [#767](https://github.com/JuliaGPU/AMDGPU.jl/issues/767)). Some have had success with the [`opencl-amd-dev`](https://aur.archlinux.org/packages/opencl-amd-dev) AUR package instead. + ## How do I control GPU memory usage? `ROCArray`s are managed by Julia's garbage collector, and a HIP memory pool caches freed allocations. You can free eagerly, cap usage, and query current usage — see the [Memory Allocation and Intrinsics](@ref) page for `AMDGPU.unsafe_free!`, memory limits, and the caching allocator. diff --git a/docs/src/index.md b/docs/src/index.md index 4cfb7514d..3da8e1e9d 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -99,7 +99,7 @@ gridsize = cld(length(c), groupsize) |:--|:--|:--| | Arrays | Dense `ROCArray`, broadcasting, reductions, sorting | [Array Programming](usage/arrays.md) | | Kernels | Native `@roc` kernels and portable [KernelAbstractions](usage/kernelabstractions.md) | [Kernel Programming](api/kernel_programming.md) | -| Multi-GPU | Task-local devices and streams | [Tasks, Streams and Multiple GPUs](usage/multitasking.md) | +| Multi-GPU | Task-local devices and streams | [Tasks and Streams](usage/multitasking.md) | | Linear algebra | `*`, `\`, `cholesky`, `lu`, `qr` via rocBLAS/rocSOLVER | [Linear Algebra](libraries/linalg.md) | | Sparse | CSR/CSC/COO arrays, SpMV/SpMM via rocSPARSE | [Sparse Arrays](libraries/sparse.md) | | FFT | `fft`/`plan_fft` via rocFFT | [Fourier Transforms](libraries/fft.md) | diff --git a/docs/src/install_tips.md b/docs/src/install_tips.md index 94092f295..dadd84a68 100644 --- a/docs/src/install_tips.md +++ b/docs/src/install_tips.md @@ -103,16 +103,3 @@ kernel might throw an exception, specifically during conversions, like: To avoid this, use 'unsafe' conversion option: `unsafe_trunc(Int32, 1f0)`. - -## Frequently-Asked-Questions - -### Archlinux - -For the last few ROCM releases we have seen folks run into -issue with the distro-provided builds of ROCM and associated tools. -[#770](https://github.com/JuliaGPU/AMDGPU.jl/issues/770), -[#696](https://github.com/JuliaGPU/AMDGPU.jl/issues/696), -[#767](https://github.com/JuliaGPU/AMDGPU.jl/issues/767) - -Some users have reported success with using the -[`opencl-amd-dev`](https://aur.archlinux.org/packages/opencl-amd-dev) AUR package. diff --git a/docs/src/usage/multitasking.md b/docs/src/usage/multitasking.md index 1fbb06e8d..7354f0df8 100644 --- a/docs/src/usage/multitasking.md +++ b/docs/src/usage/multitasking.md @@ -1,4 +1,4 @@ -# Tasks, Streams and Multiple GPUs +# Tasks and Streams AMDGPU.jl follows a **task-local** execution model: the active device and stream are properties of the current Julia task. Switching either one affects only the task that makes the switch, so concurrent tasks can drive different devices or streams without interfering with each other. This makes ordinary Julia task-based parallelism the natural way to overlap work and to use several GPUs at once. From 4f197c7260d75cd98e32b4ef73576bec02fe3d80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludovic=20R=C3=A4ss?= <61313342+luraess@users.noreply.github.com> Date: Mon, 6 Jul 2026 14:18:14 +0200 Subject: [PATCH 06/10] Use 1.12 to build docs --- .buildkite/pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index b5a6a7ee5..6d80f6cd2 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -2,7 +2,7 @@ steps: - label: "Documentation" plugins: - JuliaCI/julia#v1: - version: "1.10" + version: "1.12" - sv-oss/node-n#v0.1.2: node-version: v20 command: | From b3a1941918471bf150260f36daf146267d77ed82 Mon Sep 17 00:00:00 2001 From: Ludovic Raess Date: Mon, 6 Jul 2026 14:43:37 +0200 Subject: [PATCH 07/10] Fixup 1.12 --- .buildkite/pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index 6d80f6cd2..ebb6c28d1 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -18,7 +18,7 @@ steps: Pkg.build() Pkg.activate("docs") - Pkg.add(; path=".") + Pkg.develop(PackageSpec(path=".")) Pkg.instantiate() push!(LOAD_PATH, @__DIR__) From 444d40b4e9f873b3c0a1fb9939fcf89fbd043d63 Mon Sep 17 00:00:00 2001 From: Ludovic Raess Date: Mon, 6 Jul 2026 15:15:52 +0200 Subject: [PATCH 08/10] Add svd --- docs/src/libraries/linalg.md | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/docs/src/libraries/linalg.md b/docs/src/libraries/linalg.md index 5bd920ea9..24eb3a00f 100644 --- a/docs/src/libraries/linalg.md +++ b/docs/src/libraries/linalg.md @@ -14,7 +14,7 @@ Supported out of the box on `ROCArray`: - Matrix–matrix and matrix–vector products (`*`, `mul!`), including mixed- and low-precision (`Float16`) matmul. - BLAS level-1 operations: `dot`, `norm`, `axpy!`, `axpby!`, `rmul!`. - Triangular solves and `\` (linear systems, LU-based). -- Factorizations: `cholesky`, `lu`, `qr`. +- Factorizations: `cholesky`, `lu`, `qr`, `svd`. ```jldoctest linalg julia> A = ROCArray(Float32[4 1; 1 3]); @@ -34,7 +34,20 @@ true Element types follow rocBLAS/rocSOLVER: `Float32`, `Float64`, `ComplexF32`, and `ComplexF64` (with `Float16` also supported for matmul). -## Direct library access +## Singular value decomposition + +`svd`, `svd!`, and `svdvals` run on `ROCMatrix` via rocSOLVER. The `alg` keyword selects the backend — `JacobiAlgorithm()` (the default, usually fastest on AMD GPUs) or `QRAlgorithm()`: -Lower-level routines are available in the `AMDGPU.rocBLAS` and `AMDGPU.rocSOLVER` submodules for cases the generic interface does not cover — for example singular value decomposition via `AMDGPU.rocSOLVER.gesvd!`, or batched factorizations. The generic `LinearAlgebra.svd`/`svdvals` are **not** GPU-accelerated and fall back to the CPU, so use `gesvd!` directly for on-device SVD. +```julia +using AMDGPU.rocSOLVER: JacobiAlgorithm, QRAlgorithm + +F = svd(A) # Jacobi by default; F.U, F.S, F.Vt +s = svdvals(A) # singular values only +Ff = svd(A; full = true, alg = QRAlgorithm()) ``` + +Because `svdvals` is supported, so is `cond`. (`opnorm(A, 2)` is not yet available — it relies on scalar indexing internal to `LinearAlgebra`.) + +## Direct library access + +Lower-level routines are available in the `AMDGPU.rocBLAS` and `AMDGPU.rocSOLVER` submodules for cases the generic interface does not cover — for example batched factorizations, or the raw `gesvd!` (QR) and `gesvdj!` (Jacobi) SVD kernels. From f1f934ce75ff1c3e6cb2338dc8044dc8fea53bca Mon Sep 17 00:00:00 2001 From: Ludovic Raess Date: Mon, 6 Jul 2026 15:16:04 +0200 Subject: [PATCH 09/10] Typos --- docs/src/libraries/dnn.md | 1 - docs/src/libraries/fft.md | 1 - docs/src/libraries/rand.md | 1 - docs/src/libraries/sparse.md | 1 - 4 files changed, 4 deletions(-) diff --git a/docs/src/libraries/dnn.md b/docs/src/libraries/dnn.md index ffea0d77e..2b0a973db 100644 --- a/docs/src/libraries/dnn.md +++ b/docs/src/libraries/dnn.md @@ -12,4 +12,3 @@ AMDGPU.functional(:MIOpen) ``` If it reports `false`, install the MIOpen ROCm package for your platform (see [Installation Info](@ref)). -``` diff --git a/docs/src/libraries/fft.md b/docs/src/libraries/fft.md index 7f710030a..055865c62 100644 --- a/docs/src/libraries/fft.md +++ b/docs/src/libraries/fft.md @@ -33,4 +33,3 @@ p! * x ``` Multidimensional transforms and transforms over selected dimensions work as usual, e.g. `fft(x, (1, 2))` for a 2D transform of a higher-dimensional array. -``` diff --git a/docs/src/libraries/rand.md b/docs/src/libraries/rand.md index 74d705360..dc989fec4 100644 --- a/docs/src/libraries/rand.md +++ b/docs/src/libraries/rand.md @@ -29,4 +29,3 @@ AMDGPU.seed!(1234) ``` This seeds both the rocRAND generator (used by `AMDGPU.rand`/`randn`) and the GPUArrays fallback generator, so results are reproducible regardless of which path a given operation takes. -``` diff --git a/docs/src/libraries/sparse.md b/docs/src/libraries/sparse.md index 59523c4f0..d27e3cdbd 100644 --- a/docs/src/libraries/sparse.md +++ b/docs/src/libraries/sparse.md @@ -32,4 +32,3 @@ Y = dS * B # SpMM ``` Incomplete-factorization preconditioners (`ic0`, `ilu0`) and further sparse routines (conversions between formats, triangular solves, gather/scatter) are available in the `AMDGPU.rocSPARSE` submodule for building iterative solvers on the GPU. -``` From 50588f306e5a9fa2ed4f67672a4089be02d915af Mon Sep 17 00:00:00 2001 From: Ludovic Raess Date: Mon, 6 Jul 2026 15:58:47 +0200 Subject: [PATCH 10/10] Improve doc --- docs/src/usage/arrays.md | 17 +++++++++++++++++ src/array.jl | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/docs/src/usage/arrays.md b/docs/src/usage/arrays.md index 378d2a0e3..a7c22f4c9 100644 --- a/docs/src/usage/arrays.md +++ b/docs/src/usage/arrays.md @@ -28,6 +28,23 @@ julia> AMDGPU.ones(Float32, 2, 2) |> Array The device-side constructors mirror `Base`: `AMDGPU.zeros`, `AMDGPU.ones`, `AMDGPU.fill`, `AMDGPU.rand`, `AMDGPU.randn`, and `similar`. All take an optional element type and dimensions. +Alternatively, `roc` copies to the device while narrowing floating-point element types to 32-bit — handy when single precision is preferred for performance. It also recurses into custom structs, converting their array fields: + +```jldoctest arrays +julia> x = roc([1.0, 2.0, 3.0]); # Float64 host array + +julia> eltype(x) # narrowed to Float32 on the device +Float32 + +julia> x isa ROCArray +true +``` + +```@docs +AMDGPU.ROCArray +AMDGPU.roc +``` + ## Host ↔ device transfer Wrapping a host array in `ROCArray` copies it to the GPU; calling `Array` on a `ROCArray` copies it back: diff --git a/src/array.jl b/src/array.jl index 451d67fa5..351a7b111 100644 --- a/src/array.jl +++ b/src/array.jl @@ -1,3 +1,21 @@ +""" + ROCArray{T,N,B} <: AbstractGPUArray{T,N} + +`N`-dimensional dense array of element type `T` stored in GPU memory (backed by +buffer type `B`). `ROCArray` implements Julia's `AbstractArray` interface, so +broadcasting, reductions, and linear algebra run on the GPU. + +Copy a host array to the device by wrapping it, or allocate directly: + +```julia +ROCArray([1, 2, 3]) # copy a host array to the device +ROCArray{Float32}(undef, 4, 4) # uninitialized 4×4 device matrix +``` + +Move data back to the host with `Array(x)`. See also [`roc`](@ref), which +copies to the device while narrowing floating-point types to 32-bit, and the +`AMDGPU.zeros` / `AMDGPU.ones` / `AMDGPU.rand` constructors. +""" mutable struct ROCArray{T, N, B} <: AbstractGPUArray{T, N} buf::DataRef{Managed{B}} dims::Dims{N} @@ -295,6 +313,24 @@ Adapt.adapt_storage(::Float32Adaptor, xs::AbstractArray{<:Complex{<:AbstractFloa Adapt.adapt_storage(::Float32Adaptor, xs::AbstractArray{Float16}) = isbits(xs) ? xs : convert(ROCArray, xs) +""" + roc(x) + +Adapt `x` for the GPU: convert arrays to [`ROCArray`](@ref) while **narrowing +floating-point element types to 32-bit** (`Float64`→`Float32`, +`ComplexF64`→`ComplexF32`; `Float16` is left unchanged, other element types are +preserved). Like `Adapt.adapt`, it recurses into custom structs and converts +their array fields. + +This mirrors CUDA.jl's `cu`. Reach for it when single precision is preferred +(e.g. for performance); use the [`ROCArray`](@ref) constructor directly to keep +the original element type. + +```julia +roc([1.0, 2.0]) # 2-element ROCArray{Float32} +roc(1:3) # non-float eltype preserved: ROCArray{Int64} +``` +""" roc(xs) = adapt(Float32Adaptor(), xs) Base.unsafe_convert(typ::Type{Ptr{T}}, x::ROCArray{T}) where T =