Потоки CUDA не достигают ожидаемого параллелизма для инициализации массива и копирования памятиC++

Программы на C++. Форум разработчиков
Anonymous
 Потоки CUDA не достигают ожидаемого параллелизма для инициализации массива и копирования памяти

Сообщение Anonymous »

Я работаю над проблемой оптимизации CUDA, где мне нужно скопировать массив размером 10 000 000 с хоста на устройство. Кроме того, для последующей операции мне нужно дополнить размер массива на устройстве до 16 777 216 элементов, где дополненные значения должны быть инициализированы до INT_MAX.
Я реализовал это с помощью потоков CUDA для достижения параллелизм между:
  • Поток 1: Инициализация дополненной части массива с помощью INT_MAX.
    < li>Поток 2: Копирование исходного массива с хоста на устройство.
Я ожидал, что потоки будут работать одновременно, и общее время выполнения будет примерно максимальным (поток времени 1, поток времени 2). Однако я заметил, что общее время примерно равно сумме времени, затраченного потоком 1 и потоком 2 (временной поток 1 + временной поток 2), что указывает на то, что потоки не работают параллельно, как ожидалось. Что я делаю не так?
Кроме того, я не могу изменить способ инициализации массивов на хосте (arrHost и arrResultHost). Это ограничение, с которым мне приходится иметь дело.
Я запускаю это на графическом процессоре NVIDIA L40s, который должен поддерживать одновременное выполнение ядра и копирование памяти. Ниже приведена упрощенная версия моего кода:
#include
#include
#include
#include
#include
#include
#include
#include "device_launch_parameters.h"

__global__ void initializeArray(int* arr, int size) {
int idx = blockIdx.x * blockDim.x + threadIdx.x;
arr[idx] = INT_MAX;
}

int main(int argc, char* argv[]) {
// Problem-specific sizes
const int originalSize = 10'000'000;
const int paddedSize = 16'777'216;

// Allocate host memory for the input array and for storing sorted output
int* arrHost = (int*)malloc(originalSize * sizeof(int));
int* arrResultHost = (int*)malloc(originalSize * sizeof(int));

// Fill the input array with random values
for (int i = 0; i < originalSize; i++) {
arrHost = rand() % 1000;
}

// ===================== GPU Memory Allocation ==========================
// Allocate device memory for the main array and padding section
int* d_arrMain;
int* d_arrPadding;
cudaMalloc(&d_arrMain, originalSize * sizeof(int)); // Main array
cudaMalloc(&d_arrPadding, (paddedSize - originalSize) * sizeof(int)); // Padding portion

// Create CUDA streams for concurrent kernel execution and memory transfer
cudaStream_t streamInit, streamCopy;
cudaStreamCreate(&streamInit);
cudaStreamCreate(&streamCopy);

// Create CUDA events for timing streams and total execution
cudaEvent_t startInit, stopInit;
cudaEvent_t startCopy, stopCopy;
cudaEvent_t overallStart, overallStop;

cudaEventCreate(&startInit);
cudaEventCreate(&stopInit);
cudaEventCreate(&startCopy);
cudaEventCreate(&stopCopy);
cudaEventCreate(&overallStart);
cudaEventCreate(&overallStop);

// Start recording overall time
cudaEventRecord(overallStart);

// Configure kernel dimensions for initializing the padded section
int threadsPerBlock = 256;
int numBlocks = (paddedSize - originalSize + threadsPerBlock - 1) / threadsPerBlock;

// Record start time of kernel execution (streamInit)
cudaEventRecord(startInit, streamInit);

// Kernel launch to initialize the padding section in streamInit
initializeArray(d_arrPadding, paddedSize - originalSize);

// Record end time of kernel execution (streamInit)
cudaEventRecord(stopInit, streamInit);

// Record start time of memory copy operation (streamCopy)
cudaEventRecord(startCopy, streamCopy);

// Asynchronously copy data from host to device (main array part)
cudaMemcpyAsync(d_arrMain, arrHost, originalSize * sizeof(int), cudaMemcpyHostToDevice, streamCopy);

// Record end time of memory copy (streamCopy)
cudaEventRecord(stopCopy, streamCopy);

// Synchronize both streams before proceeding
cudaEventSynchronize(stopInit);
cudaEventSynchronize(stopCopy);

// Record overall stop time
cudaEventRecord(overallStop);
cudaEventSynchronize(overallStop);

// Calculate elapsed time for each stream and total time
float initTime = 0.0f, copyTime = 0.0f, totalTime = 0.0f;
cudaEventElapsedTime(&initTime, startInit, stopInit);
cudaEventElapsedTime(&copyTime, startCopy, stopCopy);
cudaEventElapsedTime(&totalTime, overallStart, overallStop);

// Display timing results
printf("Stream 1 (kernel initialization of padding): %f ms\n", initTime);
printf("Stream 2 (memory copy of main array): %f ms\n", copyTime);
printf("Total time for both operations: %f ms\n", totalTime);

// Cleanup resources
cudaStreamDestroy(streamInit);
cudaStreamDestroy(streamCopy);

cudaEventDestroy(startInit);
cudaEventDestroy(stopInit);
cudaEventDestroy(startCopy);
cudaEventDestroy(stopCopy);
cudaEventDestroy(overallStart);
cudaEventDestroy(overallStop);

cudaFree(d_arrMain);
cudaFree(d_arrPadding);
free(arrHost);
free(arrResultHost);

return 0;
}


Подробнее здесь: https://stackoverflow.com/questions/790 ... on-and-mem

Вернуться в «C++»