From 32558febc5e59f242e59703191ddb7a555f84624 Mon Sep 17 00:00:00 2001 From: Christian Guinard <28689358+christiangnrd@users.noreply.github.com> Date: Sun, 20 Jul 2025 18:09:30 -0300 Subject: [PATCH 01/14] POC `supports_unified` --- src/KernelAbstractions.jl | 39 +++++++++++++++++++++++++++------------ test/test.jl | 9 +++++++++ 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/src/KernelAbstractions.jl b/src/KernelAbstractions.jl index f6982c61..bc6b1975 100644 --- a/src/KernelAbstractions.jl +++ b/src/KernelAbstractions.jl @@ -532,40 +532,55 @@ get_backend(::Array) = CPU() Adapt.adapt_storage(::CPU, a::Array) = a """ - allocate(::Backend, Type, dims...)::AbstractArray + allocate(::Backend, Type, dims...; unified=false)::AbstractArray -Allocate a storage array appropriate for the computational backend. +Allocate a storage array appropriate for the computational backend. `unified` +allocates an array using unified memory if the backend supports it. Use +[`supports_unified`](@ref) to determine whether it is supported by a backend. !!! note Backend implementations **must** implement `allocate(::NewBackend, T, dims::Tuple)` """ -allocate(backend::Backend, T::Type, dims...) = allocate(backend, T, dims) -allocate(backend::Backend, T::Type, dims::Tuple) = throw(MethodError(allocate, (backend, T, dims))) +allocate(backend::Backend, T::Type, dims...; unified=false) = allocate(backend, T, dims; unified) +allocate(backend::Backend, T::Type, dims::Tuple; unified=false) = throw(MethodError(allocate, (backend, T, dims))) """ - zeros(::Backend, Type, dims...)::AbstractArray + zeros(::Backend, Type, dims...; unified=false)::AbstractArray Allocate a storage array appropriate for the computational backend filled with zeros. +`unified` allocates an array using unified memory if the backend supports it. """ -zeros(backend::Backend, T::Type, dims...) = zeros(backend, T, dims) -function zeros(backend::Backend, ::Type{T}, dims::Tuple) where {T} - data = allocate(backend, T, dims...) +zeros(backend::Backend, T::Type, dims...; kwargs...) = zeros(backend, T, dims; kwargs...) +function zeros(backend::Backend, ::Type{T}, dims::Tuple; unified=false) where {T} + data = allocate(backend, T, dims...; unified) fill!(data, zero(T)) return data end """ - ones(::Backend, Type, dims...)::AbstractArray + ones(::Backend, Type, dims...; unified=false)::AbstractArray Allocate a storage array appropriate for the computational backend filled with ones. +`unified` allocates an array using unified memory if the backend supports it. """ -ones(backend::Backend, T::Type, dims...) = ones(backend, T, dims) -function ones(backend::Backend, ::Type{T}, dims::Tuple) where {T} - data = allocate(backend, T, dims) +ones(backend::Backend, T::Type, dims...; kwargs...) = ones(backend, T, dims; kwargs...) +function ones(backend::Backend, ::Type{T}, dims::Tuple; unified=false) where {T} + data = allocate(backend, T, dims; unified) fill!(data, one(T)) return data end +""" + supports_unified(::Backend)::Bool + +Returns whether unified memory arrays are supported by the backend. + +!!! note + Backend implementations **must** implement this function + only if they **do not** support unified memory. +""" +supports_unified(::Backend) = true + """ supports_atomics(::Backend)::Bool diff --git a/test/test.jl b/test/test.jl index 7de6da0b..0771a9ba 100644 --- a/test/test.jl +++ b/test/test.jl @@ -78,6 +78,15 @@ function unittest_testsuite(Backend, backend_str, backend_mod, BackendArrayT; sk backendT = typeof(backend).name.wrapper # To look through CUDABackend{true, false} @test backend isa backendT + unified = supports_unified(backend) + @test unified isa Bool + U = allocate(backend, Float32, 5; unified) + if unified + @test U[3] isa Float32 + else + @test_throws U[3] + end + x = allocate(backend, Float32, 5) A = allocate(backend, Float32, 5, 5) @test @inferred(KernelAbstractions.get_backend(A)) isa backendT From eaaff4ce397cf720b25c8edef3bf65d164df3574 Mon Sep 17 00:00:00 2001 From: Christian Guinard <28689358+christiangnrd@users.noreply.github.com> Date: Sun, 20 Jul 2025 18:17:31 -0300 Subject: [PATCH 02/14] Formatting --- src/KernelAbstractions.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/KernelAbstractions.jl b/src/KernelAbstractions.jl index bc6b1975..a6e81a35 100644 --- a/src/KernelAbstractions.jl +++ b/src/KernelAbstractions.jl @@ -541,8 +541,8 @@ allocates an array using unified memory if the backend supports it. Use !!! note Backend implementations **must** implement `allocate(::NewBackend, T, dims::Tuple)` """ -allocate(backend::Backend, T::Type, dims...; unified=false) = allocate(backend, T, dims; unified) -allocate(backend::Backend, T::Type, dims::Tuple; unified=false) = throw(MethodError(allocate, (backend, T, dims))) +allocate(backend::Backend, T::Type, dims...; unified = false) = allocate(backend, T, dims; unified) +allocate(backend::Backend, T::Type, dims::Tuple; unified = false) = throw(MethodError(allocate, (backend, T, dims))) """ zeros(::Backend, Type, dims...; unified=false)::AbstractArray @@ -551,7 +551,7 @@ Allocate a storage array appropriate for the computational backend filled with z `unified` allocates an array using unified memory if the backend supports it. """ zeros(backend::Backend, T::Type, dims...; kwargs...) = zeros(backend, T, dims; kwargs...) -function zeros(backend::Backend, ::Type{T}, dims::Tuple; unified=false) where {T} +function zeros(backend::Backend, ::Type{T}, dims::Tuple; unified = false) where {T} data = allocate(backend, T, dims...; unified) fill!(data, zero(T)) return data @@ -564,7 +564,7 @@ Allocate a storage array appropriate for the computational backend filled with o `unified` allocates an array using unified memory if the backend supports it. """ ones(backend::Backend, T::Type, dims...; kwargs...) = ones(backend, T, dims; kwargs...) -function ones(backend::Backend, ::Type{T}, dims::Tuple; unified=false) where {T} +function ones(backend::Backend, ::Type{T}, dims::Tuple; unified = false) where {T} data = allocate(backend, T, dims; unified) fill!(data, one(T)) return data From 0361db4d244f3da94684ad349d4898a808cc6828 Mon Sep 17 00:00:00 2001 From: Christian Guinard <28689358+christiangnrd@users.noreply.github.com> Date: Mon, 21 Jul 2025 14:58:26 -0300 Subject: [PATCH 03/14] Address feedback --- src/KernelAbstractions.jl | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/KernelAbstractions.jl b/src/KernelAbstractions.jl index a6e81a35..138c2a88 100644 --- a/src/KernelAbstractions.jl +++ b/src/KernelAbstractions.jl @@ -541,8 +541,17 @@ allocates an array using unified memory if the backend supports it. Use !!! note Backend implementations **must** implement `allocate(::NewBackend, T, dims::Tuple)` """ -allocate(backend::Backend, T::Type, dims...; unified = false) = allocate(backend, T, dims; unified) -allocate(backend::Backend, T::Type, dims::Tuple; unified = false) = throw(MethodError(allocate, (backend, T, dims))) +allocate(backend::Backend, T::Type, dims...; kwargs...) = allocate(backend, T, dims; kwargs...) +function allocate(backend::Backend, T::Type, dims::Tuple; unified::Union{Nothing, Bool} = nothing) + if isnothing(unified) + throw(MethodError(allocate, (backend, T, dims))) + elseif unified + throw(ArgumentError("`$(typeof(backend))` either does not support unified memory or it has not yet defined `allocate(backend::$backend, T::Type, dims::Tuple; unified::Bool)`")) + else + allocate(backend, T, dims) + end +end + """ zeros(::Backend, Type, dims...; unified=false)::AbstractArray @@ -551,8 +560,8 @@ Allocate a storage array appropriate for the computational backend filled with z `unified` allocates an array using unified memory if the backend supports it. """ zeros(backend::Backend, T::Type, dims...; kwargs...) = zeros(backend, T, dims; kwargs...) -function zeros(backend::Backend, ::Type{T}, dims::Tuple; unified = false) where {T} - data = allocate(backend, T, dims...; unified) +function zeros(backend::Backend, ::Type{T}, dims::Tuple; kwargs...) where {T} + data = allocate(backend, T, dims...; kwargs...) fill!(data, zero(T)) return data end @@ -564,8 +573,8 @@ Allocate a storage array appropriate for the computational backend filled with o `unified` allocates an array using unified memory if the backend supports it. """ ones(backend::Backend, T::Type, dims...; kwargs...) = ones(backend, T, dims; kwargs...) -function ones(backend::Backend, ::Type{T}, dims::Tuple; unified = false) where {T} - data = allocate(backend, T, dims; unified) +function ones(backend::Backend, ::Type{T}, dims::Tuple; kwargs...) where {T} + data = allocate(backend, T, dims; kwargs...) fill!(data, one(T)) return data end @@ -577,9 +586,9 @@ Returns whether unified memory arrays are supported by the backend. !!! note Backend implementations **must** implement this function - only if they **do not** support unified memory. + only if they **do** support unified memory. """ -supports_unified(::Backend) = true +supports_unified(::Backend) = false """ supports_atomics(::Backend)::Bool From 45393124e1c00437f079ff3fa6a61a0b42e69f61 Mon Sep 17 00:00:00 2001 From: Christian Guinard <28689358+christiangnrd@users.noreply.github.com> Date: Mon, 21 Jul 2025 15:05:20 -0300 Subject: [PATCH 04/14] Format & fix --- src/KernelAbstractions.jl | 2 +- test/test.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/KernelAbstractions.jl b/src/KernelAbstractions.jl index 138c2a88..2983969b 100644 --- a/src/KernelAbstractions.jl +++ b/src/KernelAbstractions.jl @@ -543,7 +543,7 @@ allocates an array using unified memory if the backend supports it. Use """ allocate(backend::Backend, T::Type, dims...; kwargs...) = allocate(backend, T, dims; kwargs...) function allocate(backend::Backend, T::Type, dims::Tuple; unified::Union{Nothing, Bool} = nothing) - if isnothing(unified) + return if isnothing(unified) throw(MethodError(allocate, (backend, T, dims))) elseif unified throw(ArgumentError("`$(typeof(backend))` either does not support unified memory or it has not yet defined `allocate(backend::$backend, T::Type, dims::Tuple; unified::Bool)`")) diff --git a/test/test.jl b/test/test.jl index 0771a9ba..0dd01206 100644 --- a/test/test.jl +++ b/test/test.jl @@ -84,7 +84,7 @@ function unittest_testsuite(Backend, backend_str, backend_mod, BackendArrayT; sk if unified @test U[3] isa Float32 else - @test_throws U[3] + @test_throws ErrorException U[3] end x = allocate(backend, Float32, 5) From 24eeb5590eb970787f1980d53a138709e697a528 Mon Sep 17 00:00:00 2001 From: Christian Guinard <28689358+christiangnrd@users.noreply.github.com> Date: Mon, 21 Jul 2025 15:18:50 -0300 Subject: [PATCH 05/14] Fix test --- test/test.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test.jl b/test/test.jl index 0dd01206..9a818be1 100644 --- a/test/test.jl +++ b/test/test.jl @@ -78,7 +78,7 @@ function unittest_testsuite(Backend, backend_str, backend_mod, BackendArrayT; sk backendT = typeof(backend).name.wrapper # To look through CUDABackend{true, false} @test backend isa backendT - unified = supports_unified(backend) + unified = KernelAbstractions.supports_unified(backend) @test unified isa Bool U = allocate(backend, Float32, 5; unified) if unified From 9225caace578cfe5ba0399527d8e4fa302f850e0 Mon Sep 17 00:00:00 2001 From: Christian Guinard <28689358+christiangnrd@users.noreply.github.com> Date: Mon, 21 Jul 2025 15:21:18 -0300 Subject: [PATCH 06/14] Only test if unified memory is explicitly supported --- test/test.jl | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/test.jl b/test/test.jl index 9a818be1..241deb5c 100644 --- a/test/test.jl +++ b/test/test.jl @@ -83,8 +83,6 @@ function unittest_testsuite(Backend, backend_str, backend_mod, BackendArrayT; sk U = allocate(backend, Float32, 5; unified) if unified @test U[3] isa Float32 - else - @test_throws ErrorException U[3] end x = allocate(backend, Float32, 5) From 6b405a39c63ad10c42c4516e7a357c351c09a1d6 Mon Sep 17 00:00:00 2001 From: Christian Guinard <28689358+christiangnrd@users.noreply.github.com> Date: Mon, 21 Jul 2025 18:12:32 -0300 Subject: [PATCH 07/14] Format feedback --- src/KernelAbstractions.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/KernelAbstractions.jl b/src/KernelAbstractions.jl index 2983969b..217e3ed7 100644 --- a/src/KernelAbstractions.jl +++ b/src/KernelAbstractions.jl @@ -543,12 +543,12 @@ allocates an array using unified memory if the backend supports it. Use """ allocate(backend::Backend, T::Type, dims...; kwargs...) = allocate(backend, T, dims; kwargs...) function allocate(backend::Backend, T::Type, dims::Tuple; unified::Union{Nothing, Bool} = nothing) - return if isnothing(unified) + if isnothing(unified) throw(MethodError(allocate, (backend, T, dims))) elseif unified throw(ArgumentError("`$(typeof(backend))` either does not support unified memory or it has not yet defined `allocate(backend::$backend, T::Type, dims::Tuple; unified::Bool)`")) else - allocate(backend, T, dims) + return allocate(backend, T, dims) end end From e0e1ea3558c4df99c0ce462c322bdac5cd3ad5c0 Mon Sep 17 00:00:00 2001 From: Christian Guinard <28689358+christiangnrd@users.noreply.github.com> Date: Tue, 22 Jul 2025 09:43:45 -0300 Subject: [PATCH 08/14] Update docstring and shorten error --- src/KernelAbstractions.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/KernelAbstractions.jl b/src/KernelAbstractions.jl index 217e3ed7..6f8d3ab0 100644 --- a/src/KernelAbstractions.jl +++ b/src/KernelAbstractions.jl @@ -540,13 +540,14 @@ allocates an array using unified memory if the backend supports it. Use !!! note Backend implementations **must** implement `allocate(::NewBackend, T, dims::Tuple)` + Backend implementations **should** implement `allocate(::NewBackend, T, dims::Tuple; unified::Bool=false)` """ allocate(backend::Backend, T::Type, dims...; kwargs...) = allocate(backend, T, dims; kwargs...) function allocate(backend::Backend, T::Type, dims::Tuple; unified::Union{Nothing, Bool} = nothing) if isnothing(unified) throw(MethodError(allocate, (backend, T, dims))) elseif unified - throw(ArgumentError("`$(typeof(backend))` either does not support unified memory or it has not yet defined `allocate(backend::$backend, T::Type, dims::Tuple; unified::Bool)`")) + throw(ArgumentError("`$(typeof(backend))` does not support unified memory. If you believe it does, please open a github issue.")) else return allocate(backend, T, dims) end From f72296195535c2b32f3e453ddfbf338d1372ac2a Mon Sep 17 00:00:00 2001 From: Christian Guinard <28689358+christiangnrd@users.noreply.github.com> Date: Tue, 22 Jul 2025 10:19:05 -0300 Subject: [PATCH 09/14] Add CPU definition --- src/cpu.jl | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/cpu.jl b/src/cpu.jl index ac1f970f..01c3334f 100644 --- a/src/cpu.jl +++ b/src/cpu.jl @@ -1,16 +1,16 @@ unsafe_free!(::AbstractArray) = return synchronize(::CPU) = nothing -allocate(::CPU, ::Type{T}, dims::Tuple) where {T} = Array{T}(undef, dims) +allocate(::CPU, ::Type{T}, dims::Tuple; unified::Bool=false) where {T} = Array{T}(undef, dims) -function zeros(backend::CPU, ::Type{T}, dims::Tuple) where {T} - arr = allocate(backend, T, dims) +function zeros(backend::CPU, ::Type{T}, dims::Tuple; kwargs...) where {T} + arr = allocate(backend, T, dims; kwargs...) kernel = init_kernel(backend) kernel(arr, zero, T, ndrange = length(arr)) return arr end -function ones(backend::CPU, ::Type{T}, dims::Tuple) where {T} - arr = allocate(backend, T, dims) +function ones(backend::CPU, ::Type{T}, dims::Tuple; kwargs...) where {T} + arr = allocate(backend, T, dims; kwargs...) kernel = init_kernel(backend) kernel(arr, one, T; ndrange = length(arr)) return arr @@ -34,6 +34,7 @@ end functional(::CPU) = true pagelock!(::CPU, x) = nothing +supports_unified(::CPU) = true function (obj::Kernel{CPU})(args...; ndrange = nothing, workgroupsize = nothing) ndrange, workgroupsize, iterspace, dynamic = launch_config(obj, ndrange, workgroupsize) From 0ecfc05215fb236657d70c0f9796eacc0ef037c1 Mon Sep 17 00:00:00 2001 From: Christian Guinard <28689358+christiangnrd@users.noreply.github.com> Date: Tue, 22 Jul 2025 10:27:55 -0300 Subject: [PATCH 10/14] Enforcing unified support would be breaking --- src/KernelAbstractions.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/KernelAbstractions.jl b/src/KernelAbstractions.jl index 6f8d3ab0..9c262074 100644 --- a/src/KernelAbstractions.jl +++ b/src/KernelAbstractions.jl @@ -586,8 +586,9 @@ end Returns whether unified memory arrays are supported by the backend. !!! note - Backend implementations **must** implement this function - only if they **do** support unified memory. + Backend implementations **should** implement this function + only if they **do** support unified memory. It will be required + in KernelAbstractions 0.10. """ supports_unified(::Backend) = false From 38f618065736ec44e968df0d75424796d2f7876a Mon Sep 17 00:00:00 2001 From: Christian Guinard <28689358+christiangnrd@users.noreply.github.com> Date: Tue, 22 Jul 2025 10:32:44 -0300 Subject: [PATCH 11/14] Feedback --- src/KernelAbstractions.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/KernelAbstractions.jl b/src/KernelAbstractions.jl index 9c262074..65ec2cb0 100644 --- a/src/KernelAbstractions.jl +++ b/src/KernelAbstractions.jl @@ -587,8 +587,7 @@ Returns whether unified memory arrays are supported by the backend. !!! note Backend implementations **should** implement this function - only if they **do** support unified memory. It will be required - in KernelAbstractions 0.10. + only if they **do** support unified memory. """ supports_unified(::Backend) = false From 811e0f7addb9dc251eac85d64fd7f8629ff99b68 Mon Sep 17 00:00:00 2001 From: Christian Guinard <28689358+christiangnrd@users.noreply.github.com> Date: Tue, 22 Jul 2025 10:56:55 -0300 Subject: [PATCH 12/14] Update docstrings --- src/KernelAbstractions.jl | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/KernelAbstractions.jl b/src/KernelAbstractions.jl index 65ec2cb0..8ef7c071 100644 --- a/src/KernelAbstractions.jl +++ b/src/KernelAbstractions.jl @@ -534,9 +534,9 @@ Adapt.adapt_storage(::CPU, a::Array) = a """ allocate(::Backend, Type, dims...; unified=false)::AbstractArray -Allocate a storage array appropriate for the computational backend. `unified` -allocates an array using unified memory if the backend supports it. Use -[`supports_unified`](@ref) to determine whether it is supported by a backend. +Allocate a storage array appropriate for the computational backend. `unified=true` +allocates an array using unified memory if the backend supports it and throws otherwise. +Use [`supports_unified`](@ref) to determine whether it is supported by a backend. !!! note Backend implementations **must** implement `allocate(::NewBackend, T, dims::Tuple)` @@ -558,7 +558,8 @@ end zeros(::Backend, Type, dims...; unified=false)::AbstractArray Allocate a storage array appropriate for the computational backend filled with zeros. -`unified` allocates an array using unified memory if the backend supports it. +`unified=true` allocates an array using unified memory if the backend supports it and +throws otherwise. """ zeros(backend::Backend, T::Type, dims...; kwargs...) = zeros(backend, T, dims; kwargs...) function zeros(backend::Backend, ::Type{T}, dims::Tuple; kwargs...) where {T} @@ -571,7 +572,8 @@ end ones(::Backend, Type, dims...; unified=false)::AbstractArray Allocate a storage array appropriate for the computational backend filled with ones. -`unified` allocates an array using unified memory if the backend supports it. +`unified=true` allocates an array using unified memory if the backend supports it and +throws otherwise. """ ones(backend::Backend, T::Type, dims...; kwargs...) = ones(backend, T, dims; kwargs...) function ones(backend::Backend, ::Type{T}, dims::Tuple; kwargs...) where {T} From bf835b625000747c11dbde0da838a54924abd6c9 Mon Sep 17 00:00:00 2001 From: Christian Guinard <28689358+christiangnrd@users.noreply.github.com> Date: Tue, 22 Jul 2025 11:00:04 -0300 Subject: [PATCH 13/14] Format --- src/cpu.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cpu.jl b/src/cpu.jl index 01c3334f..7ee78663 100644 --- a/src/cpu.jl +++ b/src/cpu.jl @@ -1,7 +1,7 @@ unsafe_free!(::AbstractArray) = return synchronize(::CPU) = nothing -allocate(::CPU, ::Type{T}, dims::Tuple; unified::Bool=false) where {T} = Array{T}(undef, dims) +allocate(::CPU, ::Type{T}, dims::Tuple; unified::Bool = false) where {T} = Array{T}(undef, dims) function zeros(backend::CPU, ::Type{T}, dims::Tuple; kwargs...) where {T} arr = allocate(backend, T, dims; kwargs...) From c4a174a11edc01734dd10d9745c45d75caf6a57b Mon Sep 17 00:00:00 2001 From: Christian Guinard <28689358+christiangnrd@users.noreply.github.com> Date: Tue, 22 Jul 2025 11:44:06 -0300 Subject: [PATCH 14/14] Add `supports_unified` to docs --- docs/src/api.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/src/api.md b/docs/src/api.md index 9373d231..4e107075 100644 --- a/docs/src/api.md +++ b/docs/src/api.md @@ -21,6 +21,7 @@ allocate ```@docs KernelAbstractions.zeros +KernelAbstractions.supports_unified ``` ## Internal