Я реализовал это с помощью потоков CUDA для достижения параллелизм между:
- Поток 1: Инициализация дополненной части массива с помощью INT_MAX.
< li>Поток 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(©Time, 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