Больше таймеров

This commit is contained in:
2025-12-11 10:08:22 +00:00
parent 44f297e55a
commit 7f16a5c17a
3 changed files with 156 additions and 18 deletions

View File

@@ -2,6 +2,9 @@
#include <dlfcn.h> #include <dlfcn.h>
#include <map> #include <map>
#include <algorithm> #include <algorithm>
#include <iostream>
#include <iomanip>
#include <omp.h>
static void* get_gpu_lib_handle() { static void* get_gpu_lib_handle() {
static void* h = dlopen("./libgpu_compute.so", RTLD_NOW | RTLD_LOCAL); static void* h = dlopen("./libgpu_compute.so", RTLD_NOW | RTLD_LOCAL);
@@ -33,6 +36,12 @@ bool aggregate_days_gpu(
return false; return false;
} }
// Общий таймер всей функции
double t_total_start = omp_get_wtime();
// Таймер CPU preprocessing
double t_preprocess_start = omp_get_wtime();
// Группируем записи по дням и подготавливаем данные для GPU // Группируем записи по дням и подготавливаем данные для GPU
std::map<DayIndex, std::vector<size_t>> day_record_indices; std::map<DayIndex, std::vector<size_t>> day_record_indices;
@@ -80,7 +89,12 @@ bool aggregate_days_gpu(
// Выделяем память для результата // Выделяем память для результата
std::vector<GpuDayStats> gpu_stats(num_days); std::vector<GpuDayStats> 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( int result = gpu_fn(
gpu_records.data(), gpu_records.data(),
static_cast<int>(gpu_records.size()), static_cast<int>(gpu_records.size()),
@@ -92,6 +106,7 @@ bool aggregate_days_gpu(
); );
if (result != 0) { if (result != 0) {
std::cout << " GPU: Function returned error code " << result << std::endl;
return false; return false;
} }
@@ -112,5 +127,10 @@ bool aggregate_days_gpu(
out_stats.push_back(ds); 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; return true;
} }

View File

@@ -1,6 +1,15 @@
#include <cuda_runtime.h> #include <cuda_runtime.h>
#include <cstdint> #include <cstdint>
#include <cfloat> #include <cfloat>
#include <cstdio>
#include <ctime>
// 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++ кодом) // Структуры данных (должны совпадать с C++ кодом)
struct GpuRecord { struct GpuRecord {
@@ -27,6 +36,10 @@ extern "C" int gpu_is_available() {
int n = 0; int n = 0;
cudaError_t err = cudaGetDeviceCount(&n); cudaError_t err = cudaGetDeviceCount(&n);
if (err != cudaSuccess) return 0; if (err != cudaSuccess) return 0;
if (n > 0) {
// Инициализируем CUDA контекст заранее (cudaFree(0) форсирует инициализацию)
cudaFree(0);
}
return (n > 0) ? 1 : 0; return (n > 0) ? 1 : 0;
} }
@@ -89,7 +102,33 @@ extern "C" int gpu_aggregate_days(
int num_days, int num_days,
GpuDayStats* h_out_stats) 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; GpuRecord* d_records = nullptr;
int* d_day_offsets = nullptr; int* d_day_offsets = nullptr;
int* d_day_counts = 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)); 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; } 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); err = cudaMemcpy(d_records, h_records, num_records * sizeof(GpuRecord), cudaMemcpyHostToDevice);
if (err != cudaSuccess) return -10; 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); err = cudaMemcpy(d_day_indices, h_day_indices, num_days * sizeof(long long), cudaMemcpyHostToDevice);
if (err != cudaSuccess) return -13; 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; const int THREADS_PER_BLOCK = 256;
int num_blocks = (num_days + THREADS_PER_BLOCK - 1) / THREADS_PER_BLOCK; int num_blocks = (num_days + THREADS_PER_BLOCK - 1) / THREADS_PER_BLOCK;
cudaEventRecord(start_kernel);
aggregate_kernel<<<num_blocks, THREADS_PER_BLOCK>>>( aggregate_kernel<<<num_blocks, THREADS_PER_BLOCK>>>(
d_records, num_records, d_records, num_records,
d_day_offsets, d_day_counts, d_day_indices, d_day_offsets, d_day_counts, d_day_indices,
num_days, d_out_stats num_days, d_out_stats
); );
// Проверяем ошибку запуска kernel
err = cudaGetLastError(); err = cudaGetLastError();
if (err != cudaSuccess) { if (err != cudaSuccess) {
cudaFree(d_records); cudaFree(d_records);
@@ -147,26 +201,65 @@ extern "C" int gpu_aggregate_days(
return -7; return -7;
} }
// Ждём завершения cudaEventRecord(stop_kernel);
err = cudaDeviceSynchronize(); cudaEventSynchronize(stop_kernel);
if (err != cudaSuccess) {
cudaFree(d_records);
cudaFree(d_day_offsets);
cudaFree(d_day_counts);
cudaFree(d_day_indices);
cudaFree(d_out_stats);
return -6;
}
// Копируем результат обратно 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); 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_records);
cudaFree(d_day_offsets); cudaFree(d_day_offsets);
cudaFree(d_day_counts); cudaFree(d_day_counts);
cudaFree(d_day_indices); cudaFree(d_day_indices);
cudaFree(d_out_stats); 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; return 0;
} }

View File

@@ -57,7 +57,7 @@ int main(int argc, char** argv) {
MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size); MPI_Comm_size(MPI_COMM_WORLD, &size);
// Читаем количество CPU потоков из переменной окружения (по умолчанию 2) // Читаем количество CPU потоков из переменной окружения
int num_cpu_threads = 2; int num_cpu_threads = 2;
const char* env_threads = std::getenv("NUM_CPU_THREADS"); const char* env_threads = std::getenv("NUM_CPU_THREADS");
if (env_threads) { if (env_threads) {
@@ -80,15 +80,29 @@ int main(int argc, char** argv) {
std::vector<Record> local_records; std::vector<Record> local_records;
// ====== ТАЙМЕРЫ ======
double time_load_data = 0.0;
double time_distribute = 0.0;
if (rank == 0) { if (rank == 0) {
std::cout << "Rank 0 loading CSV..." << std::endl; std::cout << "Rank 0 loading CSV..." << std::endl;
// Таймер загрузки данных
double t_load_start = MPI_Wtime();
// Запускаем из build // Запускаем из build
auto records = load_csv("../data/data.csv"); auto records = load_csv("../data/data.csv");
auto days = group_by_day(records); auto days = group_by_day(records);
auto parts = split_days(days, size); 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++) { for (int r = 0; r < size; r++) {
auto vec = select_records_for_rank(days, parts[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(&count, 1, MPI_INT, r, 0, MPI_COMM_WORLD);
MPI_Send(vec.data(), count * sizeof(Record), MPI_BYTE, r, 1, 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 { else {
// Таймер получения данных
double t_receive_start = MPI_Wtime();
// Принимает данные // Принимает данные
int count = 0; int count = 0;
MPI_Recv(&count, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); 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); local_records.resize(count);
MPI_Recv(local_records.data(), count * sizeof(Record), MPI_Recv(local_records.data(), count * sizeof(Record),
MPI_BYTE, 0, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE); MPI_BYTE, 0, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
time_distribute = MPI_Wtime() - t_receive_start;
} }
MPI_Barrier(MPI_COMM_WORLD); 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 " std::cout << "Rank " << rank << " received "
<< local_records.size() << " records" << std::endl; << local_records.size() << " records" << std::endl;