From 27135fa77fc3fbb3304b575a6faaacb8e292276d Mon Sep 17 00:00:00 2001 From: VladimirSdobnov <114135450+VladimirSdobnov@users.noreply.github.com> Date: Sun, 29 Dec 2024 22:47:06 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A1=D0=B4=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=20?= =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D0=BC=D0=B8=D1=80=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=2015.=20=D0=A7=D0=B5=D1=82=D0=BD=D0=BE-=D0=BD?= =?UTF-8?q?=D0=B5=D1=87=D0=B5=D1=82=D0=BD=D0=B0=D1=8F=20=D1=81=D0=BE=D1=80?= =?UTF-8?q?=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=BA=D0=B0=20=D1=81=D0=BB=D0=B8?= =?UTF-8?q?=D1=8F=D0=BD=D0=B8=D0=B5=D0=BC=20=D0=91=D0=B5=D1=82=D1=87=D0=B5?= =?UTF-8?q?=D1=80=D0=B0=20(#783)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Входные данные: Для последовательного алгоритма: вектор и его размер равный степени двойки Для параллельного: вектор и его размер Описание параллельного алгоритма: Делим вектор между потоками. Каждый поток сортирует свои данные, после чего данные из потоков сливаются. Процесс слияния: Процесс получает данные от следующего за ним процесса, объединяет их со своими и сортирует, затем возвращает вторую половину полученного вектора обратно. Пары выбираются поочередно, сначала (0,1), (2,3), (4,5) и тд, затем (1,2), (3,4), (5,6). Число слияний равно числу потоков. После прохождения слияний все данные собираются в 0 потоке. --- .../func_tests/main.cpp | 217 ++++++++++++++++++ .../include/ops_mpi.hpp | 32 +++ .../perf_tests/main.cpp | 87 +++++++ .../src/ops_mpi.cpp | 161 +++++++++++++ .../func_tests/main.cpp | 193 ++++++++++++++++ .../include/ops_seq.hpp | 27 +++ .../perf_tests/main.cpp | 75 ++++++ .../src/ops_seq.cpp | 68 ++++++ 8 files changed, 860 insertions(+) create mode 100644 tasks/mpi/Sdobnov_V_mergesort_Betcher/func_tests/main.cpp create mode 100644 tasks/mpi/Sdobnov_V_mergesort_Betcher/include/ops_mpi.hpp create mode 100644 tasks/mpi/Sdobnov_V_mergesort_Betcher/perf_tests/main.cpp create mode 100644 tasks/mpi/Sdobnov_V_mergesort_Betcher/src/ops_mpi.cpp create mode 100644 tasks/seq/Sdobnov_V_mergesort_Betcher/func_tests/main.cpp create mode 100644 tasks/seq/Sdobnov_V_mergesort_Betcher/include/ops_seq.hpp create mode 100644 tasks/seq/Sdobnov_V_mergesort_Betcher/perf_tests/main.cpp create mode 100644 tasks/seq/Sdobnov_V_mergesort_Betcher/src/ops_seq.cpp diff --git a/tasks/mpi/Sdobnov_V_mergesort_Betcher/func_tests/main.cpp b/tasks/mpi/Sdobnov_V_mergesort_Betcher/func_tests/main.cpp new file mode 100644 index 00000000000..4cbf31040f2 --- /dev/null +++ b/tasks/mpi/Sdobnov_V_mergesort_Betcher/func_tests/main.cpp @@ -0,0 +1,217 @@ +#include + +#include +#include +#include + +#include "mpi/Sdobnov_V_mergesort_Betcher/include/ops_mpi.hpp" + +TEST(Sdobnov_V_mergesort_Betcher_par, InvalidInputCount) { + boost::mpi::communicator world; + + int size = 10; + std::vector res(size, 0); + std::vector input = {2, 1, 0, 3, 9, 7, 2, 6, 4, 8}; + std::vector expected_res = {0, 1, 2, 2, 3, 4, 6, 7, 8, 9}; + + std::shared_ptr taskDataPar = std::make_shared(); + if (world.rank() == 0) { + taskDataPar->inputs.emplace_back(reinterpret_cast(input.data())); + taskDataPar->outputs_count.emplace_back(size); + taskDataPar->outputs.emplace_back(reinterpret_cast(res.data())); + } + + Sdobnov_V_mergesort_Betcher_par::MergesortBetcherPar test(taskDataPar); + if (world.rank() == 0) { + ASSERT_FALSE(test.validation()); + } +} + +TEST(Sdobnov_V_mergesort_Betcher_par, InvalidInput) { + boost::mpi::communicator world; + + int size = 10; + std::vector res(size, 0); + std::vector input = {2, 1, 0, 3, 9, 7, 2, 6, 4, 8}; + std::vector expected_res = {0, 1, 2, 2, 3, 4, 6, 7, 8, 9}; + + std::shared_ptr taskDataPar = std::make_shared(); + if (world.rank() == 0) { + taskDataPar->inputs_count.emplace_back(size); + taskDataPar->outputs_count.emplace_back(size); + taskDataPar->outputs.emplace_back(reinterpret_cast(res.data())); + } + + Sdobnov_V_mergesort_Betcher_par::MergesortBetcherPar test(taskDataPar); + + if (world.rank() == 0) { + ASSERT_FALSE(test.validation()); + } +} + +TEST(Sdobnov_V_mergesort_Betcher_par, InvalidOutputCount) { + boost::mpi::communicator world; + + int size = 10; + std::vector res(size, 0); + std::vector input = {2, 1, 0, 3, 9, 7, 2, 6, 4, 8}; + std::vector expected_res = {0, 1, 2, 2, 3, 4, 6, 7, 8, 9}; + + std::shared_ptr taskDataPar = std::make_shared(); + + if (world.rank() == 0) { + taskDataPar->inputs_count.emplace_back(size); + taskDataPar->inputs.emplace_back(reinterpret_cast(input.data())); + taskDataPar->outputs.emplace_back(reinterpret_cast(res.data())); + } + + Sdobnov_V_mergesort_Betcher_par::MergesortBetcherPar test(taskDataPar); + + if (world.rank() == 0) { + ASSERT_FALSE(test.validation()); + } +} + +TEST(Sdobnov_V_mergesort_Betcher_par, InvalidOutput) { + boost::mpi::communicator world; + + int size = 10; + std::vector res(size, 0); + std::vector input = {2, 1, 0, 3, 9, 7, 2, 6, 4, 8}; + std::vector expected_res = {0, 1, 2, 2, 3, 4, 6, 7, 8, 9}; + + std::shared_ptr taskDataPar = std::make_shared(); + if (world.rank() == 0) { + taskDataPar->inputs_count.emplace_back(size); + taskDataPar->inputs.emplace_back(reinterpret_cast(input.data())); + taskDataPar->outputs_count.emplace_back(size); + } + + Sdobnov_V_mergesort_Betcher_par::MergesortBetcherPar test(taskDataPar); + + if (world.rank() == 0) { + ASSERT_FALSE(test.validation()); + } +} + +TEST(Sdobnov_V_mergesort_Betcher_par, SortTest8) { + boost::mpi::communicator world; + + int size = 8; + std::vector res(size, 0); + std::vector input = {2, 8, 3, 9, 5, 6, 4, 0}; + std::vector expected_res = {0, 2, 3, 4, 5, 6, 8, 9}; + std::shared_ptr taskDataPar = std::make_shared(); + + if (world.rank() == 0) { + taskDataPar->inputs_count.emplace_back(size); + taskDataPar->inputs.emplace_back(reinterpret_cast(input.data())); + taskDataPar->outputs_count.emplace_back(size); + taskDataPar->outputs.emplace_back(reinterpret_cast(res.data())); + } + + Sdobnov_V_mergesort_Betcher_par::MergesortBetcherPar test(taskDataPar); + test.validation(); + test.pre_processing(); + test.run(); + test.post_processing(); + + if (world.rank() == 0) { + for (int i = 0; i < size; i++) { + ASSERT_EQ(res[i], expected_res[i]); + } + } +} + +TEST(Sdobnov_V_mergesort_Betcher_par, SortTestRand16) { + boost::mpi::communicator world; + + int size = 16; + std::vector res(size, 0); + std::vector input = Sdobnov_V_mergesort_Betcher_par::generate_random_vector(size, 0, 1000); + + std::shared_ptr taskDataPar = std::make_shared(); + + if (world.rank() == 0) { + taskDataPar->inputs_count.emplace_back(size); + taskDataPar->inputs.emplace_back(reinterpret_cast(input.data())); + taskDataPar->outputs_count.emplace_back(size); + taskDataPar->outputs.emplace_back(reinterpret_cast(res.data())); + } + + Sdobnov_V_mergesort_Betcher_par::MergesortBetcherPar test(taskDataPar); + test.validation(); + test.pre_processing(); + test.run(); + test.post_processing(); + + if (world.rank() == 0) { + std::vector expected_res = input; + std::sort(expected_res.begin(), expected_res.end()); + for (int i = 0; i < size; i++) { + ASSERT_EQ(res[i], expected_res[i]); + } + } +} + +TEST(Sdobnov_V_mergesort_Betcher_par, SortTestRand32) { + boost::mpi::communicator world; + + int size = 32; + std::vector res(size, 0); + std::vector input = Sdobnov_V_mergesort_Betcher_par::generate_random_vector(size, 0, 1000); + + std::shared_ptr taskDataPar = std::make_shared(); + + if (world.rank() == 0) { + taskDataPar->inputs_count.emplace_back(size); + taskDataPar->inputs.emplace_back(reinterpret_cast(input.data())); + taskDataPar->outputs_count.emplace_back(size); + taskDataPar->outputs.emplace_back(reinterpret_cast(res.data())); + } + + Sdobnov_V_mergesort_Betcher_par::MergesortBetcherPar test(taskDataPar); + test.validation(); + test.pre_processing(); + test.run(); + test.post_processing(); + + if (world.rank() == 0) { + std::vector expected_res = input; + std::sort(expected_res.begin(), expected_res.end()); + for (int i = 0; i < size; i++) { + ASSERT_EQ(res[i], expected_res[i]); + } + } +} + +TEST(Sdobnov_V_mergesort_Betcher_par, SortTestRand64) { + boost::mpi::communicator world; + + int size = 64; + std::vector res(size, 0); + std::vector input = Sdobnov_V_mergesort_Betcher_par::generate_random_vector(size, 0, 1000); + + std::shared_ptr taskDataPar = std::make_shared(); + + if (world.rank() == 0) { + taskDataPar->inputs_count.emplace_back(size); + taskDataPar->inputs.emplace_back(reinterpret_cast(input.data())); + taskDataPar->outputs_count.emplace_back(size); + taskDataPar->outputs.emplace_back(reinterpret_cast(res.data())); + } + + Sdobnov_V_mergesort_Betcher_par::MergesortBetcherPar test(taskDataPar); + test.validation(); + test.pre_processing(); + test.run(); + test.post_processing(); + + if (world.rank() == 0) { + std::vector expected_res = input; + std::sort(expected_res.begin(), expected_res.end()); + for (int i = 0; i < size; i++) { + ASSERT_EQ(res[i], expected_res[i]); + } + } +} diff --git a/tasks/mpi/Sdobnov_V_mergesort_Betcher/include/ops_mpi.hpp b/tasks/mpi/Sdobnov_V_mergesort_Betcher/include/ops_mpi.hpp new file mode 100644 index 00000000000..3e4068ea9c6 --- /dev/null +++ b/tasks/mpi/Sdobnov_V_mergesort_Betcher/include/ops_mpi.hpp @@ -0,0 +1,32 @@ +// Copyright 2024 Sdobnov Vladimir +#pragma once +#include + +#include +#include +#include + +#include "core/task/include/task.hpp" + +namespace Sdobnov_V_mergesort_Betcher_par { + +std::vector generate_random_vector(int size, int lower_bound = 0, int upper_bound = 50); +int partition(std::vector& vec, int low, int high); +void quickSortIterative(std::vector& vec, int low, int high); + +class MergesortBetcherPar : public ppc::core::Task { + public: + explicit MergesortBetcherPar(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 input_; + int size_; + std::vector local_vec_; + + boost::mpi::communicator world; +}; +} // namespace Sdobnov_V_mergesort_Betcher_par \ No newline at end of file diff --git a/tasks/mpi/Sdobnov_V_mergesort_Betcher/perf_tests/main.cpp b/tasks/mpi/Sdobnov_V_mergesort_Betcher/perf_tests/main.cpp new file mode 100644 index 00000000000..d560f26167a --- /dev/null +++ b/tasks/mpi/Sdobnov_V_mergesort_Betcher/perf_tests/main.cpp @@ -0,0 +1,87 @@ +#include + +#include +#include +#include + +#include "core/perf/include/perf.hpp" +#include "mpi/Sdobnov_V_mergesort_Betcher/include/ops_mpi.hpp" + +TEST(Sdobnov_V_mergesort_Betcher_par, test_pipeline_run) { + boost::mpi::communicator world; + + long unsigned int size = 4096; + std::vector res(size, 0); + std::vector input = Sdobnov_V_mergesort_Betcher_par::generate_random_vector(size, 0, 1000); + + std::shared_ptr taskDataPar = std::make_shared(); + if (world.rank() == 0) { + taskDataPar->inputs_count.emplace_back(size); + taskDataPar->inputs.emplace_back(reinterpret_cast(input.data())); + taskDataPar->outputs_count.emplace_back(size); + taskDataPar->outputs.emplace_back(reinterpret_cast(res.data())); + } + + auto test = std::make_shared(taskDataPar); + test->validation(); + test->pre_processing(); + test->run(); + test->post_processing(); + + 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; + }; + auto perfResults = std::make_shared(); + auto perfAnalyzer = std::make_shared(test); + perfAnalyzer->pipeline_run(perfAttr, perfResults); + ppc::core::Perf::print_perf_statistic(perfResults); + + if (world.rank() == 0) { + ASSERT_EQ(res.size(), size); + } +} + +TEST(Sdobnov_V_mergesort_Betcher_par, test_task_run) { + boost::mpi::communicator world; + + long unsigned int size = 4096; + std::vector res(size, 0); + std::vector input = Sdobnov_V_mergesort_Betcher_par::generate_random_vector(size, 0, 1000); + + std::shared_ptr taskDataPar = std::make_shared(); + + if (world.rank() == 0) { + taskDataPar->inputs_count.emplace_back(size); + taskDataPar->inputs.emplace_back(reinterpret_cast(input.data())); + taskDataPar->outputs_count.emplace_back(size); + taskDataPar->outputs.emplace_back(reinterpret_cast(res.data())); + } + + auto test = std::make_shared(taskDataPar); + test->validation(); + test->pre_processing(); + test->run(); + test->post_processing(); + + 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; + }; + auto perfResults = std::make_shared(); + auto perfAnalyzer = std::make_shared(test); + perfAnalyzer->task_run(perfAttr, perfResults); + ppc::core::Perf::print_perf_statistic(perfResults); + + if (world.rank() == 0) { + ASSERT_EQ(res.size(), size); + } +} \ No newline at end of file diff --git a/tasks/mpi/Sdobnov_V_mergesort_Betcher/src/ops_mpi.cpp b/tasks/mpi/Sdobnov_V_mergesort_Betcher/src/ops_mpi.cpp new file mode 100644 index 00000000000..00d0ef684ed --- /dev/null +++ b/tasks/mpi/Sdobnov_V_mergesort_Betcher/src/ops_mpi.cpp @@ -0,0 +1,161 @@ +// Copyright 2024 Sdobnov Vladimir +#include "mpi/Sdobnov_V_mergesort_Betcher/include/ops_mpi.hpp" + +#include +#include +#include + +std::vector Sdobnov_V_mergesort_Betcher_par::generate_random_vector(int size, int lower_bound, int upper_bound) { + std::vector res(size); + for (int i = 0; i < size; i++) { + res[i] = lower_bound + rand() % (upper_bound - lower_bound + 1); + } + return res; +} + +int Sdobnov_V_mergesort_Betcher_par::partition(std::vector& vec, int low, int high) { + int pivot = vec[high]; + int i = low - 1; + + for (int j = low; j < high; ++j) { + if (vec[j] <= pivot) { + i++; + std::swap(vec[i], vec[j]); + } + } + + std::swap(vec[i + 1], vec[high]); + return i + 1; +} + +void Sdobnov_V_mergesort_Betcher_par::quickSortIterative(std::vector& vec, int low, int high) { + std::stack> s; + s.emplace(low, high); + + while (!s.empty()) { + auto [l, h] = s.top(); + s.pop(); + if (l < h) { + int pi = partition(vec, l, h); + s.emplace(l, pi - 1); + s.emplace(pi + 1, h); + } + } +} + +bool Sdobnov_V_mergesort_Betcher_par::MergesortBetcherPar::pre_processing() { + internal_order_test(); + if (world.rank() == 0) { + size_ = taskData->inputs_count[0]; + input_.assign(size_, 0); + + auto* input = reinterpret_cast(taskData->inputs[0]); + + std::copy(input, input + size_, input_.begin()); + for (int i = 0; i < size_; i++) { + reinterpret_cast(taskData->outputs[0])[i] = input_[i]; + } + } + + return true; +} + +bool Sdobnov_V_mergesort_Betcher_par::MergesortBetcherPar::validation() { + internal_order_test(); + if (world.rank() == 0) + return (taskData->inputs_count.size() == 1 && taskData->inputs_count[0] >= 0 && taskData->inputs.size() == 1 && + taskData->outputs_count.size() == 1 && taskData->outputs_count[0] >= 0 && taskData->outputs.size() == 1); + return true; +} + +bool Sdobnov_V_mergesort_Betcher_par::MergesortBetcherPar::run() { + internal_order_test(); + + int input_size = 0; + int rank = world.rank(); + int size = world.size(); + if (rank == 0) input_size = size_; + boost::mpi::broadcast(world, input_size, 0); + + int elem_per_procces = input_size / size; + int residual_elements = input_size % size; + + int process_count = elem_per_procces + (rank < residual_elements ? 1 : 0); + + std::vector counts(size); + std::vector displacment(size); + + for (int i = 0; i < size; i++) { + counts[i] = elem_per_procces + (i < residual_elements ? 1 : 0); + displacment[i] = i * elem_per_procces + std::min(i, residual_elements); + } + + local_vec_.resize(counts[rank]); + boost::mpi::scatterv(world, input_.data(), counts, displacment, local_vec_.data(), process_count, 0); + + quickSortIterative(local_vec_, 0, counts[rank] - 1); + + for (int step = 0; step < size; step++) { + if (rank % 2 == 0) { + if (step % 2 == 0) { + if (rank + 1 < size) { + for (int i = 0; i < counts[rank + 1]; i++) { + int tmp; + world.recv(rank + 1, 0, tmp); + local_vec_.push_back(tmp); + } + quickSortIterative(local_vec_, 0, counts[rank] + counts[rank + 1] - 1); + for (int i = local_vec_.size() - 1; i >= counts[rank]; i--) { + world.send(rank + 1, 0, local_vec_[i]); + local_vec_.pop_back(); + } + } + } else { + if (rank - 1 > 0) { + for (int i = 0; i < counts[rank]; i++) { + world.send(rank - 1, 0, local_vec_[i]); + } + for (int i = local_vec_.size() - 1; i >= 0; i--) { + world.recv(rank - 1, 0, local_vec_[i]); + } + } + } + } else { + if (step % 2 == 0) { + for (int i = 0; i < counts[rank]; i++) { + world.send(rank - 1, 0, local_vec_[i]); + } + for (int i = local_vec_.size() - 1; i >= 0; i--) { + world.recv(rank - 1, 0, local_vec_[i]); + } + } else { + if (rank + 1 < size) { + for (int i = 0; i < counts[rank + 1]; i++) { + int tmp; + world.recv(rank + 1, 0, tmp); + local_vec_.push_back(tmp); + } + quickSortIterative(local_vec_, 0, counts[rank] + counts[rank + 1] - 1); + for (int i = local_vec_.size() - 1; i >= counts[rank]; i--) { + world.send(rank + 1, 0, local_vec_[i]); + local_vec_.pop_back(); + } + } + } + } + quickSortIterative(local_vec_, 0, counts[rank] - 1); + } + boost::mpi::gather(world, local_vec_.data(), counts[rank], input_.data(), 0); + + return true; +} + +bool Sdobnov_V_mergesort_Betcher_par::MergesortBetcherPar::post_processing() { + internal_order_test(); + if (world.rank() == 0) { + for (int i = 0; i < size_; i++) { + reinterpret_cast(taskData->outputs[0])[i] = input_[i]; + } + } + return true; +} \ No newline at end of file diff --git a/tasks/seq/Sdobnov_V_mergesort_Betcher/func_tests/main.cpp b/tasks/seq/Sdobnov_V_mergesort_Betcher/func_tests/main.cpp new file mode 100644 index 00000000000..6a90133f144 --- /dev/null +++ b/tasks/seq/Sdobnov_V_mergesort_Betcher/func_tests/main.cpp @@ -0,0 +1,193 @@ +// Copyright 2024 Sdobnov Vladimir + +#include + +#include +#include +#include +#include + +#include "seq/Sdobnov_V_mergesort_Betcher/include/ops_seq.hpp" + +TEST(Sdobnov_V_mergesort_Betcher_seq, InvalidInputCount) { + int size = 8; + std::vector res(size, 0); + std::vector input = {2, 1, 0, 3, 2, 6, 4, 8}; + + std::shared_ptr taskDataSeq = std::make_shared(); + + taskDataSeq->inputs.emplace_back(reinterpret_cast(input.data())); + taskDataSeq->outputs_count.emplace_back(size); + taskDataSeq->outputs.emplace_back(reinterpret_cast(res.data())); + + Sdobnov_V_mergesort_Betcher_seq::MergesortBetcherSeq test(taskDataSeq); + + ASSERT_FALSE(test.validation()); +} + +TEST(Sdobnov_V_mergesort_Betcher_seq, InvalidInputCountNotPow2) { + int size = 9; + std::vector res(size, 0); + std::vector input = {2, 1, 0, 3, 2, 6, 4, 8, 9}; + + std::shared_ptr taskDataSeq = std::make_shared(); + + taskDataSeq->inputs_count.emplace_back(size); + taskDataSeq->inputs.emplace_back(reinterpret_cast(input.data())); + taskDataSeq->outputs_count.emplace_back(size); + taskDataSeq->outputs.emplace_back(reinterpret_cast(res.data())); + + Sdobnov_V_mergesort_Betcher_seq::MergesortBetcherSeq test(taskDataSeq); + + ASSERT_FALSE(test.validation()); +} + +TEST(Sdobnov_V_mergesort_Betcher_seq, InvalidInput) { + int size = 8; + std::vector res(size, 0); + + std::shared_ptr taskDataSeq = std::make_shared(); + + taskDataSeq->inputs_count.emplace_back(size); + taskDataSeq->outputs_count.emplace_back(size); + taskDataSeq->outputs.emplace_back(reinterpret_cast(res.data())); + + Sdobnov_V_mergesort_Betcher_seq::MergesortBetcherSeq test(taskDataSeq); + + ASSERT_FALSE(test.validation()); +} + +TEST(Sdobnov_V_mergesort_Betcher_seq, InvalidOutputCount) { + int size = 8; + std::vector res(size, 0); + std::vector input = {2, 1, 0, 3, 2, 6, 4, 8}; + + std::shared_ptr taskDataSeq = std::make_shared(); + + taskDataSeq->inputs_count.emplace_back(size); + taskDataSeq->inputs.emplace_back(reinterpret_cast(input.data())); + taskDataSeq->outputs.emplace_back(reinterpret_cast(res.data())); + + Sdobnov_V_mergesort_Betcher_seq::MergesortBetcherSeq test(taskDataSeq); + + ASSERT_FALSE(test.validation()); +} + +TEST(Sdobnov_V_mergesort_Betcher_seq, InvalidOutput) { + int size = 8; + std::vector res(size, 0); + std::vector input = {2, 1, 0, 3, 2, 6, 4, 8}; + + std::shared_ptr taskDataSeq = std::make_shared(); + + taskDataSeq->inputs_count.emplace_back(size); + taskDataSeq->inputs.emplace_back(reinterpret_cast(input.data())); + taskDataSeq->outputs_count.emplace_back(size); + + Sdobnov_V_mergesort_Betcher_seq::MergesortBetcherSeq test(taskDataSeq); + + ASSERT_FALSE(test.validation()); +} + +TEST(Sdobnov_V_mergesort_Betcher_seq, SortTest8) { + int size = 8; + std::vector res(size, 0); + std::vector input = {2, 8, 3, 9, 5, 6, 4, 0}; + std::vector expected_res = {0, 2, 3, 4, 5, 6, 8, 9}; + + std::shared_ptr taskDataSeq = std::make_shared(); + + taskDataSeq->inputs_count.emplace_back(size); + taskDataSeq->inputs.emplace_back(reinterpret_cast(input.data())); + taskDataSeq->outputs_count.emplace_back(size); + taskDataSeq->outputs.emplace_back(reinterpret_cast(res.data())); + + Sdobnov_V_mergesort_Betcher_seq::MergesortBetcherSeq test(taskDataSeq); + + ASSERT_TRUE(test.validation()); + test.pre_processing(); + test.run(); + test.post_processing(); + + for (int i = 0; i < size; i++) { + ASSERT_EQ(res[i], expected_res[i]); + } +} + +TEST(Sdobnov_V_mergesort_Betcher_seq, SortTestRand16) { + int size = 16; + std::vector res(size, 0); + std::vector input = Sdobnov_V_mergesort_Betcher_seq::generate_random_vector(size, 0, 1000); + std::vector expected_res = input; + std::sort(expected_res.begin(), expected_res.end()); + + std::shared_ptr taskDataSeq = std::make_shared(); + + taskDataSeq->inputs_count.emplace_back(size); + taskDataSeq->inputs.emplace_back(reinterpret_cast(input.data())); + taskDataSeq->outputs_count.emplace_back(size); + taskDataSeq->outputs.emplace_back(reinterpret_cast(res.data())); + + Sdobnov_V_mergesort_Betcher_seq::MergesortBetcherSeq test(taskDataSeq); + + ASSERT_TRUE(test.validation()); + test.pre_processing(); + test.run(); + test.post_processing(); + + for (int i = 0; i < size; i++) { + ASSERT_EQ(res[i], expected_res[i]); + } +} + +TEST(Sdobnov_V_mergesort_Betcher_seq, SortTestRand32) { + int size = 32; + std::vector res(size, 0); + std::vector input = Sdobnov_V_mergesort_Betcher_seq::generate_random_vector(size, 0, 1000); + std::vector expected_res = input; + std::sort(expected_res.begin(), expected_res.end()); + + std::shared_ptr taskDataSeq = std::make_shared(); + + taskDataSeq->inputs_count.emplace_back(size); + taskDataSeq->inputs.emplace_back(reinterpret_cast(input.data())); + taskDataSeq->outputs_count.emplace_back(size); + taskDataSeq->outputs.emplace_back(reinterpret_cast(res.data())); + + Sdobnov_V_mergesort_Betcher_seq::MergesortBetcherSeq test(taskDataSeq); + + ASSERT_TRUE(test.validation()); + test.pre_processing(); + test.run(); + test.post_processing(); + + for (int i = 0; i < size; i++) { + ASSERT_EQ(res[i], expected_res[i]); + } +} + +TEST(Sdobnov_V_mergesort_Betcher_seq, SortTestRand64) { + int size = 64; + std::vector res(size, 0); + std::vector input = Sdobnov_V_mergesort_Betcher_seq::generate_random_vector(size, 0, 1000); + std::vector expected_res = input; + std::sort(expected_res.begin(), expected_res.end()); + + std::shared_ptr taskDataSeq = std::make_shared(); + + taskDataSeq->inputs_count.emplace_back(size); + taskDataSeq->inputs.emplace_back(reinterpret_cast(input.data())); + taskDataSeq->outputs_count.emplace_back(size); + taskDataSeq->outputs.emplace_back(reinterpret_cast(res.data())); + + Sdobnov_V_mergesort_Betcher_seq::MergesortBetcherSeq test(taskDataSeq); + + ASSERT_TRUE(test.validation()); + test.pre_processing(); + test.run(); + test.post_processing(); + + for (int i = 0; i < size; i++) { + ASSERT_EQ(res[i], expected_res[i]); + } +} \ No newline at end of file diff --git a/tasks/seq/Sdobnov_V_mergesort_Betcher/include/ops_seq.hpp b/tasks/seq/Sdobnov_V_mergesort_Betcher/include/ops_seq.hpp new file mode 100644 index 00000000000..24ad522f37e --- /dev/null +++ b/tasks/seq/Sdobnov_V_mergesort_Betcher/include/ops_seq.hpp @@ -0,0 +1,27 @@ +// Copyright 2024 Sdobnov Vladimir +#pragma once +#include + +#include + +#include "core/task/include/task.hpp" + +namespace Sdobnov_V_mergesort_Betcher_seq { + +void sortPair(int& a, int& b); +void batchersort(std::vector& a, int l, int r); +std::vector generate_random_vector(int size, int lower_bound = 0, int upper_bound = 50); + +class MergesortBetcherSeq : public ppc::core::Task { + public: + explicit MergesortBetcherSeq(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 res_; + int size_; +}; +} // namespace Sdobnov_V_mergesort_Betcher_seq \ No newline at end of file diff --git a/tasks/seq/Sdobnov_V_mergesort_Betcher/perf_tests/main.cpp b/tasks/seq/Sdobnov_V_mergesort_Betcher/perf_tests/main.cpp new file mode 100644 index 00000000000..13b9bcbad20 --- /dev/null +++ b/tasks/seq/Sdobnov_V_mergesort_Betcher/perf_tests/main.cpp @@ -0,0 +1,75 @@ +#include + +#include +#include +#include +#include + +#include "core/perf/include/perf.hpp" +#include "seq/Sdobnov_V_mergesort_Betcher/include/ops_seq.hpp" + +TEST(Sdobnov_V_mergesort_Betcher_seq, test_pipeline_run) { + long unsigned int size = 4096; + std::vector res(size, 0); + std::vector input = Sdobnov_V_mergesort_Betcher_seq::generate_random_vector(size, 0, 1000); + + std::shared_ptr taskDataSeq = std::make_shared(); + + taskDataSeq->inputs_count.emplace_back(size); + taskDataSeq->inputs.emplace_back(reinterpret_cast(input.data())); + taskDataSeq->outputs_count.emplace_back(size); + taskDataSeq->outputs.emplace_back(reinterpret_cast(res.data())); + + auto test = std::make_shared(taskDataSeq); + ASSERT_EQ(test->validation(), true); + test->pre_processing(); + test->run(); + test->post_processing(); + + 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; + }; + auto perfResults = std::make_shared(); + auto perfAnalyzer = std::make_shared(test); + perfAnalyzer->pipeline_run(perfAttr, perfResults); + ppc::core::Perf::print_perf_statistic(perfResults); + ASSERT_EQ(res.size(), size); +} + +TEST(Sdobnov_V_mergesort_Betcher_seq, test_task_run) { + long unsigned int size = 4096; + std::vector res(size, 0); + std::vector input = Sdobnov_V_mergesort_Betcher_seq::generate_random_vector(size, 0, 1000); + + std::shared_ptr taskDataSeq = std::make_shared(); + + taskDataSeq->inputs_count.emplace_back(size); + taskDataSeq->inputs.emplace_back(reinterpret_cast(input.data())); + taskDataSeq->outputs_count.emplace_back(size); + taskDataSeq->outputs.emplace_back(reinterpret_cast(res.data())); + + auto test = std::make_shared(taskDataSeq); + ASSERT_EQ(test->validation(), true); + test->pre_processing(); + test->run(); + test->post_processing(); + + 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; + }; + auto perfResults = std::make_shared(); + auto perfAnalyzer = std::make_shared(test); + perfAnalyzer->task_run(perfAttr, perfResults); + ppc::core::Perf::print_perf_statistic(perfResults); + ASSERT_EQ(res.size(), size); +} \ No newline at end of file diff --git a/tasks/seq/Sdobnov_V_mergesort_Betcher/src/ops_seq.cpp b/tasks/seq/Sdobnov_V_mergesort_Betcher/src/ops_seq.cpp new file mode 100644 index 00000000000..9c85c614c24 --- /dev/null +++ b/tasks/seq/Sdobnov_V_mergesort_Betcher/src/ops_seq.cpp @@ -0,0 +1,68 @@ +// Copyright 2024 Sdobnov Vladimir +#include "seq/Sdobnov_V_mergesort_Betcher/include/ops_seq.hpp" + +#include +#include +#include +#include + +void Sdobnov_V_mergesort_Betcher_seq::sortPair(int& a, int& b) { + if (a > b) { + std::swap(a, b); + } +} + +void Sdobnov_V_mergesort_Betcher_seq::batchersort(std::vector& a, int l, int r) { + int N = r - l + 1; + for (int p = 1; p < N; p += p) + for (int k = p; k > 0; k /= 2) + for (int j = k % p; j + k < N; j += (k + k)) + for (int i = 0; i < N - j - k; i++) + if ((j + i) / (p + p) == (j + i + k) / (p + p)) sortPair(a[l + j + i], a[l + j + i + k]); +} + +std::vector Sdobnov_V_mergesort_Betcher_seq::generate_random_vector(int size, int lower_bound, int upper_bound) { + std::vector res(size); + for (int i = 0; i < size; i++) { + res[i] = lower_bound + rand() % (upper_bound - lower_bound + 1); + } + return res; +} + +bool Sdobnov_V_mergesort_Betcher_seq::MergesortBetcherSeq::pre_processing() { + internal_order_test(); + + size_ = taskData->inputs_count[0]; + res_.assign(size_, 0); + + auto* input = reinterpret_cast(taskData->inputs[0]); + + std::copy(input, input + size_, res_.begin()); + for (int i = 0; i < size_; i++) { + reinterpret_cast(taskData->outputs[0])[i] = res_[i]; + } + + return true; +} + +bool Sdobnov_V_mergesort_Betcher_seq::MergesortBetcherSeq::validation() { + internal_order_test(); + + return (taskData->inputs_count.size() == 1 && taskData->inputs_count[0] >= 0 && taskData->inputs.size() == 1 && + taskData->outputs_count.size() == 1 && taskData->outputs_count[0] >= 0 && taskData->outputs.size() == 1 && + taskData->inputs_count[0] > 0 && (taskData->inputs_count[0] & (taskData->inputs_count[0] - 1)) == 0); +} + +bool Sdobnov_V_mergesort_Betcher_seq::MergesortBetcherSeq::run() { + internal_order_test(); + batchersort(res_, 0, size_ - 1); + return true; +} + +bool Sdobnov_V_mergesort_Betcher_seq::MergesortBetcherSeq::post_processing() { + internal_order_test(); + for (int i = 0; i < size_; i++) { + reinterpret_cast(taskData->outputs[0])[i] = res_[i]; + } + return true; +}