2013-10-09 3 views
2

У меня есть очень простой пример ядра cuda, который добавляет соответствующие строки из двух матриц. У меня вопрос о доступе к памяти в матрицах. Я вызываю ядро ​​через mexfunction. Мы знаем, что в Matlab мы имеем доступ к порядку в столбце, а в C/C++ - порядок строк. Основанный на организации памяти cuda, мы имеем координаты (x, y) внутри сетки для каждого блока и потока. Я попытался получить доступ к матрицам в примерах ядра в обоих направлениях: порядок строк/столбцов - основной [1]. В первом ядре исправьте меня, если я ошибаюсь, есть доступ к столбцу, а во втором - доступ к строке. Оба ядра инициализируются теми же параметрами, количеством блоков и количеством кадров. Я полагал, что второе ядро, использующее доступ к строкам для основных матриц, будет правильным способом доступа к матрице, как мы были на C++. К сожалению, ядро ​​с порядком столбца-майор возвращает правильные результаты в соответствии с алгоритмом. У кого-нибудь есть хорошее объяснение? Имеют ли эти наблюдения какое-либо отношение к тому факту, что мы называем ядро ​​посредством mexfunction, что означает matlab и, как следствие, доступ к основному порядку столбцов?матрица row/column-major доступ в ядре, называемая mexfunction

Оба ядра называются:

int numElements = rows * cols; // rows and cols of d_A or d_B 
int threadsPerBlock = 16; 
int blocksPerGrid = ceil((double) (numElements)/threadsPerBlock); 
dim3 dimBlock(threadsPerBlock,threadsPerBlock); 
dim3 dimGrid(blocksPerGrid, blocksPerGrid); 
cudaEuclid<<<dimGrid, dimBlock>>>(d_A, d_B, d_C, rows, cols); 

Ядро 1: (рабочая, но не рядные основного C++ стиля)

__global__ void cudaEuclid(float* A, float* B, float* C, int rows, int cols) 
{ 
     int i, squareeucldist = 0; 
     int r = blockDim.x * blockIdx.x + threadIdx.x; // rows 
     int c = blockDim.y * blockIdx.y + threadIdx.y; // cols 


     if(r < rows ){ 
      for (i = 0; i < cols; i++) 
          //column-major order 
       squareeucldist += (A[r + rows*i] - B[r + rows*i]) * (A[r + rows*i] - B[r + rows*i]); 
      C[r] = squareeucldist; 
      squareeucldist = 0; 
     } 
} 

ядро ​​2: (строка-мажорных порядок, с ++ стиль)

__global__ void cudaEuclid(float* A, float* B, float* C, int rows, int cols) 
    { 
     int i, squareeucldist = 0; 
     int c = blockDim.x * blockIdx.x + threadIdx.x; // cols 
     int r = blockDim.y * blockIdx.y + threadIdx.y; // rows 


     if(r < rows ){ 
      for (i = 0; i < cols; i++) 
          //row-major order 
       squareeucldist += (A[i + cols*r] - B[i + cols*r]) * (A[i + cols*r] - B[i + cols*r]); 
      C[r] = squareeucldist; 
      squareeucldist = 0; 
    } 

ответ

1

Имеет ли эти наблюдения какое-либо отношение к тому факту, что мы называем ядро ​​с помощью mexfunction, что означает Matlab и, как следствие, доступ к основному порядку столбцов?

Да.

Расширяя это, я хочу сказать, что вы продемонстрировали, что нет причин, по которым соглашение на основе столбца не может быть использовано в C/C++ с помощью простых одномерных буферов (использование CUDA в вашем случае не имеет значения).

Подумайте о массиве MATLAB как о специальном классе, который, как правило, хранит буфер данных в главном порядке. На самом деле это называется mxArray под капотом, и вы можете получить пик в деталях только с помощью MATLAB, используя format debug.

>> format debug 
>> x = [1 2 3; 4 5 6] 
x = 

Structure address = a91d8a0 
m = 2 
n = 3 
pr = 7406f620 
pi = 0 
    1  2  3 
    4  5  6 

Существует один буфер по адресу в pr и mxArray знает, что он имеет m=2 строк и столбцов n=3. Потому что это MATLAB, x(2) - 4, а не 2, как это принято в C для второго значения. В C, если вы определяете этот 2D-массив как int A[2][3] = { {1, 2, 3}, {4, 5, 6} };, the values will be laid out as 1 2 3 4 5 6.

Однако, если у вас есть простой буфер 1D, к которому вы обращаетесь, вычисляя линейный индекс из строки и столбца, то ничего не мешает вам изменить соглашение. В ваших примерах C вы просто работаете с буферами (например, float* A), поэтому вам решать, как проиндексировать его (A[r + rows*c] против A[c + cols*r]).

Короче говоря, либо транспонируйте в MATLAB, либо используйте ядро ​​с основным ядром, либо оставьте вход MATLAB самостоятельно и используйте основное ядро.

+0

Вы имеете в виду, что если мы вызываем ядро ​​с помощью основной функции C++ вместо mexfunction, то ядро ​​2 должно возвращать ожидаемые результаты? – Darkmoor

+0

Это зависит от того, как вы решили организовать данные в своей функции C++. Нет ничего, что помешало бы вам принять макет основного столбца в C++ - это просто не обычный способ хранения матрицы. – chappjc

1

Как вы уже упоминали, Matlab использует порядок столбцов, поэтому определенная матрица, скажем A, будет соответствующим образом сохранена в памяти процессора.

В определенный момент вашей программы вам нужно будет переместить A из памяти хоста в память устройства на cudaMemcpy. Поэтому A будет храниться в памяти устройства в порядке столбцов и должен быть прочитан с учетом этого.

Очевидно, что вы можете фиктивно получить хранилище порядка строк в Matlab путем переноса матрицы. Это может иметь некоторые преимущества для достижения объединенного доступа к памяти.

Смежные вопросы