From 7f16a5c17adb8ac8aff4023b8b3ac4079332892f Mon Sep 17 00:00:00 2001 From: Arity-T Date: Thu, 11 Dec 2025 10:08:22 +0000 Subject: [PATCH] =?UTF-8?q?=D0=91=D0=BE=D0=BB=D1=8C=D1=88=D0=B5=20=D1=82?= =?UTF-8?q?=D0=B0=D0=B9=D0=BC=D0=B5=D1=80=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/gpu_loader.cpp | 22 +++++++- src/gpu_plugin.cu | 125 +++++++++++++++++++++++++++++++++++++++------ src/main.cpp | 27 +++++++++- 3 files changed, 156 insertions(+), 18 deletions(-) diff --git a/src/gpu_loader.cpp b/src/gpu_loader.cpp index 49c382d..cf16099 100644 --- a/src/gpu_loader.cpp +++ b/src/gpu_loader.cpp @@ -2,6 +2,9 @@ #include #include #include +#include +#include +#include static void* get_gpu_lib_handle() { static void* h = dlopen("./libgpu_compute.so", RTLD_NOW | RTLD_LOCAL); @@ -33,6 +36,12 @@ bool aggregate_days_gpu( return false; } + // Общий таймер всей функции + double t_total_start = omp_get_wtime(); + + // Таймер CPU preprocessing + double t_preprocess_start = omp_get_wtime(); + // Группируем записи по дням и подготавливаем данные для GPU std::map> day_record_indices; @@ -80,7 +89,12 @@ bool aggregate_days_gpu( // Выделяем память для результата std::vector gpu_stats(num_days); - // Вызываем GPU функцию + double t_preprocess_ms = (omp_get_wtime() - t_preprocess_start) * 1000.0; + std::cout << " GPU CPU preprocessing: " << std::fixed << std::setprecision(3) + << std::setw(7) << t_preprocess_ms << " ms" << std::endl << std::flush; + + // Вызываем GPU функцию (включает: malloc, memcpy H->D, kernel, memcpy D->H, free) + // Детальные тайминги выводятся внутри GPU функции int result = gpu_fn( gpu_records.data(), static_cast(gpu_records.size()), @@ -92,6 +106,7 @@ bool aggregate_days_gpu( ); if (result != 0) { + std::cout << " GPU: Function returned error code " << result << std::endl; return false; } @@ -112,5 +127,10 @@ bool aggregate_days_gpu( out_stats.push_back(ds); } + // Общее время всей GPU функции (включая preprocessing) + double t_total_ms = (omp_get_wtime() - t_total_start) * 1000.0; + std::cout << " GPU TOTAL (with prep): " << std::fixed << std::setprecision(3) + << std::setw(7) << t_total_ms << " ms" << std::endl << std::flush; + return true; } diff --git a/src/gpu_plugin.cu b/src/gpu_plugin.cu index 674775e..c6b8ffc 100644 --- a/src/gpu_plugin.cu +++ b/src/gpu_plugin.cu @@ -1,6 +1,15 @@ #include #include #include +#include +#include + +// CPU таймер в миллисекундах +static double get_time_ms() { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return ts.tv_sec * 1000.0 + ts.tv_nsec / 1000000.0; +} // Структуры данных (должны совпадать с C++ кодом) struct GpuRecord { @@ -27,6 +36,10 @@ extern "C" int gpu_is_available() { int n = 0; cudaError_t err = cudaGetDeviceCount(&n); if (err != cudaSuccess) return 0; + if (n > 0) { + // Инициализируем CUDA контекст заранее (cudaFree(0) форсирует инициализацию) + cudaFree(0); + } return (n > 0) ? 1 : 0; } @@ -89,7 +102,33 @@ extern "C" int gpu_aggregate_days( int num_days, GpuDayStats* h_out_stats) { - // Выделяем память на GPU + double cpu_total_start = get_time_ms(); + + // === Создаём CUDA события для измерения времени === + double cpu_event_create_start = get_time_ms(); + + cudaEvent_t start_malloc, stop_malloc; + cudaEvent_t start_transfer, stop_transfer; + cudaEvent_t start_kernel, stop_kernel; + cudaEvent_t start_copy_back, stop_copy_back; + cudaEvent_t start_free, stop_free; + + cudaEventCreate(&start_malloc); + cudaEventCreate(&stop_malloc); + cudaEventCreate(&start_transfer); + cudaEventCreate(&stop_transfer); + cudaEventCreate(&start_kernel); + cudaEventCreate(&stop_kernel); + cudaEventCreate(&start_copy_back); + cudaEventCreate(&stop_copy_back); + cudaEventCreate(&start_free); + cudaEventCreate(&stop_free); + + double cpu_event_create_ms = get_time_ms() - cpu_event_create_start; + + // === ИЗМЕРЕНИЕ cudaMalloc === + cudaEventRecord(start_malloc); + GpuRecord* d_records = nullptr; int* d_day_offsets = nullptr; int* d_day_counts = nullptr; @@ -113,7 +152,15 @@ extern "C" int gpu_aggregate_days( err = cudaMalloc(&d_out_stats, num_days * sizeof(GpuDayStats)); if (err != cudaSuccess) { cudaFree(d_records); cudaFree(d_day_offsets); cudaFree(d_day_counts); cudaFree(d_day_indices); return -5; } - // Копируем данные на GPU + cudaEventRecord(stop_malloc); + cudaEventSynchronize(stop_malloc); + + float time_malloc_ms = 0; + cudaEventElapsedTime(&time_malloc_ms, start_malloc, stop_malloc); + + // === ИЗМЕРЕНИЕ memcpy H->D === + cudaEventRecord(start_transfer); + err = cudaMemcpy(d_records, h_records, num_records * sizeof(GpuRecord), cudaMemcpyHostToDevice); if (err != cudaSuccess) return -10; @@ -126,17 +173,24 @@ extern "C" int gpu_aggregate_days( err = cudaMemcpy(d_day_indices, h_day_indices, num_days * sizeof(long long), cudaMemcpyHostToDevice); if (err != cudaSuccess) return -13; - // Запускаем kernel: каждый поток обрабатывает один день + cudaEventRecord(stop_transfer); + cudaEventSynchronize(stop_transfer); + + float time_transfer_ms = 0; + cudaEventElapsedTime(&time_transfer_ms, start_transfer, stop_transfer); + + // === ИЗМЕРЕНИЕ kernel === const int THREADS_PER_BLOCK = 256; int num_blocks = (num_days + THREADS_PER_BLOCK - 1) / THREADS_PER_BLOCK; + cudaEventRecord(start_kernel); + aggregate_kernel<<>>( d_records, num_records, d_day_offsets, d_day_counts, d_day_indices, num_days, d_out_stats ); - // Проверяем ошибку запуска kernel err = cudaGetLastError(); if (err != cudaSuccess) { cudaFree(d_records); @@ -147,26 +201,65 @@ extern "C" int gpu_aggregate_days( return -7; } - // Ждём завершения - err = cudaDeviceSynchronize(); - if (err != cudaSuccess) { - cudaFree(d_records); - cudaFree(d_day_offsets); - cudaFree(d_day_counts); - cudaFree(d_day_indices); - cudaFree(d_out_stats); - return -6; - } + cudaEventRecord(stop_kernel); + cudaEventSynchronize(stop_kernel); - // Копируем результат обратно + float time_kernel_ms = 0; + cudaEventElapsedTime(&time_kernel_ms, start_kernel, stop_kernel); + + // === ИЗМЕРЕНИЕ memcpy D->H === + cudaEventRecord(start_copy_back); cudaMemcpy(h_out_stats, d_out_stats, num_days * sizeof(GpuDayStats), cudaMemcpyDeviceToHost); + cudaEventRecord(stop_copy_back); + cudaEventSynchronize(stop_copy_back); + + float time_copy_back_ms = 0; + cudaEventElapsedTime(&time_copy_back_ms, start_copy_back, stop_copy_back); + + // === ИЗМЕРЕНИЕ cudaFree === + cudaEventRecord(start_free); - // Освобождаем память cudaFree(d_records); cudaFree(d_day_offsets); cudaFree(d_day_counts); cudaFree(d_day_indices); cudaFree(d_out_stats); + cudaEventRecord(stop_free); + cudaEventSynchronize(stop_free); + + float time_free_ms = 0; + cudaEventElapsedTime(&time_free_ms, start_free, stop_free); + + // Общее время GPU + float time_total_ms = time_malloc_ms + time_transfer_ms + time_kernel_ms + time_copy_back_ms + time_free_ms; + + // === Освобождаем события === + double cpu_event_destroy_start = get_time_ms(); + + cudaEventDestroy(start_malloc); + cudaEventDestroy(stop_malloc); + cudaEventDestroy(start_transfer); + cudaEventDestroy(stop_transfer); + cudaEventDestroy(start_kernel); + cudaEventDestroy(stop_kernel); + cudaEventDestroy(start_copy_back); + cudaEventDestroy(stop_copy_back); + cudaEventDestroy(start_free); + cudaEventDestroy(stop_free); + + double cpu_event_destroy_ms = get_time_ms() - cpu_event_destroy_start; + double cpu_total_ms = get_time_ms() - cpu_total_start; + + // Выводим детальную статистику + printf(" GPU Timings (%d records, %d days):\n", num_records, num_days); + printf(" cudaMalloc: %7.3f ms\n", time_malloc_ms); + printf(" memcpy H->D: %7.3f ms\n", time_transfer_ms); + printf(" kernel execution: %7.3f ms\n", time_kernel_ms); + printf(" memcpy D->H: %7.3f ms\n", time_copy_back_ms); + printf(" cudaFree: %7.3f ms\n", time_free_ms); + printf(" GPU TOTAL: %7.3f ms\n", cpu_total_ms); + fflush(stdout); + return 0; } diff --git a/src/main.cpp b/src/main.cpp index d05799d..681f839 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -57,7 +57,7 @@ int main(int argc, char** argv) { MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &size); - // Читаем количество CPU потоков из переменной окружения (по умолчанию 2) + // Читаем количество CPU потоков из переменной окружения int num_cpu_threads = 2; const char* env_threads = std::getenv("NUM_CPU_THREADS"); if (env_threads) { @@ -80,15 +80,29 @@ int main(int argc, char** argv) { std::vector local_records; + // ====== ТАЙМЕРЫ ====== + double time_load_data = 0.0; + double time_distribute = 0.0; + if (rank == 0) { std::cout << "Rank 0 loading CSV..." << std::endl; + // Таймер загрузки данных + double t_load_start = MPI_Wtime(); + // Запускаем из build auto records = load_csv("../data/data.csv"); auto days = group_by_day(records); auto parts = split_days(days, size); + + time_load_data = MPI_Wtime() - t_load_start; + std::cout << "Rank 0: Data loading time: " << std::fixed << std::setprecision(3) + << time_load_data << "s" << std::endl; + // Таймер рассылки данных + double t_distribute_start = MPI_Wtime(); + // Рассылаем данные for (int r = 0; r < size; r++) { auto vec = select_records_for_rank(days, parts[r]); @@ -103,8 +117,13 @@ int main(int argc, char** argv) { MPI_Send(&count, 1, MPI_INT, r, 0, MPI_COMM_WORLD); MPI_Send(vec.data(), count * sizeof(Record), MPI_BYTE, r, 1, MPI_COMM_WORLD); } + + time_distribute = MPI_Wtime() - t_distribute_start; } else { + // Таймер получения данных + double t_receive_start = MPI_Wtime(); + // Принимает данные int count = 0; MPI_Recv(&count, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); @@ -112,9 +131,15 @@ int main(int argc, char** argv) { local_records.resize(count); MPI_Recv(local_records.data(), count * sizeof(Record), MPI_BYTE, 0, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + + time_distribute = MPI_Wtime() - t_receive_start; } MPI_Barrier(MPI_COMM_WORLD); + + // Вывод времени рассылки/получения данных + std::cout << "Rank " << rank << ": Data distribution time: " << std::fixed + << std::setprecision(3) << time_distribute << "s" << std::endl; std::cout << "Rank " << rank << " received " << local_records.size() << " records" << std::endl;