diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index a21abe8026..f7cc0f5ef0 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -1,466 +1,481 @@ steps: # first, test supported Julia versions (using local CUDA as installed on the system) - - group: ":julia: Julia" - key: "julia" - steps: - - label: "Julia {{matrix.julia}}" - plugins: - - JuliaCI/julia#v1: - version: "{{matrix.julia}}" - - JuliaCI/julia-test#v1: - test_args: "--quickfail" - allow_reresolve: false - - JuliaCI/julia-coverage#v1: - dirs: - - src - - lib - - examples - agents: - queue: "juliagpu" - cuda: "*" - commands: | - echo -e "[CUDA_Runtime_jll]\nlocal = \"true\"" >LocalPreferences.toml - if: | - build.message =~ /\[only tests\]/ || - build.message =~ /\[only julia\]/ || - build.message !~ /\[only/ && - build.message !~ /\[skip tests\]/ && - build.message !~ /\[skip julia\]/ - timeout_in_minutes: 90 - matrix: - setup: - julia: - - "1.10" - - "1.11" - - "1.12" - - "nightly" - adjustments: - - with: - julia: "nightly" - soft_fail: true + # - group: ":julia: Julia" + # key: "julia" + # steps: + # - label: "Julia {{matrix.julia}}" + # plugins: + # - JuliaCI/julia#v1: + # version: "{{matrix.julia}}" + # - JuliaCI/julia-coverage#v1: + # dirs: + # - src + # - lib + # - examples + # agents: + # queue: "juliagpu" + # cuda: "*" + # commands: | + # echo -e "[CUDA_Runtime_jll]\nlocal = \"true\"" >LocalPreferences.toml - # then, test supported CUDA toolkits (installed through the artifact system) - - group: "CUDA" - key: "cuda" - depends_on: "julia" - steps: - - label: "CUDA {{matrix.cuda}}" - plugins: - - JuliaCI/julia#v1: - version: "1.11" - - JuliaCI/julia-test#v1: - test_args: "--quickfail core base libraries" - - JuliaCI/julia-coverage#v1: - dirs: - - src - - lib - - examples - agents: - queue: "juliagpu" - cuda: "*" - if: | - build.message =~ /\[only tests\]/ || - build.message =~ /\[only cuda\]/ || - build.message !~ /\[only/ && !build.pull_request.draft && - build.message !~ /\[skip tests\]/ && - build.message !~ /\[skip cuda\]/ - timeout_in_minutes: 60 - matrix: - setup: - cuda: - - "13.0" - - "12.9" - - "12.8" - - "12.6" - - "12.5" - - "12.4" - - "12.3" - - "12.2" - - "12.1" - - "12.0" - adjustments: - - with: - cuda: "13.0" - soft_fail: true - commands: | - echo -e "[CUDA_Runtime_jll]\nversion = \"{{matrix.cuda}}\"" >LocalPreferences.toml + # julia -e 'println("--- :julia: Developing KernelAbstractions") + # using Pkg + # Pkg.add(url="https://github.com/christiangnrd/KernelAbstractions.jl", rev="intrinsics")' - - group: ":nesting_dolls: Subpackages" - depends_on: "cuda" - steps: - - label: "{{matrix.package}} on CUDA {{matrix.cuda}}" - matrix: - setup: - cuda: - - "12.0" - - "13.0" - package: - - "cuDNN" - - "cuTENSOR" - - "cuStateVec" - - "cuTensorNet" - adjustments: - - with: - package: "cuStateVec" - cuda: "12.0" - soft_fail: true - - with: - package: "cuTensorNet" - cuda: "12.0" - soft_fail: true - - with: - package: "cuStateVec" - cuda: "13.0" - soft_fail: true - - with: - package: "cuTensorNet" - cuda: "13.0" - soft_fail: true - plugins: - - JuliaCI/julia#v1: - version: "1.10" - - JuliaCI/julia-coverage#v1: - dirs: - - src - - lib - - examples - agents: - queue: "juliagpu" - cuda: "*" - if: | - build.message =~ /\[only tests\]/ || - build.message =~ /\[only subpackages\]/ || - build.message !~ /\[only/ && !build.pull_request.draft && - build.message !~ /\[skip tests\]/ && - build.message !~ /\[skip subpackages\]/ - timeout_in_minutes: 30 - commands: | - julia -e ' - using Pkg + # julia -e 'println("--- :julia: Instantiating project") + # using Pkg + # Pkg.develop(; path=pwd())' || exit 3 - println("--- :julia: Instantiating project") - withenv("JULIA_PKG_PRECOMPILE_AUTO" => 0) do - Pkg.activate(joinpath("lib", lowercase("{{matrix.package}}"))) - try - Pkg.instantiate() - catch - # if we fail to instantiate, assume that we need newer dependencies - deps = [PackageSpec(path=".")] - if "{{matrix.package}}" == "cuTensorNet" - push!(deps, PackageSpec(path="lib/cutensor")) - end - Pkg.develop(deps) - end + # julia -e 'println("+++ :julia: Running tests") + # using Pkg + # Pkg.test("CUDA"; coverage=true)' + # if: | + # build.message =~ /\[only tests\]/ || + # build.message =~ /\[only julia\]/ || + # build.message !~ /\[only/ && + # build.message !~ /\[skip tests\]/ && + # build.message !~ /\[skip julia\]/ + # timeout_in_minutes: 90 + # matrix: + # setup: + # julia: + # - "1.10" + # - "1.11" + # - "1.12" + # - "nightly" + # adjustments: + # - with: + # julia: "nightly" + # soft_fail: true - Pkg.add("CUDA_Runtime_jll") - write(joinpath("lib", lowercase("{{matrix.package}}"), "LocalPreferences.toml"), - "[CUDA_Runtime_jll]\nversion = \"{{matrix.cuda}}\"") - end + # # then, test supported CUDA toolkits (installed through the artifact system) + # - group: "CUDA" + # key: "cuda" + # depends_on: "julia" + # steps: + # - label: "CUDA {{matrix.cuda}}" + # plugins: + # - JuliaCI/julia#v1: + # version: "1.11" + # - JuliaCI/julia-test#v1: + # test_args: "--quickfail core base libraries" + # - JuliaCI/julia-coverage#v1: + # dirs: + # - src + # - lib + # - examples + # agents: + # queue: "juliagpu" + # cuda: "*" + # if: | + # build.message =~ /\[only tests\]/ || + # build.message =~ /\[only cuda\]/ || + # build.message !~ /\[only/ && !build.pull_request.draft && + # build.message !~ /\[skip tests\]/ && + # build.message !~ /\[skip cuda\]/ + # timeout_in_minutes: 60 + # matrix: + # setup: + # cuda: + # - "13.0" + # - "12.9" + # - "12.8" + # - "12.6" + # - "12.5" + # - "12.4" + # - "12.3" + # - "12.2" + # - "12.1" + # - "12.0" + # adjustments: + # - with: + # cuda: "13.0" + # soft_fail: true + # commands: | + # echo -e "[CUDA_Runtime_jll]\nversion = \"{{matrix.cuda}}\"" >LocalPreferences.toml - println("+++ :julia: Running tests") - Pkg.test(; coverage=true)' + # - group: ":nesting_dolls: Subpackages" + # depends_on: "cuda" + # steps: + # - label: "{{matrix.package}} on CUDA {{matrix.cuda}}" + # matrix: + # setup: + # cuda: + # - "12.0" + # - "13.0" + # package: + # - "cuDNN" + # - "cuTENSOR" + # - "cuStateVec" + # - "cuTensorNet" + # adjustments: + # - with: + # package: "cuStateVec" + # cuda: "12.0" + # soft_fail: true + # - with: + # package: "cuTensorNet" + # cuda: "12.0" + # soft_fail: true + # - with: + # package: "cuStateVec" + # cuda: "13.0" + # soft_fail: true + # - with: + # package: "cuTensorNet" + # cuda: "13.0" + # soft_fail: true + # plugins: + # - JuliaCI/julia#v1: + # version: "1.10" + # - JuliaCI/julia-coverage#v1: + # dirs: + # - src + # - lib + # - examples + # agents: + # queue: "juliagpu" + # cuda: "*" + # if: | + # build.message =~ /\[only tests\]/ || + # build.message =~ /\[only subpackages\]/ || + # build.message !~ /\[only/ && !build.pull_request.draft && + # build.message !~ /\[skip tests\]/ && + # build.message !~ /\[skip subpackages\]/ + # timeout_in_minutes: 30 + # commands: | + # julia -e ' + # using Pkg - - group: ":telescope: Downstream" - depends_on: "cuda" - steps: - #- label: "NNlib.jl" - # plugins: - # - JuliaCI/julia#v1: - # version: "1.11" - # - JuliaCI/julia-coverage#v1: - # dirs: - # - src - # - lib - # - examples - # command: | - # julia --project -e ' - # using Pkg - # - # cuda = pwd() - # cudnn = joinpath(cuda, "lib", "cudnn") - # devdir = mktempdir() - # nnlib = joinpath(devdir, "NNlib") - # - # println("--- :julia: Installing TestEnv") - # Pkg.activate(; temp=true) - # Pkg.add("TestEnv") - # using TestEnv - # - # println("--- :julia: Installing NNlib") - # withenv("JULIA_PKG_PRECOMPILE_AUTO" => 0, - # "JULIA_PKG_DEVDIR" => devdir) do - # Pkg.develop("NNlib") - # Pkg.activate(nnlib) - # - # try - # Pkg.develop([PackageSpec(path=cuda), PackageSpec(path=cudnn)]) - # TestEnv.activate() - # catch err - # @error "Could not install NNlib" exception=(err,catch_backtrace()) - # exit(3) - # finally - # Pkg.activate(nnlib) - # end - # end - # - # println("+++ :julia: Running tests") - # Pkg.test(; coverage=true)' - # env: - # NNLIB_TEST_CUDA: "true" - # NNLIB_TEST_CPU: "false" - # agents: - # queue: "juliagpu" - # cuda: "*" - # if: | - # build.message =~ /\[only tests\]/ || - # build.message =~ /\[only downstream\]/ || - # build.message !~ /\[only/ && !build.pull_request.draft && - # build.message !~ /\[skip tests\]/ && - # build.message !~ /\[skip downstream\]/ - # timeout_in_minutes: 30 - # soft_fail: - # - exit_status: 3 - - label: "Enzyme.jl" - plugins: - - JuliaCI/julia#v1: - version: "1.10" # XXX: Enzyme.jl is broken on 1.11 - - JuliaCI/julia-coverage#v1: - dirs: - - src - - lib - - examples - command: | - julia -e ' - using Pkg + # println("--- :julia: Instantiating project") + # withenv("JULIA_PKG_PRECOMPILE_AUTO" => 0) do + # Pkg.activate(joinpath("lib", lowercase("{{matrix.package}}"))) + # try + # Pkg.instantiate() + # catch + # # if we fail to instantiate, assume that we need newer dependencies + # deps = [PackageSpec(path=".")] + # if "{{matrix.package}}" == "cuTensorNet" + # push!(deps, PackageSpec(path="lib/cutensor")) + # end + # Pkg.develop(deps) + # end - println("--- :julia: Instantiating project") - withenv("JULIA_PKG_PRECOMPILE_AUTO" => 0) do - # add Enzyme to the test deps - Pkg.activate("test") - Pkg.add(["Enzyme", "EnzymeCore"]) + # Pkg.add("CUDA_Runtime_jll") + # write(joinpath("lib", lowercase("{{matrix.package}}"), "LocalPreferences.toml"), + # "[CUDA_Runtime_jll]\nversion = \"{{matrix.cuda}}\"") + # end - # to check compatibility, also add Enzyme to the main environment - # (or Pkg.test, which merges both environments, could fail) - Pkg.activate(".") - # Try to co-develop Enzyme and KA, if that fails, try just to dev Enzyme - try - Pkg.develop([PackageSpec("Enzyme"), PackageSpec("KernelAbstractions")]) - catch err - try - Pkg.develop([PackageSpec("Enzyme")]) - catch err - @error "Could not install Enzyme" exception=(err,catch_backtrace()) - exit(3) - end - end - end + # println("+++ :julia: Running tests") + # Pkg.test(; coverage=true)' - println("+++ :julia: Running tests") - Pkg.test(; coverage=true, test_args=`extensions/enzyme`)' - agents: - queue: "juliagpu" - cuda: "*" - if: | - build.message =~ /\[only tests\]/ || - build.message =~ /\[only downstream\]/ || - build.message !~ /\[only/ && !build.pull_request.draft && - build.message !~ /\[skip tests\]/ && - build.message !~ /\[skip downstream\]/ - timeout_in_minutes: 60 - soft_fail: true + # - group: ":telescope: Downstream" + # depends_on: "cuda" + # steps: + # #- label: "NNlib.jl" + # # plugins: + # # - JuliaCI/julia#v1: + # # version: "1.11" + # # - JuliaCI/julia-coverage#v1: + # # dirs: + # # - src + # # - lib + # # - examples + # # command: | + # # julia --project -e ' + # # using Pkg + # # + # # cuda = pwd() + # # cudnn = joinpath(cuda, "lib", "cudnn") + # # devdir = mktempdir() + # # nnlib = joinpath(devdir, "NNlib") + # # + # # println("--- :julia: Installing TestEnv") + # # Pkg.activate(; temp=true) + # # Pkg.add("TestEnv") + # # using TestEnv + # # + # # println("--- :julia: Installing NNlib") + # # withenv("JULIA_PKG_PRECOMPILE_AUTO" => 0, + # # "JULIA_PKG_DEVDIR" => devdir) do + # # Pkg.develop("NNlib") + # # Pkg.activate(nnlib) + # # + # # try + # # Pkg.develop([PackageSpec(path=cuda), PackageSpec(path=cudnn)]) + # # TestEnv.activate() + # # catch err + # # @error "Could not install NNlib" exception=(err,catch_backtrace()) + # # exit(3) + # # finally + # # Pkg.activate(nnlib) + # # end + # # end + # # + # # println("+++ :julia: Running tests") + # # Pkg.test(; coverage=true)' + # # env: + # # NNLIB_TEST_CUDA: "true" + # # NNLIB_TEST_CPU: "false" + # # agents: + # # queue: "juliagpu" + # # cuda: "*" + # # if: | + # # build.message =~ /\[only tests\]/ || + # # build.message =~ /\[only downstream\]/ || + # # build.message !~ /\[only/ && !build.pull_request.draft && + # # build.message !~ /\[skip tests\]/ && + # # build.message !~ /\[skip downstream\]/ + # # timeout_in_minutes: 30 + # # soft_fail: + # # - exit_status: 3 + # - label: "Enzyme.jl" + # plugins: + # - JuliaCI/julia#v1: + # version: "1.10" # XXX: Enzyme.jl is broken on 1.11 + # - JuliaCI/julia-coverage#v1: + # dirs: + # - src + # - lib + # - examples + # command: | + # julia -e ' + # using Pkg - - group: ":eyes: Special" - depends_on: "cuda" - steps: - - label: "GPU-less environment" - plugins: - - JuliaCI/julia#v1: - version: "1.11" - - JuliaCI/julia-coverage#v1: - dirs: - - src - - lib - - examples - - JuliaCI/julia-test#v1: - run_tests: false - command: | - julia --project -e ' - using CUDA - @assert !CUDA.functional() - @assert !isdefined(CUDA, :libcudart) - CUDA.set_runtime_version!(v"11.6")' - julia --project -e ' - using CUDA - @assert !CUDA.functional() - @assert isdefined(CUDA, :libcudart)' - agents: - queue: "juliagpu" - intel: "*" - if: | - build.message =~ /\[only tests\]/ || - build.message =~ /\[only special\]/ || - build.message !~ /\[only/ && !build.pull_request.draft && - build.message !~ /\[skip tests\]/ && - build.message !~ /\[skip special\]/ - timeout_in_minutes: 5 + # println("--- :julia: Instantiating project") + # withenv("JULIA_PKG_PRECOMPILE_AUTO" => 0) do + # # add Enzyme to the test deps + # Pkg.activate("test") + # Pkg.add(["Enzyme", "EnzymeCore"]) - - label: "Compute sanitizer" - plugins: - - JuliaCI/julia#v1: - version: "1.11" - - JuliaCI/julia-test#v1: - test_args: "--sanitize core base" - - JuliaCI/julia-coverage#v1: - dirs: - - src - - lib - - examples - agents: - queue: "juliagpu" - cuda: "*" - if: | - build.message =~ /\[only tests\]/ || - build.message =~ /\[only special\]/ || - build.message !~ /\[only/ && !build.pull_request.draft && - build.message !~ /\[skip tests\]/ && - build.message !~ /\[skip special\]/ - timeout_in_minutes: 60 + # # to check compatibility, also add Enzyme to the main environment + # # (or Pkg.test, which merges both environments, could fail) + # Pkg.activate(".") + # # Try to co-develop Enzyme and KA, if that fails, try just to dev Enzyme + # try + # Pkg.develop([PackageSpec("Enzyme"), PackageSpec("KernelAbstractions")]) + # catch err + # try + # Pkg.develop([PackageSpec("Enzyme")]) + # catch err + # @error "Could not install Enzyme" exception=(err,catch_backtrace()) + # exit(3) + # end + # end + # end - - label: "Legacy memory allocator" - plugins: - - JuliaCI/julia#v1: - version: "1.11" - - JuliaCI/julia-test#v1: - test_args: "--quickfail core base" - - JuliaCI/julia-coverage#v1: - dirs: - - src - - lib - - examples - agents: - queue: "juliagpu" - cuda: "*" - env: - JULIA_CUDA_MEMORY_POOL: 'none' - if: | - build.message =~ /\[only tests\]/ || - build.message =~ /\[only special\]/ || - build.message !~ /\[only/ && !build.pull_request.draft && - build.message !~ /\[skip tests\]/ && - build.message !~ /\[skip special\]/ - timeout_in_minutes: 30 + # println("+++ :julia: Running tests") + # Pkg.test(; coverage=true, test_args=`extensions/enzyme`)' + # agents: + # queue: "juliagpu" + # cuda: "*" + # if: | + # build.message =~ /\[only tests\]/ || + # build.message =~ /\[only downstream\]/ || + # build.message !~ /\[only/ && !build.pull_request.draft && + # build.message !~ /\[skip tests\]/ && + # build.message !~ /\[skip downstream\]/ + # timeout_in_minutes: 60 + # soft_fail: true - - label: "CuArray with {{matrix.memory}} memory" - plugins: - - JuliaCI/julia#v1: - version: "1.11" - - JuliaCI/julia-test#v1: - test_args: "--quickfail core base libraries" - - JuliaCI/julia-coverage#v1: - dirs: - - src - - lib - - examples - agents: - queue: "juliagpu" - cuda: "*" - if: | - build.message =~ /\[only tests\]/ || - build.message =~ /\[only special\]/ || - build.message !~ /\[only/ && !build.pull_request.draft && - build.message !~ /\[skip tests\]/ && - build.message !~ /\[skip special\]/ - timeout_in_minutes: 45 - matrix: - setup: - memory: - - "unified" - - "host" - commands: | - echo -e "[CUDA]\ndefault_memory = \"{{matrix.memory}}\"" >LocalPreferences.toml + # - group: ":eyes: Special" + # depends_on: "cuda" + # steps: + # - label: "GPU-less environment" + # plugins: + # - JuliaCI/julia#v1: + # version: "1.11" + # - JuliaCI/julia-coverage#v1: + # dirs: + # - src + # - lib + # - examples + # - JuliaCI/julia-test#v1: + # run_tests: false + # command: | + # julia --project -e ' + # using CUDA + # @assert !CUDA.functional() + # @assert !isdefined(CUDA, :libcudart) + # CUDA.set_runtime_version!(v"11.6")' + # julia --project -e ' + # using CUDA + # @assert !CUDA.functional() + # @assert isdefined(CUDA, :libcudart)' + # agents: + # queue: "juliagpu" + # intel: "*" + # if: | + # build.message =~ /\[only tests\]/ || + # build.message =~ /\[only special\]/ || + # build.message !~ /\[only/ && !build.pull_request.draft && + # build.message !~ /\[skip tests\]/ && + # build.message !~ /\[skip special\]/ + # timeout_in_minutes: 5 - - label: "MultiGPU" - plugins: - - JuliaCI/julia#v1: - version: "1.11" - - JuliaCI/julia-test#v1: - test_args: "--gpu=0,1 --quickfail core base libraries" - - JuliaCI/julia-coverage#v1: - dirs: - - src - - lib - - examples - agents: - queue: "juliagpu" - cuda: "*" - multigpu: "*" - if: | - build.message =~ /\[only tests\]/ || - build.message =~ /\[only special\]/ || - build.message !~ /\[only/ && !build.pull_request.draft && - build.message !~ /\[skip tests\]/ && - build.message !~ /\[skip special\]/ - timeout_in_minutes: 45 + # - label: "Compute sanitizer" + # plugins: + # - JuliaCI/julia#v1: + # version: "1.11" + # - JuliaCI/julia-test#v1: + # test_args: "--sanitize core base" + # - JuliaCI/julia-coverage#v1: + # dirs: + # - src + # - lib + # - examples + # agents: + # queue: "juliagpu" + # cuda: "*" + # if: | + # build.message =~ /\[only tests\]/ || + # build.message =~ /\[only special\]/ || + # build.message !~ /\[only/ && !build.pull_request.draft && + # build.message !~ /\[skip tests\]/ && + # build.message !~ /\[skip special\]/ + # timeout_in_minutes: 60 - - label: ":older_man: Old dependencies" - plugins: - - JuliaCI/julia#v1: - version: "1.10" # use the oldest supported Julia version (and update below) - - JuliaCI/julia-test#v1: - test_args: "--quickfail core base" - allow_reresolve: false - - JuliaCI/julia-coverage#v1: - dirs: - - src - - lib - - examples - agents: - queue: "juliagpu" - cuda: "*" - commands: | - git clone https://github.com/StefanKarpinski/Resolver.jl /tmp/Resolver - julia -e 'using Pkg; Pkg.activate("/tmp/Resolver/bin"); Pkg.instantiate()' - julia /tmp/Resolver/bin/resolve.jl . --min=@alldeps --julia="1.10" - if: | - build.message =~ /\[only tests\]/ || - build.message =~ /\[only special\]/ || - build.message !~ /\[only/ && !build.pull_request.draft && - build.message !~ /\[skip tests\]/ && - build.message !~ /\[skip special\]/ - timeout_in_minutes: 30 + # - label: "Legacy memory allocator" + # plugins: + # - JuliaCI/julia#v1: + # version: "1.11" + # - JuliaCI/julia-test#v1: + # test_args: "--quickfail core base" + # - JuliaCI/julia-coverage#v1: + # dirs: + # - src + # - lib + # - examples + # agents: + # queue: "juliagpu" + # cuda: "*" + # env: + # JULIA_CUDA_MEMORY_POOL: 'none' + # if: | + # build.message =~ /\[only tests\]/ || + # build.message =~ /\[only special\]/ || + # build.message !~ /\[only/ && !build.pull_request.draft && + # build.message !~ /\[skip tests\]/ && + # build.message !~ /\[skip special\]/ + # timeout_in_minutes: 30 + + # - label: "CuArray with {{matrix.memory}} memory" + # plugins: + # - JuliaCI/julia#v1: + # version: "1.11" + # - JuliaCI/julia-test#v1: + # test_args: "--quickfail core base libraries" + # - JuliaCI/julia-coverage#v1: + # dirs: + # - src + # - lib + # - examples + # agents: + # queue: "juliagpu" + # cuda: "*" + # if: | + # build.message =~ /\[only tests\]/ || + # build.message =~ /\[only special\]/ || + # build.message !~ /\[only/ && !build.pull_request.draft && + # build.message !~ /\[skip tests\]/ && + # build.message !~ /\[skip special\]/ + # timeout_in_minutes: 45 + # matrix: + # setup: + # memory: + # - "unified" + # - "host" + # commands: | + # echo -e "[CUDA]\ndefault_memory = \"{{matrix.memory}}\"" >LocalPreferences.toml + + # - label: "MultiGPU" + # plugins: + # - JuliaCI/julia#v1: + # version: "1.11" + # - JuliaCI/julia-test#v1: + # test_args: "--gpu=0,1 --quickfail core base libraries" + # - JuliaCI/julia-coverage#v1: + # dirs: + # - src + # - lib + # - examples + # agents: + # queue: "juliagpu" + # cuda: "*" + # multigpu: "*" + # if: | + # build.message =~ /\[only tests\]/ || + # build.message =~ /\[only special\]/ || + # build.message !~ /\[only/ && !build.pull_request.draft && + # build.message !~ /\[skip tests\]/ && + # build.message !~ /\[skip special\]/ + # timeout_in_minutes: 45 + + # - label: ":older_man: Old dependencies" + # plugins: + # - JuliaCI/julia#v1: + # version: "1.10" # use the oldest supported Julia version (and update below) + # - JuliaCI/julia-test#v1: + # test_args: "--quickfail core base" + # allow_reresolve: false + # - JuliaCI/julia-coverage#v1: + # dirs: + # - src + # - lib + # - examples + # agents: + # queue: "juliagpu" + # cuda: "*" + # commands: | + # git clone https://github.com/StefanKarpinski/Resolver.jl /tmp/Resolver + # julia -e 'using Pkg; Pkg.activate("/tmp/Resolver/bin"); Pkg.instantiate()' + # julia /tmp/Resolver/bin/resolve.jl . --min=@alldeps --julia="1.10" + # if: | + # build.message =~ /\[only tests\]/ || + # build.message =~ /\[only special\]/ || + # build.message !~ /\[only/ && !build.pull_request.draft && + # build.message !~ /\[skip tests\]/ && + # build.message !~ /\[skip special\]/ + # timeout_in_minutes: 30 - wait: ~ continue_on_failure: true - - label: ":books: Documentation" + # - label: ":books: Documentation" + # plugins: + # - JuliaCI/julia#v1: + # version: "1.11" + # command: | + # julia --project -e ' + # println("--- :julia: Instantiating project") + # using Pkg + # Pkg.instantiate() + # Pkg.activate("docs") + # Pkg.instantiate() + # push!(LOAD_PATH, @__DIR__) + + # println("+++ :julia: Building documentation") + # include("docs/make.jl")' + # agents: + # queue: "juliagpu" + # cuda: "*" + # if: | + # build.message =~ /\[only docs\]/ || + # build.message !~ /\[only/ && !build.pull_request.draft && + # build.message !~ /\[skip docs\]/ + # timeout_in_minutes: 15 + + - label: ":racehorse: Benchmarks" plugins: - JuliaCI/julia#v1: version: "1.11" command: | julia --project -e ' - println("--- :julia: Instantiating project") using Pkg - Pkg.instantiate() - Pkg.activate("docs") - Pkg.instantiate() - push!(LOAD_PATH, @__DIR__) - println("+++ :julia: Building documentation") - include("docs/make.jl")' - agents: - queue: "juliagpu" - cuda: "*" - if: | - build.message =~ /\[only docs\]/ || - build.message !~ /\[only/ && !build.pull_request.draft && - build.message !~ /\[skip docs\]/ - timeout_in_minutes: 15 + println("--- :julia: Developing KernelAbstractions") + Pkg.add(url="https://github.com/christiangnrd/KernelAbstractions.jl", rev="intrinsics")' - - label: ":racehorse: Benchmarks" - plugins: - - JuliaCI/julia#v1: - version: "1.11" - command: | julia --project=perf -e ' using Pkg diff --git a/Project.toml b/Project.toml index c0fb240200..5dba52ac6f 100644 --- a/Project.toml +++ b/Project.toml @@ -67,7 +67,7 @@ ExprTools = "0.1" GPUArrays = "11.2.4" GPUCompiler = "1.4" GPUToolbox = "0.3, 1" -KernelAbstractions = "0.9.38" +KernelAbstractions = "0.10" LLVM = "9.3.1" LLVMLoopInfo = "1" LazyArtifacts = "1" diff --git a/src/CUDA.jl b/src/CUDA.jl index 8a82201a0a..bbe06a0bba 100644 --- a/src/CUDA.jl +++ b/src/CUDA.jl @@ -3,6 +3,7 @@ module CUDA using GPUCompiler using GPUArrays +import KernelAbstractions: KernelIntrinsics as KI using GPUToolbox diff --git a/src/CUDAKernels.jl b/src/CUDAKernels.jl index 5a36ed5eaa..bf4c269023 100644 --- a/src/CUDAKernels.jl +++ b/src/CUDAKernels.jl @@ -4,6 +4,7 @@ using ..CUDA using ..CUDA: @device_override, CUSPARSE, default_memory, UnifiedMemory import KernelAbstractions as KA +import KernelAbstractions: KernelIntrinsics as KI import StaticArrays import SparseArrays: AbstractSparseArray @@ -157,34 +158,58 @@ function (obj::KA.Kernel{CUDABackend})(args...; ndrange=nothing, workgroupsize=n return nothing end + +function KI.KIKernel(::CUDABackend, f, args...; kwargs...) + kern = eval(quote + @cuda launch=false $(kwargs...) $(f)($(args...)) + end) + KI.KIKernel{CUDABackend, typeof(kern)}(CUDABackend(), kern) +end + +function (obj::KI.KIKernel{CUDABackend})(args...; numworkgroups=nothing, workgroupsize=nothing, kwargs...) + threadsPerThreadgroup = isnothing(workgroupsize) ? 1 : workgroupsize + threadgroupsPerGrid = isnothing(numworkgroups) ? 1 : numworkgroups + + obj.kern(args...; threads=threadsPerThreadgroup, blocks=threadgroupsPerGrid, kwargs...) +end + + +function KI.kernel_max_work_group_size(::CUDABackend, kikern::KI.KIKernel{<:CUDABackend}; max_work_items::Int=typemax(Int))::Int + Int(min(kikern.kern.pipeline.maxTotalThreadsPerThreadgroup, max_work_items)) +end +function KI.max_work_group_size(::CUDABackend)::Int + Int(attribute(device(), CUDA.DEVICE_ATTRIBUTE_MAX_THREADS_PER_BLOCK)) +end +function KI.multiprocessor_count(::CUDABackend)::Int + Int(attribute(device(), CUDA.DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT)) +end + ## indexing ## COV_EXCL_START -@device_override @inline function KA.__index_Local_Linear(ctx) - return threadIdx().x +@device_override @inline function KI.get_local_id() + return (; x = Int(threadIdx().x), y = Int(threadIdx().y), z = Int(threadIdx().z)) end -@device_override @inline function KA.__index_Group_Linear(ctx) - return blockIdx().x +@device_override @inline function KI.get_group_id() + return (; x = Int(blockIdx().x), y = Int(blockIdx().y), z = Int(blockIdx().z)) end -@device_override @inline function KA.__index_Global_Linear(ctx) - I = @inbounds KA.expand(KA.__iterspace(ctx), blockIdx().x, threadIdx().x) - # TODO: This is unfortunate, can we get the linear index cheaper - @inbounds LinearIndices(KA.__ndrange(ctx))[I] +@device_override @inline function KI.get_global_id() + return (; x = Int((blockIdx().x-1)*blockDim().x + threadIdx().x), y = Int((blockIdx().y-1)*blockDim().y + threadIdx().y), z = Int((blockIdx().z-1)*blockDim().z + threadIdx().z)) end -@device_override @inline function KA.__index_Local_Cartesian(ctx) - @inbounds KA.workitems(KA.__iterspace(ctx))[threadIdx().x] +@device_override @inline function KI.get_local_size() + return (; x = Int(blockDim().x), y = Int(blockDim().y), z = Int(blockDim().z)) end -@device_override @inline function KA.__index_Group_Cartesian(ctx) - @inbounds KA.blocks(KA.__iterspace(ctx))[blockIdx().x] +@device_override @inline function KI.get_num_groups() + return (; x = Int(gridDim().x), y = Int(gridDim().y), z = Int(gridDim().z)) end -@device_override @inline function KA.__index_Global_Cartesian(ctx) - return @inbounds KA.expand(KA.__iterspace(ctx), blockIdx().x, threadIdx().x) +@device_override @inline function KI.get_global_size() + return (; x = Int(blockDim().x * gridDim().x), y = Int(blockDim().y * gridDim().y), z = Int(blockDim().z * gridDim().z)) end @device_override @inline function KA.__validindex(ctx) @@ -198,7 +223,8 @@ end ## shared and scratch memory -@device_override @inline function KA.SharedMemory(::Type{T}, ::Val{Dims}, ::Val{Id}) where {T, Dims, Id} +# @device_override @inline function KI.localmemory(::Type{T}, ::Val{Dims}, ::Val{Id}) where {T, Dims, Id} +@device_override @inline function KI.localmemory(::Type{T}, ::Val{Dims}) where {T, Dims} CuStaticSharedArray(T, Dims) end @@ -208,7 +234,7 @@ end ## synchronization and printing -@device_override @inline function KA.__synchronize() +@device_override @inline function KI.barrier() sync_threads() end diff --git a/src/accumulate.jl b/src/accumulate.jl index 1ec21f20ea..051ecc11ef 100644 --- a/src/accumulate.jl +++ b/src/accumulate.jl @@ -15,16 +15,16 @@ function partial_scan(op::Function, output::AbstractArray{T}, input::AbstractArray, Rdim, Rpre, Rpost, Rother, neutral, init, ::Val{inclusive}=Val(true)) where {T, inclusive} - threads = blockDim().x - thread = threadIdx().x - block = blockIdx().x + threads = KI.get_local_size().x + thread = KI.get_local_id().x + block = KI.get_group_id().x temp = CuDynamicSharedArray(T, (2*threads,)) # iterate the main dimension using threads and the first block dimension - i = (blockIdx().x-1i32) * blockDim().x + threadIdx().x + i = (KI.get_group_id().x-1i32) * KI.get_local_size().x + KI.get_local_id().x # iterate the other dimensions using the remaining block dimensions - j = (blockIdx().z-1i32) * gridDim().y + blockIdx().y + j = (KI.get_group_id().z-1i32) * KI.get_num_groups().y + KI.get_group_id().y if j > length(Rother) return @@ -47,7 +47,7 @@ function partial_scan(op::Function, output::AbstractArray{T}, input::AbstractArr offset = 1 d = threads>>1 while d > 0 - sync_threads() + KI.barrier() @inbounds if thread <= d ai = offset * (2*thread-1) bi = offset * (2*thread) @@ -66,7 +66,7 @@ function partial_scan(op::Function, output::AbstractArray{T}, input::AbstractArr d = 1 while d < threads offset >>= 1 - sync_threads() + KI.barrier() @inbounds if thread <= d ai = offset * (2*thread-1) bi = offset * (2*thread) @@ -78,7 +78,7 @@ function partial_scan(op::Function, output::AbstractArray{T}, input::AbstractArr d *= 2 end - sync_threads() + KI.barrier() # write results to device memory @inbounds if i <= length(Rdim) @@ -100,14 +100,14 @@ end function aggregate_partial_scan(op::Function, output::AbstractArray, aggregates::AbstractArray, Rdim, Rpre, Rpost, Rother, init) - threads = blockDim().x - thread = threadIdx().x - block = blockIdx().x + threads = KI.get_local_size().x + thread = KI.get_local_id().x + block = KI.get_group_id().x # iterate the main dimension using threads and the first block dimension - i = (blockIdx().x-1i32) * blockDim().x + threadIdx().x + i = (KI.get_group_id().x-1i32) * KI.get_local_size().x + KI.get_local_id().x # iterate the other dimensions using the remaining block dimensions - j = (blockIdx().z-1i32) * gridDim().y + blockIdx().y + j = (KI.get_group_id().z-1i32) * KI.get_num_groups().y + KI.get_group_id().y @inbounds if i <= length(Rdim) && j <= length(Rother) I = Rother[j] diff --git a/src/device/random.jl b/src/device/random.jl index d776bf886d..7d72d90a1a 100644 --- a/src/device/random.jl +++ b/src/device/random.jl @@ -72,9 +72,9 @@ end elseif field === :ctr1 @inbounds global_random_counters()[warpId] elseif field === :ctr2 - blockId = blockIdx().x + (blockIdx().y - 1i32) * gridDim().x + - (blockIdx().z - 1i32) * gridDim().x * gridDim().y - globalId = threadId + (blockId - 1i32) * (blockDim().x * blockDim().y * blockDim().z) + globalId = KI.get_global_id().x + + (KI.get_global_id().y - 1i32) * KI.get_global_size().x + + (KI.get_global_id().z - 1i32) * KI.get_global_size().x * KI.get_global_size().y globalId%UInt32 end::UInt32 end diff --git a/src/indexing.jl b/src/indexing.jl index b958dc02ec..f0fab5711c 100644 --- a/src/indexing.jl +++ b/src/indexing.jl @@ -33,7 +33,7 @@ function Base.findall(bools::AnyCuArray{Bool}) if n > 0 ## COV_EXCL_START function kernel(ys::CuDeviceArray, bools, indices) - i = threadIdx().x + (blockIdx().x - 1i32) * blockDim().x + i = KI.get_local_id().x + (KI.get_group_id().x - 1i32) * KI.get_local_size().x @inbounds if i <= length(bools) && bools[i] i′ = CartesianIndices(bools)[i] diff --git a/src/mapreduce.jl b/src/mapreduce.jl index d796b5dae1..97a4176b41 100644 --- a/src/mapreduce.jl +++ b/src/mapreduce.jl @@ -19,9 +19,9 @@ end @inline function reduce_block(op, val::T, neutral, shuffle::Val{true}) where T # shared mem for partial sums assume(warpsize() == 32) - shared = CuStaticSharedArray(T, 32) + shared = KI.localmemory(T, 32) - wid, lane = fldmod1(threadIdx().x, warpsize()) + wid, lane = fldmod1(KI.get_local_id().x, warpsize()) # each warp performs partial reduction val = reduce_warp(op, val) @@ -32,10 +32,10 @@ end end # wait for all partial reductions - sync_threads() + KI.barrier() # read from shared memory only if that warp existed - val = if threadIdx().x <= fld1(blockDim().x, warpsize()) + val = if KI.get_local_id().x <= fld1(KI.get_local_size().x, warpsize()) @inbounds shared[lane] else neutral @@ -49,8 +49,8 @@ end return val end @inline function reduce_block(op, val::T, neutral, shuffle::Val{false}) where T - threads = blockDim().x - thread = threadIdx().x + threads = KI.get_local_size().x + thread = KI.get_local_id().x # shared mem for a complete reduction shared = CuDynamicSharedArray(T, (threads,)) @@ -59,7 +59,7 @@ end # perform a reduction d = 1 while d < threads - sync_threads() + KI.barrier() index = 2 * d * (thread-1) + 1 @inbounds if index <= threads other_val = if index + d <= threads @@ -92,10 +92,10 @@ function partial_mapreduce_grid(f, op, neutral, Rreduce, Rother, shuffle, R::Abs # decompose the 1D hardware indices into separate ones for reduction (across threads # and possibly blocks if it doesn't fit) and other elements (remaining blocks) - threadIdx_reduce = threadIdx().x - blockDim_reduce = blockDim().x - blockIdx_reduce, blockIdx_other = fldmod1(blockIdx().x, length(Rother)) - gridDim_reduce = gridDim().x ÷ length(Rother) + threadIdx_reduce = KI.get_local_id().x + blockDim_reduce = KI.get_local_size().x + blockIdx_reduce, blockIdx_other = fldmod1(KI.get_group_id().x, length(Rother)) + gridDim_reduce = KI.get_num_groups().x ÷ length(Rother) # block-based indexing into the values outside of the reduction dimension # (that means we can safely synchronize threads within this block) @@ -134,7 +134,7 @@ function partial_mapreduce_grid(f, op, neutral, Rreduce, Rother, shuffle, R::Abs end function serial_mapreduce_kernel(f, op, neutral, Rreduce, Rother, R, As) - grid_idx = threadIdx().x + (blockIdx().x - 1i32) * blockDim().x + grid_idx = KI.get_local_id().x + (KI.get_group_id().x - 1i32) * KI.get_local_size().x @inbounds if grid_idx <= length(Rother) Iother = Rother[grid_idx] @@ -160,14 +160,14 @@ end # factored out for use in tests function serial_mapreduce_threshold(dev) - max_concurrency = attribute(dev, DEVICE_ATTRIBUTE_MAX_THREADS_PER_BLOCK) * - attribute(dev, DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT) + max_concurrency = KI.max_work_group_size(CUDABackend()) * KI.multiprocessor_count(CUDABackend()) return max_concurrency end function GPUArrays.mapreducedim!(f::F, op::OP, R::AnyCuArray{T}, A::Union{AbstractArray,Broadcast.Broadcasted}; init=nothing) where {F, OP, T} + backend = CUDABackend() if !isa(A, Broadcast.Broadcasted) # XXX: Base.axes isn't defined anymore for Broadcasted, breaking this check Base.check_reducedims(R, A) @@ -201,10 +201,13 @@ function GPUArrays.mapreducedim!(f::F, op::OP, R::AnyCuArray{T}, # If `Rother` is large enough, then a naive loop is more efficient than partial reductions. if length(Rother) >= serial_mapreduce_threshold(dev) args = (f, op, init, Rreduce, Rother, R, A) + # kernel = KI.KIKernel(backend, serial_mapreduce_kernel, args...) kernel = @cuda launch=false serial_mapreduce_kernel(args...) + # kernel_config = launch_configuration(kernel.kern.fun) kernel_config = launch_configuration(kernel.fun) threads = kernel_config.threads blocks = cld(length(Rother), threads) + # kernel(args...; workgroupsize=threads, numworkgroups=blocks) kernel(args...; threads, blocks) return R end @@ -228,8 +231,10 @@ function GPUArrays.mapreducedim!(f::F, op::OP, R::AnyCuArray{T}, # we might not be able to launch all those threads to reduce each slice in one go. # that's why each threads also loops across their inputs, processing multiple values # so that we can span the entire reduction dimension using a single thread block. + # kernel = KI.KIKernel(backend, partial_mapreduce_grid, f, op, init, Rreduce, Rother, Val(shuffle), R, A) kernel = @cuda launch=false partial_mapreduce_grid(f, op, init, Rreduce, Rother, Val(shuffle), R, A) compute_shmem(threads) = shuffle ? 0 : threads*sizeof(T) + # kernel_config = launch_configuration(kernel.kern.fun; shmem=compute_shmem∘compute_threads) kernel_config = launch_configuration(kernel.fun; shmem=compute_shmem∘compute_threads) reduce_threads = compute_threads(kernel_config.threads) reduce_shmem = compute_shmem(reduce_threads) @@ -255,6 +260,7 @@ function GPUArrays.mapreducedim!(f::F, op::OP, R::AnyCuArray{T}, # perform the actual reduction if reduce_blocks == 1 # we can cover the dimensions to reduce using a single block + # kernel(f, op, init, Rreduce, Rother, Val(shuffle), R, A; workgroupsize=threads, numworkgroups=blocks, shmem) kernel(f, op, init, Rreduce, Rother, Val(shuffle), R, A; threads, blocks, shmem) else # TODO: provide a version that atomically reduces from different blocks @@ -265,7 +271,9 @@ function GPUArrays.mapreducedim!(f::F, op::OP, R::AnyCuArray{T}, # NOTE: we can't use the previously-compiled kernel, or its launch configuration, # since the type of `partial` might not match the original output container # (e.g. if that was a view). + # partial_kernel = KI.KIKernel(backend, partial_mapreduce_grid, f, op, init, Rreduce, Rother, Val(shuffle), partial, A) partial_kernel = @cuda launch=false partial_mapreduce_grid(f, op, init, Rreduce, Rother, Val(shuffle), partial, A) + # partial_kernel_config = launch_configuration(partial_kernel.kern.fun; shmem=compute_shmem∘compute_threads) partial_kernel_config = launch_configuration(partial_kernel.fun; shmem=compute_shmem∘compute_threads) partial_reduce_threads = compute_threads(partial_kernel_config.threads) partial_reduce_shmem = compute_shmem(partial_reduce_threads) @@ -286,7 +294,8 @@ function GPUArrays.mapreducedim!(f::F, op::OP, R::AnyCuArray{T}, end partial_kernel(f, op, init, Rreduce, Rother, Val(shuffle), partial, A; - threads=partial_threads, blocks=partial_blocks, shmem=partial_shmem) + threads=partial_threads, blocks=partial_blocks, shmem=partial_shmem) + # workgroupsize=partial_threads, numworkgroups=partial_blocks, shmem=partial_shmem) GPUArrays.mapreducedim!(identity, op, R, partial; init) end diff --git a/test/base/kernelabstractions.jl b/test/base/kernelabstractions.jl index 2cb607ee3e..2f2c4300b5 100644 --- a/test/base/kernelabstractions.jl +++ b/test/base/kernelabstractions.jl @@ -4,7 +4,9 @@ using SparseArrays include(joinpath(dirname(pathof(KernelAbstractions)), "..", "test", "testsuite.jl")) -Testsuite.testsuite(()->CUDABackend(false, false), "CUDA", CUDA, CuArray, CuDeviceArray) +Testsuite.testsuite(()->CUDABackend(false, false), "CUDA", CUDA, CuArray, CuDeviceArray; skip_tests=Set([ + "CPU synchronization", + "fallback test: callable types",])) for (PreferBlocks, AlwaysInline) in Iterators.product((true, false), (true, false)) Testsuite.unittest_testsuite(()->CUDABackend(PreferBlocks, AlwaysInline), "CUDA", CUDA, CuDeviceArray) end @@ -16,7 +18,7 @@ end @testset "CUDA Backend Adapt Tests" begin # CPU → GPU A = sprand(Float32, 10, 10, 0.5) #CSC - A_d = adapt(CUDABackend(), A) + A_d = adapt(CUDABackend(), A) @test A_d isa CUSPARSE.CuSparseMatrixCSC @test adapt(CUDABackend(), A_d) |> typeof == typeof(A_d) @@ -24,5 +26,5 @@ end B_d = A |> cu # CuCSC B = adapt(KA.CPU(), A_d) @test B isa SparseMatrixCSC - @test adapt(KA.CPU(), B) |> typeof == typeof(B) + @test adapt(KA.CPU(), B) |> typeof == typeof(B) end