Однопоточные переменные области Cuda

Можно ли заставить 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();
}

Три функции устройства должны управлять одними и теми же переменными. Каждая переменная вычисляется независимо для каждого потока. Насколько я понимаю, я не могу использовать приведенный выше код, потому что я не могу объявить переменные так, чтобы они были локальными для каждого потока.

Вместо этого я должен объявить все переменные внутри функции ядра, а затем передать указатели на переменные всем остальным функциям:

__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);
}

person mollerhoj    schedule 10.03.2013    source источник
comment
Не могли бы вы добавить пример использования к вашему вопросу? Будет ли работать класс, содержащий переменные и функции __device__?   -  person talonmies    schedule 10.03.2013
comment
Если бы существовал способ, которым __device__ знал, что он принадлежит к какому потоку, это было бы возможно, но я не думаю, что такая вещь существует. (И даже тогда он не мог получить доступ к регистрам, однако он мог получить доступ к глобально определенному массиву, который служил бы локальной переменной для каждого потока, и даже тогда производительность сильно снизилась бы!)   -  person Soroosh Bateni    schedule 10.03.2013
comment
В CUDA невозможно иметь приватную переменную потока в области файла. В частности, я не верю, что есть способ поддержать его в PTX.   -  person Jared Hoberock    schedule 11.03.2013


Ответы (2)


Ваш вариант использования - действительно ужасная идея, и я бы не рекомендовал этот шаблон проектирования моему злейшему врагу. Оставив на мгновение в стороне достоинства кода, как я намекнул в комментариях, вы можете добиться желаемой области видимости локальной переменной потока, инкапсулировав функции __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;
}

который намного чище и легче читается.

person talonmies    schedule 11.03.2013
comment
Мое желание проектировать код таким ужасным образом исходит, как вы могли догадаться, из-за объектно-ориентированного мышления. В объектно-ориентированном языке такие локальные переменные имеют смысл. Я понимаю, что в C это не так. Спасибо, что показали мне передачу стиля C++ по ссылке, это сделает мой код немного чище! - person mollerhoj; 11.03.2013
comment
@mollerhoj Я считаю, что C ++ - это язык ООП. Почему бы вам не использовать это и не объявить правильный класс? - person KiaMorot; 12.03.2013

Я просто хотел добавить, что я пришел к выводу, что это невозможно. Я считаю, что это серьезная проблема дизайна с CUDA C.

Я видел ключевое слово __local__ в некоторых слайд-шоу, но не могу найти никакой документации, и оно также не распознается nvcc.

Я предполагаю, что все переменные, которые должны иметь область действия только одного потока, должны быть объявлены только внутри функций.

person mollerhoj    schedule 10.03.2013
comment
Имеет ли смысл отвечать на уточняющие вопросы, т.е. от @talonmies, прежде чем заявить, что решения нет? Позволяет ли C или любой другой язык определять переменные определенной области вне этой области? Если да, не могли бы вы привести пример? - person Robert Crovella; 11.03.2013
comment
Извините, я добавил пример сейчас, надеюсь, этого достаточно, чтобы объяснить мои проблемы @talonmies и вам. - person mollerhoj; 11.03.2013