【问题标题】:Cuda single-thread scoped variablesCuda 单线程作用域变量
【发布时间】:2013-03-11 18:04:11
【问题描述】:

是否可以让 cuda 使用在函数外部声明的单线程范围变量(寄存器或本地内存)?

我的大部分设备函数都需要使用相同的变量。

我不想将相同的变量作为参数传递给我的所有设备函数,而是在函数之外声明变量。

这可能吗?

我的计算能力是 1.2。

编辑:一个例子:

__device__ __local__ int id;
__device__ __local__ int variable1 = 3;
__device__ __local__ int variable2 = 5;
__device__ __local__ int variable3 = 8;
__device__ __local__ int variable4 = 8;

//
__device__ int deviceFunction3() {
  variable1 += 8;
  variable4 += 7;
  variable2 += 1;
  variable3 += id;

  return variable1 + variable2 + variable3;
}

__device__ int deviceFunction2() {
  variable3 += 8; 
  variable1 += deviceFunction3();
  variable4 += deviceFunction3();

  return variable3 + variable4;
}

__device__ int deviceFunction1() {
  variable1 += id;
  variable4 += 2;
  variable2 += deviceFunction2();
  variable3 += variable2 + variable4;
  return variable1 + variable2 + variable3 + variable4;
}

// Kernel
__global__ void kernel(int *dev_a, int *dev_b, int *dev_c) {
  id = get_id();

  dev_c[id] = deviceFunction1();
}

3 个设备函数需要操作相同的变量。每个变量都是针对每个线程独立计算的。据我了解,我不能使用上面的代码,因为我不能声明变量以便它们对每个线程都是本地的。

我必须做的是在内核函数中声明所有变量,然后将指向变量的指针传递给所有其他函数:

__device__ int deviceFunction3(int* id,int* variable1,int* variable2,int* variable3,int* variable4) {
  *variable1 += 8;
  *variable4 += 7;
  *variable2 += 1;
  *variable3 += 2;

  return *variable1 + *variable2 + *variable3;
}

__device__ int deviceFunction2(int* id,int* variable1,int* variable2,int* variable3,int* variable4) {
  *variable3 += 8; 
  *variable1 += deviceFunction3(id,variable1,variable2,variable3,variable4);
  *variable4 += deviceFunction3(id,variable1,variable2,variable3,variable4);

  return *variable3 + *variable4;
}

__device__ int deviceFunction1(int* id,int* variable1,int* variable2,int* variable3,int* variable4) {
  *variable1 += *id;
  *variable4 += 2;
  *variable2 += deviceFunction2(id,variable1,variable2,variable3,variable4);
  *variable3 += *variable2 + *variable4;
  return *variable1 + *variable2 + *variable3 + *variable4;
}

// Kernel
__global__ void kernel(int *dev_a, int *dev_b, int *dev_c) {
  int id = get_id();
  int variable1 = 3;
  int variable2 = 5;
  int variable3 = 8;
  int variable4 = 8;

  dev_c[id] = deviceFunction1(&id,&variable1,&variable2,&variable3,&variable4);
}

【问题讨论】:

  • 您能否在您的问题中添加一个用例示例?包含变量和 __device__ 函数的类可以工作吗?
  • 如果有办法让__device__ 知道它属于哪个线程是可能的,但我不认为有这样的事情。 (即使那样它也无法访问寄存器,但它可以访问一个全局定义的数组来充当每个线程的局部变量,即使这样性能也会大大降低!)
  • 在 CUDA 的文件范围内没有线程私有变量。特别是,我不相信有办法在 PTX 中支持它。

标签: cuda register-allocation


【解决方案1】:

您的用例是一个非常糟糕的想法,我不会向我最大的敌人推荐这种设计模式。暂时不考虑代码的优点,正如我在 cmets 中所暗示的那样,您可以通过将它们所依赖的 __device__ 函数和变量封装在一个结构中来实现所需的线程局部变量作用域,如下所示:

struct folly
{
    int id;
    int variable1;
    int variable2;
    int variable3;
    int variable4;

    __device__ folly(int _id) {
        id = _id;
        variable1 = 3;
        variable2 = 5;
        variable3 = 8;
        variable4 = 8;
    }

    __device__ int deviceFunction3() {
        variable1 += 8;
        variable4 += 7;
        variable2 += 1;
        variable3 += id;

        return variable1 + variable2 + variable3;
    }

    __device__ int deviceFunction2() {
        variable3 += 8; 
        variable1 += deviceFunction3();
        variable4 += deviceFunction3();

        return variable3 + variable4;
    }

    __device__ int deviceFunction1() {
        variable1 += id;
        variable4 += 2;
        variable2 += deviceFunction2();
        variable3 += variable2 + variable4;
        return variable1 + variable2 + variable3 + variable4;
    }
};

__global__ void kernel(int *dev_a, int *dev_b, int *dev_c) {
    int id = threadIdx.x + blockIdx.x * blockDim.x;
    folly do_calc(id);
    dev_c[id] = do_calc.deviceFunction1();
}

另请注意,CUDA 支持 C++ 样式的引用传递,因此您在发布的第二段代码中编写的任何一个设备函数都可以轻松编写如下:

__device__ int deviceFunction3(int & variable1, int & variable2, 
                               int & variable3, int & variable4) 
{
  variable1 += 8;
  variable4 += 7;
  variable2 += 1;
  variable3 += 2;

  return variable1 + variable2 + variable3;
}

更简洁,更易于阅读。

【讨论】:

  • 我希望以这种“糟糕”的方式设计代码,正如您可能已经猜到的,来自面向对象的思路。在面向对象的语言中,拥有这样的局部变量非常有意义。我意识到,在 C 语言中并非如此。感谢您向我展示了 C++ 样式的引用传递,这将使我的代码更加简洁!
  • @mollerhoj 我相信 C++ 是 OOP 语言。为什么不使用它并声明一个适当的类?
【解决方案2】:

我只是想补充一点,我已经得出结论,这是不可能的。我发现这是 CUDA C 的一个主要设计问题。

我在一些幻灯片中看到了一个名为__local__ 的关键字,但是我找不到任何文档,而且它也无法被 nvcc 识别。

我猜所有应该只有单个线程范围的变量必须只在函数内部声明。

【讨论】:

  • 回答要求澄清的问题是否有意义,例如来自@talonmies,在宣布没有解决方案之前? C 或任何其他语言是否允许在该范围之外定义特定范围的变量?如果可以,你能举个例子吗?
  • 对不起,我现在添加了一个例子,希望足以向@talonmies和你解释我的烦恼。
猜你喜欢
  • 1970-01-01
  • 2013-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-14
  • 1970-01-01
  • 1970-01-01
  • 2014-01-15
相关资源
最近更新 更多