Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add OpenCL extension and buildkite CI #51

Merged
merged 3 commits into from
Jan 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .buildkite/pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,22 @@ steps:
intel: "*"
if: build.message !~ /\[skip tests\]/
timeout_in_minutes: 15

- label: "OpenCL.jl"
plugins:
- JuliaCI/julia#v1:
version: "1.10"
command: |
julia -e 'using Pkg

println("--- :julia: Instantiating environment")
Pkg.add(["OpenCL", "pocl_jll"])
Pkg.develop(PackageSpec(name="Atomix", path="."))

println("+++ :julia: Running tests")
Pkg.test("Atomix", test_args=["--OpenCL"])'
agents:
queue: "juliagpu"
intel: "*"
if: build.message !~ /\[skip tests\]/
timeout_in_minutes: 15
3 changes: 3 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,18 @@ UnsafeAtomics = "013be700-e6cd-48c3-b4a1-df204f14c38f"
CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba"
Metal = "dde4c033-4e86-420c-a63e-0dd931031962"
oneAPI = "8f75cd03-7ff8-4ecb-9b8f-daf728133b1b"
OpenCL = "08131aa3-fb12-5dee-8b74-c09406e224a2"

[extensions]
AtomixCUDAExt = "CUDA"
AtomixMetalExt = "Metal"
AtomixoneAPIExt = "oneAPI"
AtomixOpenCLExt = "OpenCL"

[compat]
CUDA = "5"
Metal = "1"
oneAPI = "1"
OpenCL = "^0.10"
UnsafeAtomics = "0.1, 0.2, 0.3"
julia = "1.10"
59 changes: 59 additions & 0 deletions ext/AtomixOpenCLExt.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# TODO: respect ordering
module AtomixOpenCLExt

using Atomix: Atomix, IndexableRef
using OpenCL: SPIRVIntrinsics, CLDeviceArray

const CLIndexableRef{Indexable<:CLDeviceArray} = IndexableRef{Indexable}

function Atomix.get(ref::CLIndexableRef, order)
error("not implemented")

Check warning on line 10 in ext/AtomixOpenCLExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/AtomixOpenCLExt.jl#L9-L10

Added lines #L9 - L10 were not covered by tests
end

function Atomix.set!(ref::CLIndexableRef, v, order)
error("not implemented")

Check warning on line 14 in ext/AtomixOpenCLExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/AtomixOpenCLExt.jl#L13-L14

Added lines #L13 - L14 were not covered by tests
end

@inline function Atomix.replace!(

Check warning on line 17 in ext/AtomixOpenCLExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/AtomixOpenCLExt.jl#L17

Added line #L17 was not covered by tests
ref::CLIndexableRef,
expected,
desired,
success_ordering,
failure_ordering,
)
ptr = Atomix.pointer(ref)
expected = convert(eltype(ref), expected)
desired = convert(eltype(ref), desired)
begin
old = SPIRVIntrinsics.atomic_cmpxchg!(ptr, expected, desired)

Check warning on line 28 in ext/AtomixOpenCLExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/AtomixOpenCLExt.jl#L24-L28

Added lines #L24 - L28 were not covered by tests
end
return (; old = old, success = old === expected)

Check warning on line 30 in ext/AtomixOpenCLExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/AtomixOpenCLExt.jl#L30

Added line #L30 was not covered by tests
end

@inline function Atomix.modify!(ref::CLIndexableRef, op::OP, x, order) where {OP}
x = convert(eltype(ref), x)
ptr = Atomix.pointer(ref)
begin
old = if op === (+)
SPIRVIntrinsics.atomic_add!(ptr, x)
elseif op === (-)
SPIRVIntrinsics.atomic_sub!(ptr, x)
elseif op === (&)
SPIRVIntrinsics.atomic_and!(ptr, x)
elseif op === (|)
SPIRVIntrinsics.atomic_or!(ptr, x)
elseif op === xor
SPIRVIntrinsics.atomic_xor!(ptr, x)
elseif op === min
SPIRVIntrinsics.atomic_min!(ptr, x)
elseif op === max
SPIRVIntrinsics.atomic_max!(ptr, x)

Check warning on line 50 in ext/AtomixOpenCLExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/AtomixOpenCLExt.jl#L33-L50

Added lines #L33 - L50 were not covered by tests
else
error("not implemented")

Check warning on line 52 in ext/AtomixOpenCLExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/AtomixOpenCLExt.jl#L52

Added line #L52 was not covered by tests
end
end
return old => op(old, x)

Check warning on line 55 in ext/AtomixOpenCLExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/AtomixOpenCLExt.jl#L55

Added line #L55 was not covered by tests
end

end # module AtomixOpenCLExt

4 changes: 4 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -149,4 +149,8 @@ elseif "--oneAPI" in ARGS
import Pkg
Pkg.add("oneAPI")
include("test_atomix_oneapi.jl")
elseif "--OpenCL" in ARGS
import Pkg
Pkg.add(["OpenCL", "pocl_jll"])
include("test_atomix_opencl.jl")
end
81 changes: 81 additions & 0 deletions test/test_atomix_opencl.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using OpenCL, pocl_jll
VarLad marked this conversation as resolved.
Show resolved Hide resolved
using OpenCL: @allowscalar
cl.platform!("pocl")

@testset "AtomixOpenCLExt:extension_found" begin
@test !isnothing(Base.get_extension(Atomix, :AtomixOpenCLExt))
end


function opencl(f)
function g()
f()
nothing
end
OpenCL.@opencl g()
end


# Not implemented:
#=
function test_get_set()
A = CUDA.ones(Int, 3)
cuda() do
GC.@preserve A begin
ref = Atomix.IndexableRef(A, (1,))
x = Atomix.get(ref)
Atomix.set!(ref, -x)
end
end
@test collect(A) == [-1, 1, 1]
end
=#


@testset "AtomixOpenCLExt:test_cas" begin
idx = (
data = 1,
cas1_ok = 2,
cas2_ok = 3,
# ...
)
@assert minimum(idx) >= 1
@assert maximum(idx) == length(idx)

A = OpenCL.zeros(Int32, length(idx))
opencl() do
GC.@preserve A begin
ref = Atomix.IndexableRef(A, (1,))
(old, success) = Atomix.replace!(ref, 0, 42)
A[idx.cas1_ok] = old == 0 && success
(old, success) = Atomix.replace!(ref, 0, 43)
A[idx.cas2_ok] = old == 42 && !success
end
end
@test collect(A) == [42, 1, 1]
end


@testset "AtomixOpenCLExt:test_inc" begin
A = OpenCL.CLArray(Int32(1):Int32(3))
opencl() do
GC.@preserve A begin
ref = Atomix.IndexableRef(A, (1,))
pre, post = Atomix.modify!(ref, +, 1)
A[2] = pre
A[3] = post
end
end
@test collect(A) == [2, 1, 2]
end


@testset "AtomixOpenCLExt:test_inc_sugar" begin
A = OpenCL.ones(Int32, 3)
opencl() do
GC.@preserve A begin
@atomic A[begin] += 1
end
end
@test collect(A) == [2, 1, 1]
end
Loading