From f2d251e965b0b03c0ce66bcaf08618cc47a00430 Mon Sep 17 00:00:00 2001 From: NeiroYT <119765880+NeiroYT@users.noreply.github.com> Date: Sun, 29 Dec 2024 22:50:25 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D1=82=D1=8C=D0=B5?= =?UTF-8?q?=D0=B2=20=D0=9D=D0=B8=D0=BA=D0=B8=D1=82=D0=B0.=20=D0=97=D0=B0?= =?UTF-8?q?=D0=B4=D0=B0=D1=87=D0=B0=203.=20=D0=92=D0=B0=D1=80=D0=B8=D0=B0?= =?UTF-8?q?=D0=BD=D1=82=2030.=20=D0=9F=D0=BE=D0=B2=D1=8B=D1=88=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=BA=D0=BE=D0=BD=D1=82=D1=80=D0=B0=D1=81=D1=82?= =?UTF-8?q?=D0=B0=20=D0=BF=D0=BE=D0=BB=D1=83=D1=82=D0=BE=D0=BD=D0=BE=D0=B2?= =?UTF-8?q?=D0=BE=D0=B3=D0=BE=20=D0=B8=D0=B7=D0=BE=D0=B1=D1=80=D0=B0=D0=B6?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BF=D0=BE=D1=81=D1=80=D0=B5=D0=B4?= =?UTF-8?q?=D1=81=D1=82=D0=B2=D0=BE=D0=BC=20=D0=BB=D0=B8=D0=BD=D0=B5=D0=B9?= =?UTF-8?q?=D0=BD=D0=BE=D0=B9=20=D1=80=D0=B0=D1=81=D1=82=D1=8F=D0=B6=D0=BA?= =?UTF-8?q?=D0=B8=20=D0=B3=D0=B8=D1=81=D1=82=D0=BE=D0=B3=D1=80=D0=B0=D0=BC?= =?UTF-8?q?=D0=BC=D1=8B=20(#796)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Последовательная реализация: Преобразуем изображение в вектор, затем для каждого пикселя вычислим его яркость по формуле среднего арифм. (R+G+B)/3. Линейным растяжением получим новую яркость для каждого пикселя. Результирующий вектор - вектор с повышенным контрастом. MPI реализация: Разделим все пиксели на N, где N - число процессов. Остаток распределим между процессами, используется broadcast, all_reduce, gatherv, scatterv. Далее используется алгоритм из посл. реализации. --- .../func_tests/main.cpp | 220 ++++++++++++++++++ .../include/ops_mpi.hpp | 44 ++++ .../perf_tests/main.cpp | 141 +++++++++++ .../src/ops_mpi.cpp | 211 +++++++++++++++++ .../func_tests/main.cpp | 132 +++++++++++ .../include/ops_seq.hpp | 22 ++ .../perf_tests/main.cpp | 84 +++++++ .../src/ops_seq.cpp | 72 ++++++ 8 files changed, 926 insertions(+) create mode 100644 tasks/mpi/leontev_n_image_enhancement/func_tests/main.cpp create mode 100644 tasks/mpi/leontev_n_image_enhancement/include/ops_mpi.hpp create mode 100644 tasks/mpi/leontev_n_image_enhancement/perf_tests/main.cpp create mode 100644 tasks/mpi/leontev_n_image_enhancement/src/ops_mpi.cpp create mode 100644 tasks/seq/leontev_n_image_enhancement/func_tests/main.cpp create mode 100644 tasks/seq/leontev_n_image_enhancement/include/ops_seq.hpp create mode 100644 tasks/seq/leontev_n_image_enhancement/perf_tests/main.cpp create mode 100644 tasks/seq/leontev_n_image_enhancement/src/ops_seq.cpp diff --git a/tasks/mpi/leontev_n_image_enhancement/func_tests/main.cpp b/tasks/mpi/leontev_n_image_enhancement/func_tests/main.cpp new file mode 100644 index 00000000000..97507139fa6 --- /dev/null +++ b/tasks/mpi/leontev_n_image_enhancement/func_tests/main.cpp @@ -0,0 +1,220 @@ +#include + +#include +#include +#include +#include +#include +#include + +#include "mpi/leontev_n_image_enhancement/include/ops_mpi.hpp" + +namespace leontev_n_image_enhancement_mpi { +std::vector getRandomImage(int sz) { + std::random_device dev; + std::mt19937 gen(dev()); + std::uniform_int_distribution dist(0, 255); + std::vector vec(sz); + for (int i = 0; i < sz; i++) { + vec[i] = dist(gen); + } + return vec; +} +} // namespace leontev_n_image_enhancement_mpi + +inline void taskEmplacement(std::shared_ptr &taskDataPar, std::vector &global_vec, + std::vector &global_sum) { + taskDataPar->inputs.emplace_back(reinterpret_cast(global_vec.data())); + taskDataPar->inputs_count.emplace_back(global_vec.size()); + taskDataPar->outputs.emplace_back(reinterpret_cast(global_sum.data())); + taskDataPar->outputs_count.emplace_back(global_sum.size()); +} + +TEST(leontev_n_image_enhancement_mpi, test_image_imin_imax) { + boost::mpi::communicator world; + + const int vector_size = 6; + std::vector in_vec = {255, 0, 255, 255, 0, 255}; + std::vector out_vec_par(vector_size, 0); + + std::shared_ptr taskDataPar = std::make_shared(); + + if (world.rank() == 0) { + taskEmplacement(taskDataPar, in_vec, out_vec_par); + } + + leontev_n_image_enhancement_mpi::MPIImgEnhancementParallel MPIImgEnhancementParallel(taskDataPar); + ASSERT_EQ(MPIImgEnhancementParallel.validation(), true); + MPIImgEnhancementParallel.pre_processing(); + MPIImgEnhancementParallel.run(); + MPIImgEnhancementParallel.post_processing(); + + if (world.rank() == 0) { + // Create data + std::vector out_vec_seq(vector_size, 0); + + // Create TaskData + std::shared_ptr taskDataSeq = std::make_shared(); + taskEmplacement(taskDataSeq, in_vec, out_vec_seq); + + // Create Task + leontev_n_image_enhancement_mpi::MPIImgEnhancementSequential MPIImgEnhancementSequential(taskDataSeq); + ASSERT_EQ(MPIImgEnhancementSequential.validation(), true); + MPIImgEnhancementSequential.pre_processing(); + MPIImgEnhancementSequential.run(); + MPIImgEnhancementSequential.post_processing(); + + ASSERT_EQ(out_vec_par, out_vec_seq); + } +} + +TEST(leontev_n_image_enhancement_mpi, test_image_1) { + boost::mpi::communicator world; + + const int width = 300; + const int height = 300; + const int vector_size = width * height * 3; + std::vector in_vec = leontev_n_image_enhancement_mpi::getRandomImage(vector_size); + std::vector out_vec_par(vector_size, 0); + + std::shared_ptr taskDataPar = std::make_shared(); + + if (world.rank() == 0) { + taskEmplacement(taskDataPar, in_vec, out_vec_par); + } + + leontev_n_image_enhancement_mpi::MPIImgEnhancementParallel MPIImgEnhancementParallel(taskDataPar); + ASSERT_EQ(MPIImgEnhancementParallel.validation(), true); + MPIImgEnhancementParallel.pre_processing(); + MPIImgEnhancementParallel.run(); + MPIImgEnhancementParallel.post_processing(); + + if (world.rank() == 0) { + // Create data + std::vector out_vec_seq(vector_size, 0); + + // Create TaskData + std::shared_ptr taskDataSeq = std::make_shared(); + taskEmplacement(taskDataSeq, in_vec, out_vec_seq); + + // Create Task + leontev_n_image_enhancement_mpi::MPIImgEnhancementSequential MPIImgEnhancementSequential(taskDataSeq); + ASSERT_EQ(MPIImgEnhancementSequential.validation(), true); + MPIImgEnhancementSequential.pre_processing(); + MPIImgEnhancementSequential.run(); + MPIImgEnhancementSequential.post_processing(); + + ASSERT_EQ(out_vec_par, out_vec_seq); + } +} + +TEST(leontev_n_image_enhancement_mpi, test_image_2) { + boost::mpi::communicator world; + + const int width = 600; + const int height = 600; + const int vector_size = width * height * 3; + std::vector in_vec = leontev_n_image_enhancement_mpi::getRandomImage(vector_size); + std::vector out_vec_par(vector_size, 0); + + std::shared_ptr taskDataPar = std::make_shared(); + + if (world.rank() == 0) { + taskEmplacement(taskDataPar, in_vec, out_vec_par); + } + + leontev_n_image_enhancement_mpi::MPIImgEnhancementParallel MPIImgEnhancementParallel(taskDataPar); + ASSERT_EQ(MPIImgEnhancementParallel.validation(), true); + MPIImgEnhancementParallel.pre_processing(); + MPIImgEnhancementParallel.run(); + MPIImgEnhancementParallel.post_processing(); + + if (world.rank() == 0) { + // Create data + std::vector out_vec_seq(vector_size, 0); + + // Create TaskData + std::shared_ptr taskDataSeq = std::make_shared(); + taskEmplacement(taskDataSeq, in_vec, out_vec_seq); + + // Create Task + leontev_n_image_enhancement_mpi::MPIImgEnhancementSequential MPIImgEnhancementSequential(taskDataSeq); + ASSERT_EQ(MPIImgEnhancementSequential.validation(), true); + MPIImgEnhancementSequential.pre_processing(); + MPIImgEnhancementSequential.run(); + MPIImgEnhancementSequential.post_processing(); + + ASSERT_EQ(out_vec_par, out_vec_seq); + } +} + +TEST(leontev_n_image_enhancement_mpi, test_incorrect_image_size) { + boost::mpi::communicator world; + + const int vector_size = 5; + std::vector in_vec = {0, 10, 10, 10, 60}; + std::vector out_vec_par(vector_size, 0); + + std::shared_ptr taskDataPar = std::make_shared(); + + if (world.rank() == 0) { + taskEmplacement(taskDataPar, in_vec, out_vec_par); + leontev_n_image_enhancement_mpi::MPIImgEnhancementParallel MPIImgEnhancementParallel(taskDataPar); + ASSERT_EQ(MPIImgEnhancementParallel.validation(), false); + } +} + +TEST(leontev_n_image_enhancement_mpi, test_incorrect_rgb_image) { + boost::mpi::communicator world; + + const int width = 4; + const int height = 4; + const int vector_size = width * height * 3; + std::vector in_vec = leontev_n_image_enhancement_mpi::getRandomImage(vector_size); + in_vec[0] = -100; + std::vector out_vec_par(vector_size, 0); + + std::shared_ptr taskDataPar = std::make_shared(); + + if (world.rank() == 0) { + taskEmplacement(taskDataPar, in_vec, out_vec_par); + leontev_n_image_enhancement_mpi::MPIImgEnhancementParallel MPIImgEnhancementParallel(taskDataPar); + ASSERT_EQ(MPIImgEnhancementParallel.validation(), false); + } +} + +TEST(leontev_n_image_enhancement_mpi, test_incorrect_rgb_image2) { + boost::mpi::communicator world; + + const int width = 2; + const int height = 3; + const int vector_size = width * height * 3; + std::vector in_vec = {-2, -10, -20, 0, 555, -25, 50, 265, 0, 0, 0, 0, -22, 0, 1, 4, 105, 90}; + std::vector out_vec_par(vector_size, 0); + + std::shared_ptr taskDataPar = std::make_shared(); + + if (world.rank() == 0) { + taskEmplacement(taskDataPar, in_vec, out_vec_par); + leontev_n_image_enhancement_mpi::MPIImgEnhancementParallel MPIImgEnhancementParallel(taskDataPar); + ASSERT_EQ(MPIImgEnhancementParallel.validation(), false); + } +} + +TEST(leontev_n_image_enhancement_mpi, test_incorrect_empty_image) { + boost::mpi::communicator world; + + const int width = 0; + const int height = 0; + const int vector_size = width * height * 3; + std::vector in_vec = {}; + std::vector out_vec_par(vector_size, 0); + + std::shared_ptr taskDataPar = std::make_shared(); + + if (world.rank() == 0) { + taskEmplacement(taskDataPar, in_vec, out_vec_par); + leontev_n_image_enhancement_mpi::MPIImgEnhancementParallel MPIImgEnhancementParallel(taskDataPar); + ASSERT_EQ(MPIImgEnhancementParallel.validation(), false); + } +} diff --git a/tasks/mpi/leontev_n_image_enhancement/include/ops_mpi.hpp b/tasks/mpi/leontev_n_image_enhancement/include/ops_mpi.hpp new file mode 100644 index 00000000000..8b0f1fc61c1 --- /dev/null +++ b/tasks/mpi/leontev_n_image_enhancement/include/ops_mpi.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "core/task/include/task.hpp" + +namespace leontev_n_image_enhancement_mpi { + +class MPIImgEnhancementSequential : public ppc::core::Task { + public: + explicit MPIImgEnhancementSequential(std::shared_ptr taskData_) : Task(std::move(taskData_)) {} + bool pre_processing() override; + bool validation() override; + bool run() override; + bool post_processing() override; + + private: + std::vector I; + std::vector image_input; + std::vector image_output; +}; + +class MPIImgEnhancementParallel : public ppc::core::Task { + public: + explicit MPIImgEnhancementParallel(std::shared_ptr taskData_) : Task(std::move(taskData_)) {} + bool pre_processing() override; + bool validation() override; + bool run() override; + bool post_processing() override; + + private: + std::vector image_input; + std::vector image_output; + boost::mpi::communicator world; +}; +} // namespace leontev_n_image_enhancement_mpi \ No newline at end of file diff --git a/tasks/mpi/leontev_n_image_enhancement/perf_tests/main.cpp b/tasks/mpi/leontev_n_image_enhancement/perf_tests/main.cpp new file mode 100644 index 00000000000..e7e3a109f6e --- /dev/null +++ b/tasks/mpi/leontev_n_image_enhancement/perf_tests/main.cpp @@ -0,0 +1,141 @@ +#include + +#include +#include +#include +#include + +#include "core/perf/include/perf.hpp" +#include "mpi/leontev_n_image_enhancement/include/ops_mpi.hpp" + +namespace leontev_n_image_enhancement_mpi { +std::vector getRandomImage(int sz) { + std::mt19937 gen(42); + std::uniform_int_distribution dist(0, 255); + std::vector vec(sz); + for (int i = 0; i < sz; i++) { + vec[i] = dist(gen); + } + return vec; +} +} // namespace leontev_n_image_enhancement_mpi + +inline void taskEmplacement(std::shared_ptr &taskDataPar, std::vector &global_vec, + std::vector &global_sum) { + taskDataPar->inputs.emplace_back(reinterpret_cast(global_vec.data())); + taskDataPar->inputs_count.emplace_back(global_vec.size()); + taskDataPar->outputs.emplace_back(reinterpret_cast(global_sum.data())); + taskDataPar->outputs_count.emplace_back(global_sum.size()); +} + +TEST(leontev_n_image_enhancement_mpi, test_pipeline_run) { + boost::mpi::communicator world; + + const int width = 2048; + const int height = 2048; + + std::vector in_vec; + const int vector_size = width * height * 3; + std::vector out_vec_par(vector_size, 0); + // Create TaskData + std::shared_ptr taskDataPar = std::make_shared(); + + if (world.rank() == 0) { + in_vec = leontev_n_image_enhancement_mpi::getRandomImage(vector_size); + taskEmplacement(taskDataPar, in_vec, out_vec_par); + } + + auto MPIImgEnhancementParallel = + std::make_shared(taskDataPar); + ASSERT_EQ(MPIImgEnhancementParallel->validation(), true); + MPIImgEnhancementParallel->pre_processing(); + MPIImgEnhancementParallel->run(); + MPIImgEnhancementParallel->post_processing(); + + // Create Perf attributes + auto perfAttr = std::make_shared(); + perfAttr->num_running = 15; + const boost::mpi::timer current_timer; + perfAttr->current_timer = [&] { return current_timer.elapsed(); }; + + // Create and init perf results + auto perfResults = std::make_shared(); + + // Create Perf analyzer + auto perfAnalyzer = std::make_shared(MPIImgEnhancementParallel); + perfAnalyzer->pipeline_run(perfAttr, perfResults); + if (world.rank() == 0) { + ppc::core::Perf::print_perf_statistic(perfResults); + + std::vector out_vec_seq(vector_size, 0); + + // Create TaskData + std::shared_ptr taskDataSeq = std::make_shared(); + taskEmplacement(taskDataSeq, in_vec, out_vec_seq); + + // Create Task + leontev_n_image_enhancement_mpi::MPIImgEnhancementSequential MPIImgEnhancementSequential(taskDataSeq); + ASSERT_EQ(MPIImgEnhancementSequential.validation(), true); + MPIImgEnhancementSequential.pre_processing(); + MPIImgEnhancementSequential.run(); + MPIImgEnhancementSequential.post_processing(); + + ASSERT_EQ(out_vec_par, out_vec_seq); + } +} + +TEST(leontev_n_image_enhancement_mpi, test_task_run) { + boost::mpi::communicator world; + + const int width = 2048; + const int height = 2048; + + std::vector in_vec; + const int count_size_vector = width * height * 3; + std::vector out_vec_par(count_size_vector, 0); + // Create TaskData + std::shared_ptr taskDataPar = std::make_shared(); + + if (world.rank() == 0) { + in_vec = leontev_n_image_enhancement_mpi::getRandomImage(count_size_vector); + taskEmplacement(taskDataPar, in_vec, out_vec_par); + } + + auto MPIImgEnhancementParallel = + std::make_shared(taskDataPar); + ASSERT_EQ(MPIImgEnhancementParallel->validation(), true); + MPIImgEnhancementParallel->pre_processing(); + MPIImgEnhancementParallel->run(); + MPIImgEnhancementParallel->post_processing(); + + // Create Perf attributes + auto perfAttr = std::make_shared(); + perfAttr->num_running = 15; + const boost::mpi::timer current_timer; + perfAttr->current_timer = [&] { return current_timer.elapsed(); }; + + // Create and init perf results + auto perfResults = std::make_shared(); + + // Create Perf analyzer + auto perfAnalyzer = std::make_shared(MPIImgEnhancementParallel); + perfAnalyzer->task_run(perfAttr, perfResults); + if (world.rank() == 0) { + ppc::core::Perf::print_perf_statistic(perfResults); + + std::vector out_vec_seq(count_size_vector, 0); + + // Create TaskData + std::shared_ptr taskDataSeq = std::make_shared(); + taskEmplacement(taskDataSeq, in_vec, out_vec_seq); + + // Create Task + leontev_n_image_enhancement_mpi::MPIImgEnhancementSequential MPIImgEnhancementSequential(taskDataSeq); + ASSERT_EQ(MPIImgEnhancementSequential.validation(), true); + MPIImgEnhancementSequential.pre_processing(); + MPIImgEnhancementSequential.run(); + MPIImgEnhancementSequential.post_processing(); + + ASSERT_EQ(out_vec_par, out_vec_seq); + } +} \ No newline at end of file diff --git a/tasks/mpi/leontev_n_image_enhancement/src/ops_mpi.cpp b/tasks/mpi/leontev_n_image_enhancement/src/ops_mpi.cpp new file mode 100644 index 00000000000..37b9ffba846 --- /dev/null +++ b/tasks/mpi/leontev_n_image_enhancement/src/ops_mpi.cpp @@ -0,0 +1,211 @@ +#include "mpi/leontev_n_image_enhancement/include/ops_mpi.hpp" + +#include +#include +#include + +bool leontev_n_image_enhancement_mpi::MPIImgEnhancementSequential::pre_processing() { + internal_order_test(); + + int size = taskData->inputs_count[0]; + image_input = std::vector(size); + auto* tmp_ptr = reinterpret_cast(taskData->inputs[0]); + std::copy(tmp_ptr, tmp_ptr + size, image_input.begin()); + + int pixel_count = size / 3; + I.resize(pixel_count); + for (int i = 0; i < pixel_count; i++) { + int r = image_input[3 * i]; + int g = image_input[3 * i + 1]; + int b = image_input[3 * i + 2]; + I[i] = (r + g + b) / 3; + } + + image_output = {}; + return true; +} + +bool leontev_n_image_enhancement_mpi::MPIImgEnhancementSequential::validation() { + internal_order_test(); + + int size = taskData->inputs_count[0]; + if (size % 3 != 0) { + return false; + } + + for (int i = 0; i < size; ++i) { + int value = reinterpret_cast(taskData->inputs[0])[i]; + if (value < 0 || value > 255) { + return false; + } + } + + return (taskData->inputs_count[0] > 0) && (taskData->outputs_count[0] > 0); +} + +bool leontev_n_image_enhancement_mpi::MPIImgEnhancementSequential::run() { + internal_order_test(); + + int size = image_input.size(); + image_output.resize(size); + int Imin = 255; + int Imax = 0; + + for (int intensity : I) { + Imin = std::min(Imin, intensity); + Imax = std::max(Imax, intensity); + } + + if (Imin == Imax) { + image_output = image_input; + return true; + } + + for (size_t i = 0; i < I.size(); i++) { + int Inew = ((I[i] - Imin) * 255) / (Imax - Imin); + + float scale = static_cast(Inew) / static_cast(I[i]); + + image_output[3 * i] = std::min(255, static_cast(image_input[3 * i] * scale)); + image_output[3 * i + 1] = std::min(255, static_cast(image_input[3 * i + 1] * scale)); + image_output[3 * i + 2] = std::min(255, static_cast(image_input[3 * i + 2] * scale)); + } + + return true; +} + +bool leontev_n_image_enhancement_mpi::MPIImgEnhancementSequential::post_processing() { + internal_order_test(); + + auto* output = reinterpret_cast(taskData->outputs[0]); + std::copy(image_output.begin(), image_output.end(), output); + return true; +} + +bool leontev_n_image_enhancement_mpi::MPIImgEnhancementParallel::pre_processing() { + internal_order_test(); + if (world.rank() == 0) { + int size = taskData->inputs_count[0]; + image_input = std::vector(size); + auto* tmp_ptr = reinterpret_cast(taskData->inputs[0]); + std::copy(tmp_ptr, tmp_ptr + size, image_input.begin()); + image_output = {}; + } + return true; +} + +bool leontev_n_image_enhancement_mpi::MPIImgEnhancementParallel::validation() { + internal_order_test(); + if (world.rank() == 0) { + int size = taskData->inputs_count[0]; + if (size % 3 != 0) { + return false; + } + + for (int i = 0; i < size; ++i) { + int value = reinterpret_cast(taskData->inputs[0])[i]; + if (value < 0 || value > 255) { + return false; + } + } + + return (taskData->inputs_count[0] > 0) && (taskData->outputs_count[0] > 0); + } + return true; +} + +bool leontev_n_image_enhancement_mpi::MPIImgEnhancementParallel::run() { + internal_order_test(); + + int size = 0; + if (world.rank() == 0) { + size = image_input.size(); + } + + broadcast(world, size, 0); + + int num_pixels = 0; + int pixels_per_process = 0; + int extra_pixels = 0; + if (world.rank() == 0) { + num_pixels = size / 3; + pixels_per_process = num_pixels / world.size(); + extra_pixels = num_pixels % world.size(); + } + + broadcast(world, num_pixels, 0); + broadcast(world, pixels_per_process, 0); + broadcast(world, extra_pixels, 0); + + int local_pixels = pixels_per_process + (world.rank() < extra_pixels ? 1 : 0); + + std::vector offset(world.size(), 0); + std::vector send_counts(world.size(), 0); + + if (world.rank() == 0) { + for (int proc = 0; proc < world.size(); ++proc) { + send_counts[proc] = (pixels_per_process + (proc < extra_pixels ? 1 : 0)) * 3; + if (proc > 0) { + offset[proc] = offset[proc - 1] + send_counts[proc - 1]; + } + } + } + + broadcast(world, send_counts.data(), send_counts.size(), 0); + broadcast(world, offset.data(), offset.size(), 0); + + std::vector local_input(local_pixels * 3); + boost::mpi::scatterv(world, image_input.data(), send_counts, offset, local_input.data(), local_pixels * 3, 0); + + int local_Imin = 255; + int local_Imax = 0; + std::vector local_I(local_pixels); + for (int i = 0; i < local_pixels; i++) { + int r = local_input[3 * i]; + int g = local_input[3 * i + 1]; + int b = local_input[3 * i + 2]; + + local_I[i] = (r + g + b) / 3; + local_Imin = std::min(local_Imin, local_I[i]); + local_Imax = std::max(local_Imax, local_I[i]); + } + + int global_Imin; + int global_Imax; + boost::mpi::all_reduce(world, local_Imin, global_Imin, boost::mpi::minimum()); + boost::mpi::all_reduce(world, local_Imax, global_Imax, boost::mpi::maximum()); + + if (global_Imin == global_Imax) { + if (world.rank() == 0) { + image_output = image_input; + } + return true; + } + + std::vector local_output(local_pixels * 3); + for (int i = 0; i < local_pixels; i++) { + int Inew = ((local_I[i] - global_Imin) * 255) / (global_Imax - global_Imin); + float scale = static_cast(Inew) / static_cast(local_I[i]); + + local_output[3 * i] = std::min(255, static_cast(local_input[3 * i] * scale)); + local_output[3 * i + 1] = std::min(255, static_cast(local_input[3 * i + 1] * scale)); + local_output[3 * i + 2] = std::min(255, static_cast(local_input[3 * i + 2] * scale)); + } + + if (world.rank() == 0) { + image_output.resize(size); + } + + boost::mpi::gatherv(world, local_output.data(), local_pixels * 3, image_output.data(), send_counts, offset, 0); + + return true; +} + +bool leontev_n_image_enhancement_mpi::MPIImgEnhancementParallel::post_processing() { + internal_order_test(); + if (world.rank() == 0) { + auto* output = reinterpret_cast(taskData->outputs[0]); + std::copy(image_output.begin(), image_output.end(), output); + } + return true; +} \ No newline at end of file diff --git a/tasks/seq/leontev_n_image_enhancement/func_tests/main.cpp b/tasks/seq/leontev_n_image_enhancement/func_tests/main.cpp new file mode 100644 index 00000000000..c318ed467cd --- /dev/null +++ b/tasks/seq/leontev_n_image_enhancement/func_tests/main.cpp @@ -0,0 +1,132 @@ +#include + +#include +#include + +#include "seq/leontev_n_image_enhancement/include/ops_seq.hpp" + +namespace leontev_n_image_enhancement_seq { +std::vector getRandomImage(int sz) { + std::random_device dev; + std::mt19937 gen(dev()); + std::uniform_int_distribution dist(0, 255); + std::vector vec(sz); + for (int i = 0; i < sz; i++) { + vec[i] = dist(gen); + } + return vec; +} +} // namespace leontev_n_image_enhancement_seq + +template +void taskEmplacement(std::shared_ptr &taskDataPar, std::vector &global_vec, + std::vector &global_sum) { + taskDataPar->inputs.emplace_back(reinterpret_cast(global_vec.data())); + taskDataPar->inputs_count.emplace_back(global_vec.size()); + taskDataPar->outputs.emplace_back(reinterpret_cast(global_sum.data())); + taskDataPar->outputs_count.emplace_back(global_sum.size()); +} + +TEST(leontev_n_image_enhancement_seq, test_image_1) { + const int vector_size = 9; + + std::shared_ptr taskDataSeq = std::make_shared(); + leontev_n_image_enhancement_seq::ImgEnhancementSequential imgEnhancementSequential(taskDataSeq); + + // Create data + std::vector in_vec = {15, 50, 45, 101, 92, 79, 0, 0, 15}; + std::vector out_vec(vector_size, 0); + + // Create TaskData + + taskEmplacement(taskDataSeq, in_vec, out_vec); + + // Create Task + ASSERT_EQ(imgEnhancementSequential.validation(), true); + imgEnhancementSequential.pre_processing(); + imgEnhancementSequential.run(); + imgEnhancementSequential.post_processing(); + + ASSERT_EQ(out_vec, std::vector({38, 129, 116, 255, 255, 223, 0, 0, 0})); +} + +TEST(leontev_n_image_enhancement_seq, test_image_2) { + const int vector_size = 27; + + std::shared_ptr taskDataSeq = std::make_shared(); + leontev_n_image_enhancement_seq::ImgEnhancementSequential imgEnhancementSequential(taskDataSeq); + + // Create data + std::vector in_vec(27); + for (size_t i = 0; i < in_vec.size(); i++) { + in_vec[i] = i; + } + std::vector out_vec(vector_size, 0); + + // Create TaskData + + taskEmplacement(taskDataSeq, in_vec, out_vec); + + // Create Task + ASSERT_EQ(imgEnhancementSequential.validation(), true); + imgEnhancementSequential.pre_processing(); + imgEnhancementSequential.run(); + imgEnhancementSequential.post_processing(); + + ASSERT_EQ(out_vec, std::vector({0, 0, 0, 23, 31, 38, 54, 63, 72, 85, 95, 104, 117, 127, + 136, 149, 159, 168, 180, 191, 201, 212, 223, 233, 244, 255, 255})); +} + +TEST(leontev_n_image_enhancement_seq, test_incorrect_size) { + const int vector_size = 8; + + std::shared_ptr taskDataSeq = std::make_shared(); + leontev_n_image_enhancement_seq::ImgEnhancementSequential imgEnhancementSequential(taskDataSeq); + + // Create data + std::vector in_vec = {15, 50, 45, 101, 92, 79, 0, 0}; + std::vector out_vec(vector_size, 0); + + // Create TaskData + + taskEmplacement(taskDataSeq, in_vec, out_vec); + + // Create Task + ASSERT_EQ(imgEnhancementSequential.validation(), false); +} + +TEST(leontev_n_image_enhancement_seq, test_incorrect_color_range) { + const int vector_size = 12; + + std::shared_ptr taskDataSeq = std::make_shared(); + leontev_n_image_enhancement_seq::ImgEnhancementSequential imgEnhancementSequential(taskDataSeq); + + // Create data + std::vector in_vec = {631, -2, 45, 101, 92, 79, 0, 0, 300, 255, 10, 15}; + std::vector out_vec(vector_size, 0); + + // Create TaskData + + taskEmplacement(taskDataSeq, in_vec, out_vec); + + // Create Task + ASSERT_EQ(imgEnhancementSequential.validation(), false); +} + +TEST(leontev_n_image_enhancement_seq, test_empty_image) { + const int vector_size = 0; + + std::shared_ptr taskDataSeq = std::make_shared(); + leontev_n_image_enhancement_seq::ImgEnhancementSequential imgEnhancementSequential(taskDataSeq); + + // Create data + std::vector in_vec = {}; + std::vector out_vec(vector_size, 0); + + // Create TaskData + + taskEmplacement(taskDataSeq, in_vec, out_vec); + + // Create Task + ASSERT_EQ(imgEnhancementSequential.validation(), false); +} \ No newline at end of file diff --git a/tasks/seq/leontev_n_image_enhancement/include/ops_seq.hpp b/tasks/seq/leontev_n_image_enhancement/include/ops_seq.hpp new file mode 100644 index 00000000000..57f061d890a --- /dev/null +++ b/tasks/seq/leontev_n_image_enhancement/include/ops_seq.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include +#include + +#include "core/task/include/task.hpp" + +namespace leontev_n_image_enhancement_seq { +class ImgEnhancementSequential : public ppc::core::Task { + public: + explicit ImgEnhancementSequential(std::shared_ptr taskData_) : Task(std::move(taskData_)) {} + bool pre_processing() override; + bool validation() override; + bool run() override; + bool post_processing() override; + + private: + std::vector I; + std::vector image_input; + std::vector image_output; +}; +} // namespace leontev_n_image_enhancement_seq \ No newline at end of file diff --git a/tasks/seq/leontev_n_image_enhancement/perf_tests/main.cpp b/tasks/seq/leontev_n_image_enhancement/perf_tests/main.cpp new file mode 100644 index 00000000000..d1f6136f9f8 --- /dev/null +++ b/tasks/seq/leontev_n_image_enhancement/perf_tests/main.cpp @@ -0,0 +1,84 @@ +#include + +#include +#include + +#include "core/perf/include/perf.hpp" +#include "seq/leontev_n_image_enhancement/include/ops_seq.hpp" + +template +void taskEmplacement(std::shared_ptr &taskDataPar, std::vector &global_vec, + std::vector &global_sum) { + taskDataPar->inputs.emplace_back(reinterpret_cast(global_vec.data())); + taskDataPar->inputs_count.emplace_back(global_vec.size()); + taskDataPar->outputs.emplace_back(reinterpret_cast(global_sum.data())); + taskDataPar->outputs_count.emplace_back(global_sum.size()); +} + +TEST(leontev_n_image_enhancement_seq, test_pipeline_run) { + const int width = 4000; + const int height = 4000; + const int count_size_vector = width * height * 3; + + std::vector in_vec(count_size_vector, 0); + std::vector out_vec(count_size_vector, 0); + std::vector res_exp_out(count_size_vector, 0); + + std::shared_ptr taskDataSeq = std::make_shared(); + auto imgEnhancementSequential = + std::make_shared(taskDataSeq); + taskEmplacement(taskDataSeq, in_vec, out_vec); + + // Create Perf attributes + auto perfAttr = std::make_shared(); + perfAttr->num_running = 10; + const auto t0 = std::chrono::high_resolution_clock::now(); + perfAttr->current_timer = [&] { + auto current_time_point = std::chrono::high_resolution_clock::now(); + auto duration = std::chrono::duration_cast(current_time_point - t0).count(); + return static_cast(duration) * 1e-9; + }; + + // Create and init perf results + auto perfResults = std::make_shared(); + + // Create Perf analyzer + auto perfAnalyzer = std::make_shared(imgEnhancementSequential); + perfAnalyzer->pipeline_run(perfAttr, perfResults); + ppc::core::Perf::print_perf_statistic(perfResults); + ASSERT_EQ(res_exp_out, out_vec); +} + +TEST(leontev_n_image_enhancement_seq, test_task_run) { + const int width = 4000; + const int height = 4000; + const int count_size_vector = width * height * 3; + + std::vector in_vec(count_size_vector, 0); + std::vector out_vec(count_size_vector, 0); + std::vector res_exp_out(count_size_vector, 0); + + std::shared_ptr taskDataSeq = std::make_shared(); + auto imgEnhancementSequential = + std::make_shared(taskDataSeq); + taskEmplacement(taskDataSeq, in_vec, out_vec); + + // Create Perf attributes + auto perfAttr = std::make_shared(); + perfAttr->num_running = 10; + const auto t0 = std::chrono::high_resolution_clock::now(); + perfAttr->current_timer = [&] { + auto current_time_point = std::chrono::high_resolution_clock::now(); + auto duration = std::chrono::duration_cast(current_time_point - t0).count(); + return static_cast(duration) * 1e-9; + }; + + // Create and init perf results + auto perfResults = std::make_shared(); + + // Create Perf analyzer + auto perfAnalyzer = std::make_shared(imgEnhancementSequential); + perfAnalyzer->task_run(perfAttr, perfResults); + ppc::core::Perf::print_perf_statistic(perfResults); + ASSERT_EQ(res_exp_out, out_vec); +} diff --git a/tasks/seq/leontev_n_image_enhancement/src/ops_seq.cpp b/tasks/seq/leontev_n_image_enhancement/src/ops_seq.cpp new file mode 100644 index 00000000000..0908ee3e48c --- /dev/null +++ b/tasks/seq/leontev_n_image_enhancement/src/ops_seq.cpp @@ -0,0 +1,72 @@ +#include "seq/leontev_n_image_enhancement/include/ops_seq.hpp" + +#include +#include + +bool leontev_n_image_enhancement_seq::ImgEnhancementSequential::pre_processing() { + internal_order_test(); + + int size = taskData->inputs_count[0]; + image_input = std::vector(size); + auto* tmp_ptr = reinterpret_cast(taskData->inputs[0]); + std::copy(tmp_ptr, tmp_ptr + size, image_input.begin()); + + int pixel_count = size / 3; + I.resize(pixel_count); + for (int i = 0; i < pixel_count; i++) { + int r = image_input[3 * i]; + int g = image_input[3 * i + 1]; + int b = image_input[3 * i + 2]; + + I[i] = (r + g + b) / 3; + } + + image_output = {}; + return true; +} + +bool leontev_n_image_enhancement_seq::ImgEnhancementSequential::validation() { + internal_order_test(); + int size = taskData->inputs_count[0]; + if (size % 3 != 0) return false; + + for (int i = 0; i < size; ++i) { + int value = reinterpret_cast(taskData->inputs[0])[i]; + if (value < 0 || value > 255) { + return false; + } + } + + return (taskData->inputs_count[0] > 0) && (taskData->outputs_count[0] > 0); +} + +bool leontev_n_image_enhancement_seq::ImgEnhancementSequential::run() { + internal_order_test(); + int size = image_input.size(); + image_output.resize(size); + int Imin = 255; + int Imax = 0; + for (int intensity : I) { + Imin = std::min(Imin, intensity); + Imax = std::max(Imax, intensity); + } + if (Imin == Imax) { + image_output = image_input; + return true; + } + for (size_t i = 0; i < I.size(); i++) { + int Inew = ((I[i] - Imin) * 255) / (Imax - Imin); + float scale = static_cast(Inew) / static_cast(I[i]); + image_output[3 * i] = std::min(255, static_cast(image_input[3 * i] * scale)); + image_output[3 * i + 1] = std::min(255, static_cast(image_input[3 * i + 1] * scale)); + image_output[3 * i + 2] = std::min(255, static_cast(image_input[3 * i + 2] * scale)); + } + return true; +} + +bool leontev_n_image_enhancement_seq::ImgEnhancementSequential::post_processing() { + internal_order_test(); + auto* output = reinterpret_cast(taskData->outputs[0]); + std::copy(image_output.begin(), image_output.end(), output); + return true; +} \ No newline at end of file