Понимание использования memset в коде устройства CUDA

У меня есть линейный массив int arr, который находится в глобальной памяти CUDA. Я хочу установить подмассивы arr в определенные значения. Начальные индексы подмассива задаются массивом starts, а длина каждого подмассива задается массивом counts.

Что я хочу сделать, так это установить значение подмассива i, начиная с starts[i] и продолжая до counts[i] до значения starts[i]. То есть операция:

arr[starts[i]: starts[i]+counts[i]] = starts[i]

Я подумал об использовании memset() в ядре для установки значений. Однако он не записывается правильно (элементам массива присваиваются некоторые случайные значения). Код, который я использую:

#include <stdlib.h>
__global__ void kern(int* starts,int* counts, int* arr,int* numels)
{
    unsigned int idx = threadIdx.x + blockIdx.x*blockDim.x;

    if (idx>=numels[0])
        return;

    const int val = starts[idx];
    memset(&arr[val], val, sizeof(arr[0])*counts[idx]) ;
    __syncthreads();
}

Обратите внимание, что numels[0] содержит количество элементов в массиве starts.

Я проверил код с помощью cuda-memcheck(), но не получил никаких ошибок. Я использую PyCUDA, если это уместно. Я, вероятно, неправильно понимаю использование memset здесь, поскольку я изучаю CUDA.

Не могли бы вы предложить способ исправить это? Или другой эффективный способ выполнить эту операцию.

P.S: Я знаю, что thrust::fill(), вероятно, может это делать хорошо, но, поскольку я изучаю CUDA, я хотел бы знать, как это сделать без использования внешних библиотек.


person Geralt    schedule 29.07.2018    source источник
comment
memset работает с unsigned charс, а не с intс.   -  person molbdnilo    schedule 29.07.2018
comment
@molbdnilo Итак, мне нужно сначала указать его как unsigned char?   -  person Geralt    schedule 29.07.2018
comment
Есть ли другой эффективный способ выполнить ту же операцию на CUDA?   -  person Geralt    schedule 29.07.2018


Ответы (1)


Реализации memset и memcpy в коде устройства CUDA выполняют простые, последовательные операции с байтовыми значениями (и обратите внимание, что memset не может устанавливать ничего, кроме байтовых значений, что может способствовать проблеме, которую вы видите, если значения, которые вы пытаетесь установить, являются больше 8 бит).

Вы можете заменить вызов memset чем-то вроде этого:

const int val = starts[idx];
//memset(&arr[val], val, sizeof(arr[0])*counts[idx]) ;
for(int i = 0; i < counts[idx]; i++)
    arr[val + i] = val;

Производительность этого кода, вероятно, будет выше, чем у встроенного memset.

Также обратите внимание, что вызов __syncthreads() в конце вашего ядра не нужен и является потенциальным источником взаимоблокировки, и его следует удалить. Подробнее см. здесь.

person Community    schedule 29.07.2018
comment
Спасибо за предложения! - person Geralt; 29.07.2018