RadixSort fails on NVIDIA's OpenCL driver: its default block size of 512 exceeds the reported kernel limit of 256

未关闭
#201 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 1 天内回复

还没有人认领这个 Issue。

评估

难度
4/5
预计耗时
1-2 天
新手友好度
48/100
Issue 类型
缺陷
描述清晰度
描述清楚
活跃度
活跃
技术栈
julia

调研方向

Start with SortTuning and OpenCLExt to trace how OpenCL GPU devices choose radix_block_size; then inspect the RadixSort cases in test/generic/workspace.jl and the “reduce: block sizes” testset in reduce_dims.jl. Check how MAX_BLOCK_SIZE is set in test/runtests.jl, since it uses the device limit while launches are checked against a kernel limit. Done when the default radix sort fits the kernel limit and the affected OpenCL tests pass.

由索引模型根据 Issue 内容生成。

描述

With NVIDIA's OpenCL driver, every RadixSort call with the default settings throws before launching anything:

using OpenCL                      # with NVIDIA's ICD, e.g. OCL_ICD_FILENAMES=libnvidia-opencl.so.1
import AcceleratedKernels as AK
AK.sort!(CLArray(rand(Float32, 1000)); alg=AK.RadixSort())
ERROR: ArgumentError: Work-group size (512, 1, 1) has more than 256 work-items, the maximum for this kernel

SortTuning's default radix_block_size is 512. KernelInterface checks each launch against CL_KERNEL_WORK_GROUP_SIZE, and NVIDIA's driver reports 256 for that. Every length and layout fails the same way (100 and 10^4 elements, dims=1 on 100×3, dims=2 on 3×3000, 32- and 64-bit keys), while RadixSort(block_size=256) sorts correctly. Auto() never picks RadixSort on OpenCL GPUs, so only an explicit alg=AK.RadixSort() runs into this. The test suite hits it in test/generic/workspace.jl (the RadixSort cases) and in the "reduce: block sizes" testset of reduce_dims.jl, which tries block sizes up to MAX_BLOCK_SIZE. For OpenCL that is the device's max_work_group_size (1024), not the kernel's limit.

Nothing launches with an invalid configuration: KernelInterface's check_work_group_size rejects the launch, so the user gets an ArgumentError, not a crash.

Environment: AK main (fdd0a6f, 0.5.11), OpenCL.jl 1.0.0, KernelAbstractions 0.10.4, KernelInterface 0.4.3, spirv2clc_jll 0.2.7, Julia 1.12.7. NVIDIA driver 615.78.08 (OpenCL platform "CUDA 13.4.96"), on an RTX 5080 (Linux 7.2) and an RTX 6000 Ada. The driver lacks cl_khr_il_program, so OpenCL.jl translates the SPIR-V to OpenCL C with spirv2clc.

Triage: the limit is the driver's, and it doesn't depend on the kernel:

  • Every kernel reports CL_KERNEL_WORK_GROUP_SIZE == 256, while CL_DEVICE_MAX_WORK_GROUP_SIZE is 1024. That includes AK's radix, merge, scan and reduce kernels, a one-line KA copy kernel, and hand-written OpenCL C built directly with cl.Program(source=...), with or without -cl-std. So it isn't spirv2clc output or register pressure.
  • Even a kernel declared __attribute__((reqd_work_group_size(1024, 1, 1))) reports 256, while CL_KERNEL_COMPILE_WORK_GROUP_SIZE says (1024, 1, 1). The two answers contradict each other.
  • Launches past the reported limit work. Hand-written kernels at local sizes of 512 and 1024 (one with a barrier and local memory) give correct results, and with KernelInterface's check overridden, RadixSort(block_size=512) and block_size=1024 sort 100 and 10^6 Float32/Int64 keys correctly.

So the driver under-reports. Still, the per-kernel value is the only limit OpenCL defines, and nothing tells which larger launches are safe, so AK should stay within it rather than have KernelInterface skip the check.

Other back-ends:

  • CUDA: KA compiles a kernel with a static work-group size with that size as its thread limit, so max_threads_per_block equals the block size. On the RTX 5080 the radix kernels report 512 at block_size=512 and 1024 at 1024.
  • Metal and oneAPI: KernelInterface checks the pipeline's maxTotalThreadsPerThreadgroup or the kernel's maximum group size the same way. Register-heavy kernels can get a lower limit there, but RadixSort at 512 passes the M1 CI. I haven't measured it further.

On every back-end, a too-large block is an ArgumentError before launch. AK never queries a kernel's limit itself: check_block_size only bounds block sizes at 1024.

Suggested fix:

  1. In OpenCLExt, give GPU devices SortTuning(radix_block_size=256). OpenCL GPUs have no measured tuning (the comment says so), and 256 is what every other AK kernel algorithm uses by default. A clamp at launch time wouldn't work, because the block size is a compile-time constant of the kernels and sets the size of the workspace's histograms.
  2. In test/runtests.jl, derive OpenCL's MAX_BLOCK_SIZE from a compiled kernel's limit (for example, KI.max_work_group_size of a trivial kernel), not from the device's max_work_group_size.
  3. Optionally, report the constant 256 to NVIDIA, with the reqd_work_group_size kernel as the reproducer.
主要语言
Julia
星标
204
派生
20
平均合并
2 天 19 小时
30 天内合并 PR
41

环境准备

这个项目没有提供开发容器、Dockerfile 或贡献指南,环境需要你自己搭建:先看它的 README,通用步骤见我们的新手贡献指南。

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

JuliaGPU/AcceleratedKernels.jl 的其他 Issue

查看 JuliaGPU/AcceleratedKernels.jl 的全部 Issue

相似的 Issue

更多 Julia Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。