Skip to content

Commit 5427d33

Browse files
authored
Add implementation notes to host functionality (#401)
1 parent 606b2c5 commit 5427d33

File tree

3 files changed

+99
-17
lines changed

3 files changed

+99
-17
lines changed

src/KernelAbstractions.jl

Lines changed: 71 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@ KernelAbstractions primitives can be used in non-kernel functions.
6666
6767
!!! warn
6868
This is an experimental feature.
69-
7069
"""
7170
macro kernel(config, expr)
7271
if config isa Expr && config.head == :(=) &&
@@ -97,13 +96,19 @@ macro Const end
9796
copyto!(::Backend, dest::AbstractArray, src::AbstractArray)
9897
9998
Perform a `copyto!` operation that execution ordered with respect to the backend.
99+
100+
!!! note
101+
Backend implementations **must** implement this function.
100102
"""
101103
function copyto! end
102104

103105
"""
104106
synchronize(::Backend)
105107
106108
Synchronize the current backend.
109+
110+
!!! note
111+
Backend implementations **must** implement this function.
107112
"""
108113
function synchronize end
109114

@@ -114,12 +119,13 @@ Release the memory of an array for reuse by future allocations
114119
and reduce pressure on the allocator.
115120
After releasing the memory of an array, it should no longer be accessed.
116121
117-
This function is optional both to implement and call.
118-
If not implemented for a particular backend, default action is a no-op.
119-
Otherwise, it should be defined for backend's array type.
120-
121122
!!! note
122123
On CPU backend this is always a no-op.
124+
125+
!!! note
126+
Backend implementations **may** implement this function.
127+
If not implemented for a particular backend, default action is a no-op.
128+
Otherwise, it should be defined for backend's array type.
123129
"""
124130
function unsafe_free! end
125131

@@ -393,9 +399,17 @@ constify(arg) = adapt(ConstAdaptor(), arg)
393399
###
394400

395401
"""
396-
Abstract type for all KernelAbstractions backends.
402+
403+
Abstract type for all KernelAbstractions backends.
397404
"""
398405
abstract type Backend end
406+
407+
"""
408+
Abstract type for all GPU based KernelAbstractions backends.
409+
410+
!!! note
411+
New backend implementations **must** sub-type this abstract type.
412+
"""
399413
abstract type GPU <: Backend end
400414

401415
"""
@@ -412,6 +426,11 @@ struct CPU <: Backend
412426
CPU(;static::Bool=false) = new(static)
413427
end
414428

429+
"""
430+
isgpu(::Backend)::Bool
431+
432+
Returns true for all [`GPU`](@ref) backends.
433+
"""
415434
isgpu(::GPU) = true
416435
isgpu(::CPU) = false
417436

@@ -420,6 +439,10 @@ isgpu(::CPU) = false
420439
get_backend(A::AbstractArray)::Backend
421440
422441
Get a [`Backend`](@ref) instance suitable for array `A`.
442+
443+
!!! note
444+
Backend implementations **must** provide `get_backend` for their custom array type.
445+
It should be the same as the return type of [`allocate`](@ref)
423446
"""
424447
function get_backend end
425448

@@ -438,39 +461,61 @@ get_backend(::Array) = CPU()
438461
Adapt.adapt_storage(::CPU, a::Array) = a
439462

440463
"""
441-
allocate(::Backend, Type, dims...)
464+
allocate(::Backend, Type, dims...)::AbstractArray
442465
443466
Allocate a storage array appropriate for the computational backend.
467+
468+
!!! note
469+
Backend implementations **must** implement `allocate(::NewBackend, T, dims::Tuple)`
470+
"""
471+
allocate(backend::Backend, T, dims...) = allocate(backend, T, dims)
472+
allocate(backend::Backend, T, dims::Tuple) = throw(MethodError(allocate, (backend, T, dims)))
473+
444474
"""
445-
allocate(backend, T, dims...) = return allocate(backend, T, dims)
475+
zeros(::Backend, Type, dims...)::AbstractArray
446476
447-
zeros(backend, T, dims...) = zeros(backend, T, dims)
448-
function zeros(backend, ::Type{T}, dims::Tuple) where T
477+
Allocate a storage array appropriate for the computational backend filled with zeros.
478+
"""
479+
zeros(backend::Backend, T, dims...) = zeros(backend, T, dims)
480+
function zeros(backend::Backend, ::Type{T}, dims::Tuple) where T
449481
data = allocate(backend, T, dims...)
450482
fill!(data, zero(T))
451483
return data
452484
end
453485

454-
ones(backend, T, dims...) = ones(backend, T, dims)
455-
function ones(backend, ::Type{T}, dims::Tuple) where T
486+
"""
487+
ones(::Backend, Type, dims...)::AbstractArray
488+
489+
Allocate a storage array appropriate for the computational backend filled with ones.
490+
"""
491+
ones(backend::Backend, T, dims...) = ones(backend, T, dims)
492+
function ones(backend::Backend, ::Type{T}, dims::Tuple) where T
456493
data = allocate(backend, T, dims)
457494
fill!(data, one(T))
458495
return data
459496
end
460497

461498
"""
462-
supports_atomics(::Backend)
499+
supports_atomics(::Backend)::Bool
463500
464501
Returns whether `@atomic` operations are supported by the backend.
502+
503+
!!! note
504+
Backend implementations **must** implement this function,
505+
only if they **do not** support atomic operations with Atomix.
465506
"""
466-
supports_atomics(backend) = true
507+
supports_atomics(::Backend) = true
467508

468509
"""
469-
supports_float64(::Backend)
510+
supports_float64(::Backend)::Bool
470511
471512
Returns whether `Float64` values are supported by the backend.
513+
514+
!!! note
515+
Backend implementations **must** implement this function,
516+
only if they **do not** support `Float64`.
472517
"""
473-
supports_float64(backend) = true
518+
supports_float64(::Backend) = true
474519

475520
"""
476521
priority!(::Backend, prio::Symbol)
@@ -479,6 +524,9 @@ Set the priority for the backend stream/queue. This is an optional
479524
feature that backends may or may not implement. If a backend shall
480525
support priorities it must accept `:high`, `:normal`, `:low`.
481526
Where `:normal` is the default.
527+
528+
!!! note
529+
Backend implementations **may** implement this function.
482530
"""
483531
function priority!(::Backend, prio::Symbol)
484532
if !(prio in (:high, :normal, :low))
@@ -501,6 +549,13 @@ import .NDIteration: get
501549
Kernel closure struct that is used to represent the backend
502550
kernel on the host. `WorkgroupSize` is the number of workitems
503551
in a workgroup.
552+
553+
!!! note
554+
Backend implementations **must** implement:
555+
```
556+
(kernel::Kernel{<:NewBackend})(args...; ndrange=nothing, workgroupsize=nothing)
557+
```
558+
As well as the on-device functionality.
504559
"""
505560
struct Kernel{Backend, WorkgroupSize<:_Size, NDRange<:_Size, Fun}
506561
backend::Backend

test/convert.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ using KernelAbstractions, Test
4444
end
4545

4646
function convert_testsuite(backend, ArrayT)
47-
ET = KernelAbstractions.supports_float64(backend) ? Float64 : Float32
47+
ET = KernelAbstractions.supports_float64(backend()) ? Float64 : Float32
4848

4949
N = 32
5050
d_A = ArrayT([rand(ET)*3 for i = 1:N])

test/runtests.jl

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,30 @@ kern_static(CPU(static=true), (1,))(A, ndrange=length(A))
2020
@kernel cpu=false function my_no_cpu_kernel(a)
2121
end
2222
@test_throws ErrorException("This kernel is unavailable for backend CPU") my_no_cpu_kernel(CPU())
23+
24+
struct NewBackend <: KernelAbstractions.GPU end
25+
@testset "Default host implementation" begin
26+
backend = NewBackend()
27+
@test KernelAbstractions.isgpu(backend) == true
28+
29+
@test_throws MethodError KernelAbstractions.synchronize(backend)
30+
31+
@test_throws MethodError KernelAbstractions.allocate(backend, Float32, 1)
32+
@test_throws MethodError KernelAbstractions.allocate(backend, Float32, (1,))
33+
@test_throws MethodError KernelAbstractions.allocate(backend, Float32, 1, 2)
34+
35+
@test_throws MethodError KernelAbstractions.zeros(backend, Float32, 1)
36+
@test_throws MethodError KernelAbstractions.ones(backend, Float32, 1)
37+
38+
@test KernelAbstractions.supports_atomics(backend) == true
39+
@test KernelAbstractions.supports_float64(backend) == true
40+
41+
@test KernelAbstractions.priority!(backend, :high) === nothing
42+
@test KernelAbstractions.priority!(backend, :normal) === nothing
43+
@test KernelAbstractions.priority!(backend, :low) === nothing
44+
45+
@test_throws ErrorException KernelAbstractions.priority!(backend, :middle)
46+
47+
kernel = my_no_cpu_kernel(backend)
48+
@test_throws MethodError kernel()
49+
end

0 commit comments

Comments
 (0)