CUDA — Есть ли способ сохранить относительность указателей на другие классы в той же памяти, скопированной на графический процессор

#cuda

Вопрос:

Я работаю с кодом, в котором в памяти хоста есть указатели на другие области памяти, которые будут скопированы вызовом cudaMemcpy.

Есть ли способ сделать что-то подобное в следующем примере кода (который не работает), чтобы элементы в указателях памяти устройства соответствовали другим элементам в памяти устройства, как это происходит в памяти хоста? Или существует «наилучший» способ решения такого рода проблем?

В противном случае, я думаю, мне пришлось бы хранить относительные смещения вместо указателей.

 #include "cuda_runtime.h"
#include <stdlib.h>
#include <stdio.h>

struct A {
    A* nextA = nullptr;
    int val = 5;
};
__global__ void kernel(A* d) {
    d[0].nextA->val = 20;
}
int main() {
    A* h = new A[2];
    h[0].nextA = amp;h[1];

    A* d;
    cudaMalloc(amp;d, sizeof(A) * 2);
    cudaMemcpy(d, h, sizeof(A) * 2, cudaMemcpyHostToDevice);
    kernel << <1, 1 >> > (d);
    cudaMemcpy(h, d, sizeof(A) * 2, cudaMemcpyDeviceToHost);

    printf("val=%dn",h[1].val);    //hoping this would be 20
    return 0;
}
 

Ответ №1:

Есть ли способ… сделать так, чтобы элементы в указателях памяти устройства соответствовали другим элементам в памяти устройства, как это происходит в памяти хоста?

Ну, вы могли бы использовать функцию унифицированной памяти CUDA (доступную с CUDA 6), с помощью которой у вас есть память на стороне устройства, доступная со стороны хоста, и наоборот. С графическими процессорами Pascal и более поздних версий вы также получаете подкачку виртуальной памяти, поэтому вы можете выделить больше, чем на самом деле имеет графический процессор, и все равно получить к нему доступ.

Конечно, если вы будете делать это неосознанно, это повредит вашей производительности. Выполнение этого очень осторожно все равно несколько повредит вашей производительности, и мне трудно сказать, насколько сильно, поскольку это зависит от варианта использования, плюс я не отношусь к типу UVM подкачки.

Или существует «наилучший» способ решения такого рода проблем?

Ну, вы могли бы использовать смещения вместо указателей. Ваши связанные указатели, вероятно, имеют какую-то общую «арену» памяти; и если они еще этого не делают, вы, вероятно, можете определить ее (в пределах которой они выделены для начала). Теперь перестаньте хранить указатели. Скорее, храните базовый адрес арены в каком-нибудь общем месте и сохраняйте смещения оттуда. Затем выделите на устройстве объем памяти, соответствующий размеру арены, и скопируйте то, что вам нужно. На стороне устройства вы можете продолжать использовать тот же код, но с адресом arena на стороне устройства, а не на стороне хоста.

… но на самом деле, это, вероятно, не настоящий ответ. Реальный ответ вероятен: если вы часто разыменовываете указатели, значит, ваше ядро неисправно; перепишите его. Он, скорее всего, неправильно разработан для использования аппаратного обеспечения графического процессора и будет работать медленно.