我正在研究应该进行大量模块化计算的 GPU 算法。特别是,对有限域中的矩阵进行的各种运算,从长远来看,它们会简化为原始运算,例如: (a*b - c*d) mod m 或 (a*b + c) mod m 其中 a,b,c 和 d是模 m 的余数,m 是 32 位素数。
通过实验,我了解到该算法的性能主要受到慢模运算的限制,因为硬件 GPU 不支持整数模 (%) 和除法运算。
如果有人能告诉我如何使用 CUDA 实现高效的模块化计算,我将不胜感激?
为了了解这在 CUDA 上是如何实现的,我使用以下代码片段:
__global__ void mod_kernel(unsigned *gout, const unsigned *gin) {
unsigned tid = threadIdx.x;
unsigned a = gin[tid], b = gin[tid * 2], m = gin[tid * 3];
typedef unsigned long long u64;
__syncthreads();
unsigned r = (unsigned)(((u64)a * (u64)b) % m);
__syncthreads();
gout[tid] = r;
}
这段代码不应该工作,我只是想看看如何在 CUDA 上实现模块化缩减。
当我用 cuobjdump --dump-sass 反汇编它时(感谢 njuffa 的建议!),我看到以下内容:
/*0098*/ /*0xffffdc0450ee0000*/ BAR.RED.POPC RZ, RZ;
/*00a0*/ /*0x1c315c4350000000*/ IMUL.U32.U32.HI R5, R3, R7;
/*00a8*/ /*0x1c311c0350000000*/ IMUL.U32.U32 R4, R3, R7;
/*00b0*/ /*0xfc01dde428000000*/ MOV R7, RZ;
/*00b8*/ /*0xe001000750000000*/ CAL 0xf8;
/*00c0*/ /*0x00000007d0000000*/ BPT.DRAIN 0x0;
/*00c8*/ /*0xffffdc0450ee0000*/ BAR.RED.POPC RZ, RZ;
请注意,在对 bar.red.popc 的两次调用之间,有一个对 0xf8 过程的调用,该过程实现了一些复杂的算法(大约 50 条指令甚至更多)。毫不奇怪 mod (%) 操作很慢