Какой самый надежный способ вызова cudaMemcpy из нескольких процессов MPI? - PullRequest
0 голосов
/ 02 марта 2020

Я работаю над библиотекой, которая выполняет динамическое распределение рабочей нагрузки c для решения дифференциального уравнения с использованием CUDA и MPI. У меня есть несколько узлов, каждый из которых имеет графический процессор NVIDIA. Конечно, у каждого узла также есть несколько процессов. Уравнение принимает определенное количество входных данных (6 в этом примере) и создает решение, которое представляется в виде массива в глобальной памяти на графическом процессоре.

Моя текущая стратегия состоит в том, чтобы выделить буфер входных данных на root процесс на каждом узле :

if (node_info.is_node_root_process)
{
    cudaMalloc(&gpu_input_buffer.u_buffer, totalsize);
    cudaMalloc(&gpu_input_buffer.v_buffer, totalsize);
}

Затем я хочу, чтобы каждый процесс по отдельности вызывал cudaMemcpy, чтобы скопировать входные данные в глобальную память графического процессора, каждый в другое место в этом входном буфере. Таким образом, входной буфер является непрерывным в памяти, и возможно достичь слияния памяти.

Я понимаю, что вызов cudaMemcpy из нескольких процессов (или потоков), что вызовы будут выполняться последовательно на устройство. Это нормально.

Я хочу поделиться адресом, который, например, gpu_input_buffer.u_buffer указывает на каждый процесс. Таким образом, каждый процесс имеет смещение process_gpu_io_offset, так что данные, относящиеся к этому процессу, просто gpu_input_buffer.u_buffer + process_gpu_io_offset до gpu_input_buffer.u_buffer + process_gpu_io_offset + number_of_points - 1.

Я прочитал, что разделять значения указателя через MPI запрещено, поскольку виртуальный используется адресация, но поскольку все данные графического процессора находятся в одном пространстве памяти, а gpu_input_buffer.u_buffer является указателем устройства, я думаю, что это нормально.

Это надежный способ реализовать то, что я хочу?

РЕДАКТИРОВАТЬ: На основе документации CUDA:

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

Это означает, что мой оригинальный подход недопустим. Как уже указывалось, для этой цели в CUDA API есть дескрипторы памяти IP C, но я не могу найти никакой информации о том, как поделиться этим с помощью MPI. Документация для cudaIpcMemHandle_t просто:

CUDA IP C дескриптор памяти

, которая не дает никакой информации в поддержку того, что мне нужно делать. Можно создать производный тип MPI и сообщить об этом, но для этого необходимо, чтобы я знал членов cudaIpcMemHandle_t, чего я не знаю.

1 Ответ

2 голосов
/ 02 марта 2020

API CUDA Runtime имеет определенную поддержку c для совместного использования областей памяти (и событий) между процессами на одном компьютере. Просто используйте это!

Вот примеры фрагментов (с использованием моих оболочек modern-C ++ для CUDA Runtime API )

Основной процесс:

auto buffer = cuda::memory::device::make_unique<unsigned char[]>(totalsize);
gpu_input_buffer.u_buffer = buffer.get(); // because it's a smart pointer
auto handle_to_share = cuda::memory::ipc::export_(gpu_input_buffer.u_buffer);
do_some_MPI_magic_here_to_share_the_handle(handle_to_share);

Другие процессы:

auto shared_buffer_handle = do_some_MPI_magic_here_to_get_the_shared_handle();
auto full_raw_buffer = cuda::memory::ipc::import<unsigned char>(shared_buffer_handle);
auto my_part_of_the_raw_buffer = full_raw_buffer + process_gpu_io_offset;

Примечание. Если вам очень интересно узнать точное расположение типа дескриптора, вот выдержка из CUDA driver_types.h:

typedef __device_builtin__ struct __device_builtin__ cudaIpcMemHandle_st 
{
    char reserved[CUDA_IPC_HANDLE_SIZE];
} cudaIpcMemHandle_t;
...