是否可以将一部分共享内存专用于每个线程?
Is it possible to dedicate a portion of shared memory to each thread?
我在 Ubuntu 18.04 上使用 CUDA 10.1,我想知道是否可以将一部分共享内存专用于每个线程。我的意思是,比方说,我希望每个线程都有一个相对较大的私有数组,它不适合寄存器,将数组放入共享内存会引入竞争条件,因为块上的每个线程都可以访问它。因此,使用一部分共享内存作为 "register" 对我来说非常有趣,这样我就可以避免竞争条件。我知道它会通过限制我可以在 SM 中使用的线程数来限制我的占用,但在我的情况下,这种权衡是值得的。
感谢您的帮助!
不,不可能将共享内存分配(静态或动态)分配给特定线程。共享内存只有块作用域。
但是,完全有可能设计一种索引方案,块内的线程可以独占地使用块范围共享内存分配内的唯一位置。例如:
template<int nthreads, int words_per_thread>
__global__
void kernel(..)
{
__shared__ int buffer[nthreads * words_per_thread];
int* localbuff = &buffer[threadIdx.x * words_per_thread];
// localbuff is now safely indexed from [0] to [words_per_thread-1]
}
另一种可能的方法是这样的:
#include <stdio.h>
template<typename T>
class sr_
{
T *sp;
public:
__device__
sr_(T *_sd) { sp = _sd;}
__device__
T &operator[](int idx){return sp[blockDim.x*idx+threadIdx.x];}
};
// for statically allocated shared memory
#define SREG(size,type,block_size) \
__shared__ type SREG_sdata[size*block_size]; \
typedef type SREG_type; \
sr_<SREG_type> sreg(SREG_sdata);
// for dynamically allocated shared memory
#define DSREG(type) \
__shared__ type SREG_sdata[]; \
typedef type SREG_type; \
sr_<SREG_type> sreg(SREG_sdata);
const int BS = 8;
__global__ void k2(){
SREG(8,float,BS)
sreg[0] = 1.0f;
printf("%f\n", sreg[0]);
}
int main(){
k2<<<1,BS>>>();
cudaDeviceSynchronize();
}
它的好处是一个线程不可能索引到另一个线程的space,而且也不会有任何银行冲突。请注意,这不会处理所有用例。它必须被修改,例如,如果在同一个模块中有多个内核使用不同的数据类型共享内存。
我在 Ubuntu 18.04 上使用 CUDA 10.1,我想知道是否可以将一部分共享内存专用于每个线程。我的意思是,比方说,我希望每个线程都有一个相对较大的私有数组,它不适合寄存器,将数组放入共享内存会引入竞争条件,因为块上的每个线程都可以访问它。因此,使用一部分共享内存作为 "register" 对我来说非常有趣,这样我就可以避免竞争条件。我知道它会通过限制我可以在 SM 中使用的线程数来限制我的占用,但在我的情况下,这种权衡是值得的。 感谢您的帮助!
不,不可能将共享内存分配(静态或动态)分配给特定线程。共享内存只有块作用域。
但是,完全有可能设计一种索引方案,块内的线程可以独占地使用块范围共享内存分配内的唯一位置。例如:
template<int nthreads, int words_per_thread>
__global__
void kernel(..)
{
__shared__ int buffer[nthreads * words_per_thread];
int* localbuff = &buffer[threadIdx.x * words_per_thread];
// localbuff is now safely indexed from [0] to [words_per_thread-1]
}
另一种可能的方法是这样的:
#include <stdio.h>
template<typename T>
class sr_
{
T *sp;
public:
__device__
sr_(T *_sd) { sp = _sd;}
__device__
T &operator[](int idx){return sp[blockDim.x*idx+threadIdx.x];}
};
// for statically allocated shared memory
#define SREG(size,type,block_size) \
__shared__ type SREG_sdata[size*block_size]; \
typedef type SREG_type; \
sr_<SREG_type> sreg(SREG_sdata);
// for dynamically allocated shared memory
#define DSREG(type) \
__shared__ type SREG_sdata[]; \
typedef type SREG_type; \
sr_<SREG_type> sreg(SREG_sdata);
const int BS = 8;
__global__ void k2(){
SREG(8,float,BS)
sreg[0] = 1.0f;
printf("%f\n", sreg[0]);
}
int main(){
k2<<<1,BS>>>();
cudaDeviceSynchronize();
}
它的好处是一个线程不可能索引到另一个线程的space,而且也不会有任何银行冲突。请注意,这不会处理所有用例。它必须被修改,例如,如果在同一个模块中有多个内核使用不同的数据类型共享内存。