Aparapi在新AMD/NVIDIA显卡上本地内核大小超限问题咨询
问题概况
使用Aparapi运行代码时,搭配旧版驱动的AMD Radeon R7 450显卡支持size参数最大值达到268435455(对应16384×16384的2D图像尺寸);但同样支持该2D尺寸的AMD Radeon RX 5700 XT却报错:Total Local Kernel Size: Exceeds Maximum Allowed Local Kernel Size: 256,即size值不能超过256;支持32768×32768 2D尺寸的NVIDIA GeForce RTX 3060 Ti也存在相同问题。
测试代码如下:
int size = 268435455; double[] a = new double[size]; double[] b = new double[size]; double[] c = new double[size]; for (int i = 0; i < size; i++) { a[i] = i; b[i] = i; } Kernel kernel = new Kernel() { @Override public void run() { int gid = getGlobalId(); c[gid] = a[gid] + b[gid]; } }; kernel.execute(size); kernel.dispose();
临时解决方案:改用Range.create2D(size, 1)执行内核后,size可大于256:
Range range = Range.create2D(size, 1); kernel.execute(range); kernel.dispose();
但二维数组场景下,AMD RX 5700 XT可用此方法突破限制,NVIDIA RTX 3060 Ti仍无法支持size大于256:
Kernel kernel = new Kernel() { @Override public void run() { int gid = getGlobalId(); for (int i = 0; i < size; i++) { c[i][gid] = a[i][gid] + b[i][gid]; } } };
疑问解答
1. 为何新显卡会出现此问题?
根源在于Aparapi的默认一维执行逻辑:调用kernel.execute(size)时,它会直接将全局尺寸当作工作组(Local Work Group)尺寸提交给驱动。新显卡的驱动严格遵循OpenCL规范,单工作组的最大尺寸通常为256或1024;而早期AMD显卡驱动可能放宽了规范限制,或Aparapi对旧驱动的兼容逻辑特殊,允许超规格提交,因此旧显卡能正常运行。
改用Range.create2D(size,1)时,Aparapi会自动将全局尺寸拆分为多个符合规范的工作组(比如每个工作组256个线程),从而绕过限制。至于NVIDIA在二维数组场景下仍无法突破限制,大概率是Aparapi对NVIDIA OpenCL的二维内存访问逻辑适配不到位,驱动仍判定工作组尺寸违规。
2. 为何新显卡上代码性能更低?
- 新显卡(AMD RDNA、NVIDIA Ampere系列)针对现代GPU编程模型设计,支持硬件光追、张量核心、高效内存层级等特性,但Aparapi作为Java字节码转OpenCL的中间层,无法直接利用这些新硬件特性,导致性能无法充分发挥。
- 使用临时方案拆分工作组时,Aparapi的线程调度逻辑不够高效,相比原生OpenCL代码,中间层带来的额外开销在新显卡上更明显——旧显卡性能基数低,开销占比小;新显卡性能基数高,瓶颈就会被放大。
3. 是否Aparapi更适配AMD显卡?
是的,Aparapi最初由AMD开发,早期的优化和兼容性测试均围绕AMD显卡及自家OpenCL实现展开。虽然后来开源,但对NVIDIA CUDA转OpenCL的兼容处理仍存在短板,尤其是内存访问、工作组调度等细节,导致NVIDIA显卡在部分场景下表现不佳。从二维数组场景的差异也能看出,Aparapi对AMD显卡的适配确实更完善。
内容的提问来源于stack exchange,提问作者forreg16

