Больше таймеров
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
27
src/main.cpp
27
src/main.cpp
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user