diff --git a/tasks/mpi/sedova_o_vertical_ribbon_scheme/func_tests/main.cpp b/tasks/mpi/sedova_o_vertical_ribbon_scheme/func_tests/main.cpp new file mode 100644 index 00000000000..78c00254f5e --- /dev/null +++ b/tasks/mpi/sedova_o_vertical_ribbon_scheme/func_tests/main.cpp @@ -0,0 +1,209 @@ +#include + +#include +#include +#include +#include + +#include "mpi/sedova_o_vertical_ribbon_scheme/include/ops_mpi.hpp" + +TEST(sedova_o_vertical_ribbon_scheme_mpi, distribution1) { + int rows_ = 5; + int cols_ = 3; + int count_proc = 5; + std::vector proc_(count_proc, 0); + std::vector off(count_proc, 0); + if (count_proc > rows_) { + for (int i = 0; i < rows_; ++i) { + off[i] = i * cols_; + proc_[i] = cols_; + } + for (int i = rows_; i < count_proc; ++i) { + off[i] = -1; + proc_[i] = 0; + } + } else { + int count_proc_ = rows_ / count_proc; + int surplus = rows_ % count_proc; + int offset = 0; + for (int i = 0; i < count_proc; ++i) { + if (surplus > 0) { + proc_[i] = (count_proc_ + 1) * cols_; + --surplus; + } else { + proc_[i] = count_proc_ * cols_; + } + off[i] = offset; + offset += proc_[i]; + } + } + std::vector expected_proc = {3, 3, 3, 3, 3}; + std::vector expected_off = {0, 3, 6, 9, 12}; + EXPECT_EQ(proc_, expected_proc); + EXPECT_EQ(off, expected_off); +} + +TEST(sedova_o_vertical_ribbon_scheme_mpi, distribution2) { + int rows_ = 5; + int cols_ = 3; + int count_proc = 3; + std::vector proc_(count_proc, 0); + std::vector off(count_proc, 0); + if (count_proc > rows_) { + for (int i = 0; i < rows_; ++i) { + off[i] = i * cols_; + proc_[i] = cols_; + } + for (int i = rows_; i < count_proc; ++i) { + off[i] = -1; + proc_[i] = 0; + } + } else { + int count_proc_ = rows_ / count_proc; + int surplus = rows_ % count_proc; + int offset = 0; + for (int i = 0; i < count_proc; ++i) { + if (surplus > 0) { + proc_[i] = (count_proc_ + 1) * cols_; + --surplus; + } else { + proc_[i] = count_proc_ * cols_; + } + off[i] = offset; + offset += proc_[i]; + } + } + std::vector expected_proc = {6, 6, 3}; + std::vector expected_off = {0, 6, 12}; + EXPECT_EQ(proc_, expected_proc); + EXPECT_EQ(off, expected_off); +} + +TEST(sedova_o_vertical_ribbon_scheme_mpi, distribution3) { + int rows_ = 5; + int cols_ = 4; + int count_proc = 6; + std::vector proc_(count_proc, 0); + std::vector off(count_proc, 0); + if (count_proc > rows_) { + for (int i = 0; i < rows_; ++i) { + off[i] = i * cols_; + proc_[i] = cols_; + } + for (int i = rows_; i < count_proc; ++i) { + off[i] = -1; + proc_[i] = 0; + } + } else { + int count_proc_ = rows_ / count_proc; + int surplus = rows_ % count_proc; + int offset = 0; + for (int i = 0; i < count_proc; ++i) { + if (surplus > 0) { + proc_[i] = (count_proc_ + 1) * cols_; + --surplus; + } else { + proc_[i] = count_proc_ * cols_; + } + off[i] = offset; + offset += proc_[i]; + } + } + std::vector expected_proc = {4, 4, 4, 4, 4, 0}; + std::vector expected_off = {0, 4, 8, 12, 16, -1}; + EXPECT_EQ(proc_, expected_proc); + EXPECT_EQ(off, expected_off); +} + +TEST(sedova_o_vertical_ribbon_scheme_mpi, distribution4) { + int rows_ = 10; + int cols_ = 4; + int count_proc = 8; + std::vector proc_(count_proc, 0); + std::vector off(count_proc, 0); + if (count_proc > rows_) { + for (int i = 0; i < rows_; ++i) { + off[i] = i * cols_; + proc_[i] = cols_; + } + for (int i = rows_; i < count_proc; ++i) { + off[i] = -1; + proc_[i] = 0; + } + } else { + int count_proc_ = rows_ / count_proc; + int surplus = rows_ % count_proc; + int offset = 0; + for (int i = 0; i < count_proc; ++i) { + if (surplus > 0) { + proc_[i] = (count_proc_ + 1) * cols_; + --surplus; + } else { + proc_[i] = count_proc_ * cols_; + } + off[i] = offset; + offset += proc_[i]; + } + } + std::vector expected_proc = {8, 8, 4, 4, 4, 4, 4, 4}; + std::vector expected_off = {0, 8, 16, 20, 24, 28, 32, 36}; + EXPECT_EQ(proc_, expected_proc); + EXPECT_EQ(off, expected_off); +} + +TEST(sedova_o_vertical_ribbon_scheme_mpi, false_validation) { + std::vector matrix = {1, 2, 3}; + std::vector vector = {7, 8}; + std::vector result(3, 0); + + std::shared_ptr taskDataSeq = std::make_shared(); + taskDataSeq->inputs.emplace_back(reinterpret_cast(matrix.data())); + taskDataSeq->inputs_count.emplace_back(matrix.size()); + taskDataSeq->inputs.emplace_back(reinterpret_cast(vector.data())); + taskDataSeq->inputs_count.emplace_back(vector.size()); + taskDataSeq->outputs.emplace_back(reinterpret_cast(result.data())); + taskDataSeq->outputs_count.emplace_back(result.size()); + + sedova_o_vertical_ribbon_scheme_mpi::SequentialMPI TestSequential(taskDataSeq); + EXPECT_FALSE(TestSequential.validation()); +} + +TEST(sedova_o_vertical_ribbon_scheme_mpi, true_validation) { + std::vector matrix = {1, 2, 3, 4}; + std::vector vector = {7, 8}; + std::vector result(2, 0); + + std::shared_ptr taskDataPar = std::make_shared(); + taskDataPar->inputs.emplace_back(reinterpret_cast(matrix.data())); + taskDataPar->inputs_count.emplace_back(matrix.size()); + taskDataPar->inputs.emplace_back(reinterpret_cast(vector.data())); + taskDataPar->inputs_count.emplace_back(vector.size()); + taskDataPar->outputs.emplace_back(reinterpret_cast(result.data())); + taskDataPar->outputs_count.emplace_back(result.size()); + + sedova_o_vertical_ribbon_scheme_mpi::ParallelMPI taskParallel(taskDataPar); + EXPECT_TRUE(taskParallel.validation()); +} + +TEST(sedova_o_vertical_ribbon_scheme_mpi, correct_matrix_and_vector_seq) { + std::vector matrix = {1, 2, 3, 4, 5, 6}; + std::vector vector = {7, 8}; + std::vector result(3, 0); + + std::shared_ptr taskDataSeq = std::make_shared(); + taskDataSeq->inputs.emplace_back(reinterpret_cast(matrix.data())); + taskDataSeq->inputs_count.emplace_back(matrix.size()); + taskDataSeq->inputs.emplace_back(reinterpret_cast(vector.data())); + taskDataSeq->inputs_count.emplace_back(vector.size()); + taskDataSeq->outputs.emplace_back(reinterpret_cast(result.data())); + taskDataSeq->outputs_count.emplace_back(result.size()); + + sedova_o_vertical_ribbon_scheme_mpi::SequentialMPI TestSequential(taskDataSeq); + ASSERT_TRUE(TestSequential.validation()); + TestSequential.pre_processing(); + TestSequential.run(); + TestSequential.post_processing(); + + std::vector expected_result = {39, 54, 69}; + ASSERT_EQ(result, expected_result); +} \ No newline at end of file diff --git a/tasks/mpi/sedova_o_vertical_ribbon_scheme/include/ops_mpi.hpp b/tasks/mpi/sedova_o_vertical_ribbon_scheme/include/ops_mpi.hpp new file mode 100644 index 00000000000..61ca193f70c --- /dev/null +++ b/tasks/mpi/sedova_o_vertical_ribbon_scheme/include/ops_mpi.hpp @@ -0,0 +1,52 @@ +// Copyright 2024 Sedova Olga +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "core/task/include/task.hpp" + +namespace sedova_o_vertical_ribbon_scheme_mpi { + +class ParallelMPI : public ppc::core::Task { + public: + explicit ParallelMPI(std::shared_ptr taskData_) : Task(std::move(taskData_)) {} + bool pre_processing() override; + bool validation() override; + bool run() override; + bool post_processing() override; + + private: + int rows_{}; + int cols_{}; + std::vector input_matrix_1; + std::vector input_vector_1; + std::vector result_vector_; + std::vector proc; + std::vector off; + boost::mpi::communicator world; +}; + +class SequentialMPI : public ppc::core::Task { + public: + explicit SequentialMPI(std::shared_ptr taskData_) : Task(std::move(taskData_)) {} + bool pre_processing() override; + bool validation() override; + bool run() override; + bool post_processing() override; + + private: + int* matrix_; + int* vector_; + std::vector result_vector_; + int rows_; + int cols_; +}; +} // namespace sedova_o_vertical_ribbon_scheme_mpi \ No newline at end of file diff --git a/tasks/mpi/sedova_o_vertical_ribbon_scheme/perf_tests/main.cpp b/tasks/mpi/sedova_o_vertical_ribbon_scheme/perf_tests/main.cpp new file mode 100644 index 00000000000..761f174023e --- /dev/null +++ b/tasks/mpi/sedova_o_vertical_ribbon_scheme/perf_tests/main.cpp @@ -0,0 +1,130 @@ +#include + +#include +#include + +#include "core/perf/include/perf.hpp" +#include "mpi/sedova_o_vertical_ribbon_scheme/include/ops_mpi.hpp" + +TEST(sedova_o_vertical_ribbon_scheme_mpi, test_pipeline_run) { + boost::mpi::environment env; + boost::mpi::communicator world; + std::vector global_matrix; + std::vector global_vector; + std::vector global_result; + std::shared_ptr taskDataPar = std::make_shared(); + int rows_; + int cols_; + if (world.rank() == 0) { + rows_ = 2024; + cols_ = 2024; + global_vector.resize(cols_); + global_matrix.resize(rows_ * cols_); + for (int j = 0; j < rows_; ++j) { + for (int i = 0; i < cols_; ++i) { + global_matrix[j * cols_ + i] = (rand() % 101) - 50; + } + } + for (int i = 0; i < rows_; ++i) { + global_vector[i] = (rand() % 100) - 50; + } + global_result.resize(cols_, 0); + taskDataPar->inputs.emplace_back(reinterpret_cast(global_matrix.data())); + taskDataPar->inputs_count.emplace_back(global_matrix.size()); + taskDataPar->inputs.emplace_back(reinterpret_cast(global_vector.data())); + taskDataPar->inputs_count.emplace_back(global_vector.size()); + taskDataPar->outputs.emplace_back(reinterpret_cast(global_result.data())); + taskDataPar->outputs_count.emplace_back(global_result.size()); + } + auto taskParallel = std::make_shared(taskDataPar); + ASSERT_TRUE(taskParallel->validation()); + taskParallel->pre_processing(); + taskParallel->run(); + taskParallel->post_processing(); + auto perfAttr = std::make_shared(); + perfAttr->num_running = 10; + const boost::mpi::timer current_timer; + perfAttr->current_timer = [&] { return current_timer.elapsed(); }; + auto perfResults = std::make_shared(); + auto perfAnalyzer = std::make_shared(taskParallel); + perfAnalyzer->pipeline_run(perfAttr, perfResults); + if (world.rank() == 0) { + ppc::core::Perf::print_perf_statistic(perfResults); + std::vector seq_result(global_result.size(), 0); + auto taskDataSeq = std::make_shared(); + taskDataSeq->inputs.emplace_back(reinterpret_cast(global_matrix.data())); + taskDataSeq->inputs_count.emplace_back(global_matrix.size()); + taskDataSeq->inputs.emplace_back(reinterpret_cast(global_vector.data())); + taskDataSeq->inputs_count.emplace_back(global_vector.size()); + taskDataSeq->outputs.emplace_back(reinterpret_cast(seq_result.data())); + taskDataSeq->outputs_count.emplace_back(seq_result.size()); + auto taskSequential = std::make_shared(taskDataSeq); + ASSERT_TRUE(taskSequential->validation()); + taskSequential->pre_processing(); + taskSequential->run(); + taskSequential->post_processing(); + ASSERT_EQ(global_result.size(), seq_result.size()); + EXPECT_EQ(global_result, seq_result); + } +} +TEST(sedova_o_vertical_ribbon_scheme_mpi, test_task_run) { + boost::mpi::environment env; + boost::mpi::communicator world; + std::vector global_matrix; + std::vector global_vector; + std::vector global_result; + std::shared_ptr taskDataPar = std::make_shared(); + int rows_; + int cols_; + if (world.rank() == 0) { + rows_ = 2000; + cols_ = 2000; + global_matrix.resize(rows_ * cols_); + global_vector.resize(cols_); + for (int j = 0; j < rows_; ++j) { + for (int i = 0; i < cols_; ++i) { + global_matrix[j * cols_ + i] = (rand() % 101) - 50; + } + } + for (int i = 0; i < rows_; ++i) { + global_vector[i] = (rand() % 100) - 50; + } + global_result.resize(cols_, 0); + taskDataPar->inputs.emplace_back(reinterpret_cast(global_matrix.data())); + taskDataPar->inputs_count.emplace_back(global_matrix.size()); + taskDataPar->inputs.emplace_back(reinterpret_cast(global_vector.data())); + taskDataPar->inputs_count.emplace_back(global_vector.size()); + taskDataPar->outputs.emplace_back(reinterpret_cast(global_result.data())); + taskDataPar->outputs_count.emplace_back(global_result.size()); + } + auto taskParallel = std::make_shared(taskDataPar); + ASSERT_TRUE(taskParallel->validation()); + taskParallel->pre_processing(); + taskParallel->run(); + taskParallel->post_processing(); + auto perfAttr = std::make_shared(); + perfAttr->num_running = 10; + const boost::mpi::timer current_timer; + perfAttr->current_timer = [&] { return current_timer.elapsed(); }; + auto perfResults = std::make_shared(); + auto perfAnalyzer = std::make_shared(taskParallel); + perfAnalyzer->task_run(perfAttr, perfResults); + if (world.rank() == 0) { + ppc::core::Perf::print_perf_statistic(perfResults); + std::vector seq_result(global_result.size(), 0); + auto taskDataSeq = std::make_shared(); + taskDataSeq->inputs.emplace_back(reinterpret_cast(global_matrix.data())); + taskDataSeq->inputs_count.emplace_back(global_matrix.size()); + taskDataSeq->inputs.emplace_back(reinterpret_cast(global_vector.data())); + taskDataSeq->inputs_count.emplace_back(global_vector.size()); + taskDataSeq->outputs.emplace_back(reinterpret_cast(seq_result.data())); + taskDataSeq->outputs_count.emplace_back(seq_result.size()); + auto taskSequential = std::make_shared(taskDataSeq); + ASSERT_TRUE(taskSequential->validation()); + taskSequential->pre_processing(); + taskSequential->run(); + taskSequential->post_processing(); + ASSERT_EQ(global_result.size(), seq_result.size()); + EXPECT_EQ(global_result, seq_result); + } +} \ No newline at end of file diff --git a/tasks/mpi/sedova_o_vertical_ribbon_scheme/src/ops_mpi.cpp b/tasks/mpi/sedova_o_vertical_ribbon_scheme/src/ops_mpi.cpp new file mode 100644 index 00000000000..330231f170b --- /dev/null +++ b/tasks/mpi/sedova_o_vertical_ribbon_scheme/src/ops_mpi.cpp @@ -0,0 +1,136 @@ +#include "mpi/sedova_o_vertical_ribbon_scheme/include/ops_mpi.hpp" + +#include +#include +#include +#include +#include +#include + +bool sedova_o_vertical_ribbon_scheme_mpi::SequentialMPI::validation() { + internal_order_test(); + return taskData->inputs_count[0] > 1 && taskData->inputs_count[1] > 0 && + taskData->inputs_count[0] % taskData->inputs_count[1] == 0 && + taskData->outputs_count[0] == taskData->inputs_count[0] / taskData->inputs_count[1]; +} + +bool sedova_o_vertical_ribbon_scheme_mpi::SequentialMPI::pre_processing() { + internal_order_test(); + matrix_ = reinterpret_cast(taskData->inputs[0]); + vector_ = reinterpret_cast(taskData->inputs[1]); + int count = taskData->inputs_count[0]; + rows_ = taskData->inputs_count[1]; + cols_ = count / rows_; + result_vector_.assign(cols_, 0); + return true; +} + +bool sedova_o_vertical_ribbon_scheme_mpi::SequentialMPI::run() { + internal_order_test(); + for (int i = 0; i < rows_; ++i) { + for (int j = 0; j < cols_; ++j) { + result_vector_[j] += matrix_[i * cols_ + j] * vector_[i]; + } + } + return true; +} + +bool sedova_o_vertical_ribbon_scheme_mpi::SequentialMPI::post_processing() { + internal_order_test(); + + int* output_data = reinterpret_cast(taskData->outputs[0]); + std::copy(result_vector_.begin(), result_vector_.end(), output_data); + + return true; +} + +bool sedova_o_vertical_ribbon_scheme_mpi::ParallelMPI::validation() { + internal_order_test(); + return taskData->inputs_count[0] > 0 && taskData->inputs_count[1] > 0 && + taskData->inputs_count[0] % taskData->inputs_count[1] == 0 && + taskData->outputs_count[0] == taskData->inputs_count[0] / taskData->inputs_count[1]; +} + +bool sedova_o_vertical_ribbon_scheme_mpi::ParallelMPI::pre_processing() { + internal_order_test(); + + if (world.rank() == 0) { + if (!taskData || taskData->inputs[0] == nullptr || taskData->inputs[1] == nullptr || + taskData->outputs[0] == nullptr) { + return false; + } + + int* input_A = reinterpret_cast(taskData->inputs[0]); + int* input_B = reinterpret_cast(taskData->inputs[1]); + + int count = taskData->inputs_count[0]; + rows_ = taskData->inputs_count[1]; + cols_ = count / rows_; + + input_matrix_1.assign(input_A, input_A + count); + input_vector_1.assign(input_B, input_B + rows_); + result_vector_.resize(cols_, 0); + + proc.resize(world.size(), 0); + off.resize(world.size(), -1); + + if (world.size() > rows_) { + for (int i = 0; i < rows_; ++i) { + proc[i] = cols_; + off[i] = i * cols_; + } + } else { + int count_proc = rows_ / world.size(); + int surplus = rows_ % world.size(); + + int offset = 0; + for (int i = 0; i < world.size(); ++i) { + if (surplus > 0) { + proc[i] = (count_proc + 1) * cols_; + --surplus; + } else { + proc[i] = count_proc * cols_; + } + off[i] = offset; + offset += proc[i]; + } + } + } + + return true; +} + +bool sedova_o_vertical_ribbon_scheme_mpi::ParallelMPI::run() { + internal_order_test(); + boost::mpi::broadcast(world, rows_, 0); + boost::mpi::broadcast(world, cols_, 0); + boost::mpi::broadcast(world, proc, 0); + boost::mpi::broadcast(world, off, 0); + boost::mpi::broadcast(world, input_matrix_1, 0); + boost::mpi::broadcast(world, input_vector_1, 0); + int proc_start = off[world.rank()] / cols_; + int matrix_start_ = proc[world.rank()] / cols_; + std::vector proc_result(cols_, 0); + + for (int i = 0; i < matrix_start_; ++i) { + for (int j = 0; j < cols_; ++j) { + int prog_start = proc_start + i; + int matr = input_matrix_1[cols_ * prog_start + j]; + int vec = input_vector_1[prog_start]; + proc_result[j] += matr * vec; + } + } + + boost::mpi::reduce(world, proc_result.data(), cols_, result_vector_.data(), std::plus<>(), 0); + + return true; +} + +bool sedova_o_vertical_ribbon_scheme_mpi::ParallelMPI::post_processing() { + internal_order_test(); + if (world.rank() == 0) { + int* answer = reinterpret_cast(taskData->outputs[0]); + std::copy(result_vector_.begin(), result_vector_.end(), answer); + } + return true; +} \ No newline at end of file diff --git a/tasks/seq/sedova_o_vertical_ribbon_scheme/func_tests/main.cpp b/tasks/seq/sedova_o_vertical_ribbon_scheme/func_tests/main.cpp new file mode 100644 index 00000000000..fbfd14218fc --- /dev/null +++ b/tasks/seq/sedova_o_vertical_ribbon_scheme/func_tests/main.cpp @@ -0,0 +1,183 @@ +#include + +#include +#include + +#include "seq/sedova_o_vertical_ribbon_scheme/include/ops_seq.hpp" + +TEST(sedova_o_vertical_ribbon_scheme_seq, empty_matrix) { + std::vector matrix = {}; + std::vector vector = {1, 2, 3}; + std::vector result(3, 0); + + std::shared_ptr taskDataSeq = std::make_shared(); + taskDataSeq->inputs.emplace_back(reinterpret_cast(matrix.data())); + taskDataSeq->inputs_count.emplace_back(matrix.size()); + taskDataSeq->inputs.emplace_back(reinterpret_cast(vector.data())); + taskDataSeq->inputs_count.emplace_back(vector.size()); + taskDataSeq->outputs.emplace_back(reinterpret_cast(result.data())); + taskDataSeq->outputs_count.emplace_back(result.size()); + + sedova_o_vertical_ribbon_scheme_seq::Sequential TestSequential(taskDataSeq); + EXPECT_FALSE(TestSequential.validation()); +} + +TEST(sedova_o_vertical_ribbon_scheme_seq, empty_vector) { + std::vector matrix = {1, 2, 4, 5}; + std::vector vector = {}; + std::vector result(2, 0); + + std::shared_ptr taskDataSeq = std::make_shared(); + taskDataSeq->inputs.emplace_back(reinterpret_cast(matrix.data())); + taskDataSeq->inputs_count.emplace_back(matrix.size()); + taskDataSeq->inputs.emplace_back(reinterpret_cast(vector.data())); + taskDataSeq->inputs_count.emplace_back(vector.size()); + taskDataSeq->outputs.emplace_back(reinterpret_cast(result.data())); + taskDataSeq->outputs_count.emplace_back(result.size()); + + sedova_o_vertical_ribbon_scheme_seq::Sequential TestSequential(taskDataSeq); + EXPECT_FALSE(TestSequential.validation()); +} + +TEST(sedova_o_vertical_ribbon_scheme_seq, empty_matrix_and_vector) { + std::vector matrix = {}; + std::vector vector = {}; + std::vector result; + + std::shared_ptr taskDataSeq = std::make_shared(); + taskDataSeq->inputs.emplace_back(reinterpret_cast(matrix.data())); + taskDataSeq->inputs_count.emplace_back(matrix.size()); + taskDataSeq->inputs.emplace_back(reinterpret_cast(vector.data())); + taskDataSeq->inputs_count.emplace_back(vector.size()); + taskDataSeq->outputs.emplace_back(reinterpret_cast(result.data())); + taskDataSeq->outputs_count.emplace_back(result.size()); + + sedova_o_vertical_ribbon_scheme_seq::Sequential TestSequential(taskDataSeq); + EXPECT_FALSE(TestSequential.validation()); +} + +TEST(sedova_o_vertical_ribbon_scheme_seq, matrix_3x2) { + std::vector matrix = {1, 2, 3, 4, 5, 6}; + std::vector vector = {7, 8}; + std::vector result(3, 0); + + std::shared_ptr taskDataSeq = std::make_shared(); + taskDataSeq->inputs.emplace_back(reinterpret_cast(matrix.data())); + taskDataSeq->inputs_count.emplace_back(matrix.size()); + taskDataSeq->inputs.emplace_back(reinterpret_cast(vector.data())); + taskDataSeq->inputs_count.emplace_back(vector.size()); + taskDataSeq->outputs.emplace_back(reinterpret_cast(result.data())); + taskDataSeq->outputs_count.emplace_back(result.size()); + + sedova_o_vertical_ribbon_scheme_seq::Sequential TestSequential(taskDataSeq); + ASSERT_TRUE(TestSequential.validation()); + TestSequential.pre_processing(); + TestSequential.run(); + TestSequential.post_processing(); + + std::vector expected_result = {39, 54, 69}; + ASSERT_EQ(result, expected_result); +} + +TEST(sedova_o_vertical_ribbon_scheme_seq, matrix_2x2) { + std::vector matrix = {1, 2, 3, 4}; + std::vector vector = {5, 6}; + std::vector result(2, 0); + + std::shared_ptr taskDataSeq = std::make_shared(); + taskDataSeq->inputs.emplace_back(reinterpret_cast(matrix.data())); + taskDataSeq->inputs_count.emplace_back(matrix.size()); + taskDataSeq->inputs.emplace_back(reinterpret_cast(vector.data())); + taskDataSeq->inputs_count.emplace_back(vector.size()); + taskDataSeq->outputs.emplace_back(reinterpret_cast(result.data())); + taskDataSeq->outputs_count.emplace_back(result.size()); + + sedova_o_vertical_ribbon_scheme_seq::Sequential TestSequential(taskDataSeq); + ASSERT_TRUE(TestSequential.validation()); + TestSequential.pre_processing(); + TestSequential.run(); + TestSequential.post_processing(); + + std::vector expected_result = {23, 34}; + ASSERT_EQ(result, expected_result); +} + +TEST(sedova_o_vertical_ribbon_scheme_seq, matrix_5x2) { + std::vector matrix = {1, 3, 5, 4, 6, 7, 8, 2, 9, 10}; + std::vector vector = {2, 6}; + std::vector result(5, 0); + + std::shared_ptr taskDataSeq = std::make_shared(); + taskDataSeq->inputs.emplace_back(reinterpret_cast(matrix.data())); + taskDataSeq->inputs_count.emplace_back(matrix.size()); + taskDataSeq->inputs.emplace_back(reinterpret_cast(vector.data())); + taskDataSeq->inputs_count.emplace_back(vector.size()); + taskDataSeq->outputs.emplace_back(reinterpret_cast(result.data())); + taskDataSeq->outputs_count.emplace_back(result.size()); + + sedova_o_vertical_ribbon_scheme_seq::Sequential TestSequential(taskDataSeq); + ASSERT_TRUE(TestSequential.validation()); + TestSequential.pre_processing(); + TestSequential.run(); + TestSequential.post_processing(); + + std::vector expected_result = {44, 54, 22, 62, 72}; + ASSERT_EQ(result, expected_result); +} + +TEST(sedova_o_vertical_ribbon_scheme_seq, matrix_5x1) { + std::vector matrix = {1, 3, 5, 4, 6}; + std::vector vector = {2}; + std::vector result(5, 0); + + std::shared_ptr taskDataSeq = std::make_shared(); + taskDataSeq->inputs.emplace_back(reinterpret_cast(matrix.data())); + taskDataSeq->inputs_count.emplace_back(matrix.size()); + taskDataSeq->inputs.emplace_back(reinterpret_cast(vector.data())); + taskDataSeq->inputs_count.emplace_back(vector.size()); + taskDataSeq->outputs.emplace_back(reinterpret_cast(result.data())); + taskDataSeq->outputs_count.emplace_back(result.size()); + + sedova_o_vertical_ribbon_scheme_seq::Sequential TestSequential(taskDataSeq); + ASSERT_TRUE(TestSequential.validation()); + TestSequential.pre_processing(); + TestSequential.run(); + TestSequential.post_processing(); + + std::vector expected_result = {2, 6, 10, 8, 12}; + ASSERT_EQ(result, expected_result); +} + +TEST(sedova_o_vertical_ribbon_scheme_seq, false_validation1) { + std::vector matrix = {1, 2, 3, 4}; + std::vector vector = {1, 2, 3}; + std::vector result(3, 0); + + std::shared_ptr taskDataSeq = std::make_shared(); + taskDataSeq->inputs.emplace_back(reinterpret_cast(matrix.data())); + taskDataSeq->inputs_count.emplace_back(matrix.size()); + taskDataSeq->inputs.emplace_back(reinterpret_cast(vector.data())); + taskDataSeq->inputs_count.emplace_back(vector.size()); + taskDataSeq->outputs.emplace_back(reinterpret_cast(result.data())); + taskDataSeq->outputs_count.emplace_back(result.size()); + + sedova_o_vertical_ribbon_scheme_seq::Sequential TestSequential(taskDataSeq); + EXPECT_FALSE(TestSequential.validation()); +} + +TEST(sedova_o_vertical_ribbon_scheme_seq, false_validation2) { + std::vector matrix = {1, 2, 3}; + std::vector vector = {1, 2}; + std::vector result(3, 0); + + std::shared_ptr taskDataSeq = std::make_shared(); + taskDataSeq->inputs.emplace_back(reinterpret_cast(matrix.data())); + taskDataSeq->inputs_count.emplace_back(matrix.size()); + taskDataSeq->inputs.emplace_back(reinterpret_cast(vector.data())); + taskDataSeq->inputs_count.emplace_back(vector.size()); + taskDataSeq->outputs.emplace_back(reinterpret_cast(result.data())); + taskDataSeq->outputs_count.emplace_back(result.size()); + + sedova_o_vertical_ribbon_scheme_seq::Sequential TestSequential(taskDataSeq); + EXPECT_FALSE(TestSequential.validation()); +} \ No newline at end of file diff --git a/tasks/seq/sedova_o_vertical_ribbon_scheme/include/ops_seq.hpp b/tasks/seq/sedova_o_vertical_ribbon_scheme/include/ops_seq.hpp new file mode 100644 index 00000000000..a818cb6efce --- /dev/null +++ b/tasks/seq/sedova_o_vertical_ribbon_scheme/include/ops_seq.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include + +#include +#include +#include +#include + +#include "core/task/include/task.hpp" + +namespace sedova_o_vertical_ribbon_scheme_seq { + +class Sequential : public ppc::core::Task { + public: + explicit Sequential(std::shared_ptr taskData_) : Task(std::move(taskData_)) {} + bool pre_processing() override; + bool validation() override; + bool run() override; + bool post_processing() override; + + private: + int* matrix_; + int* vector_; + std::vector> input_matrix_; + std::vector input_vector_; + std::vector result_vector_; + int count; + int rows_; + int cols_; +}; + +} // namespace sedova_o_vertical_ribbon_scheme_seq \ No newline at end of file diff --git a/tasks/seq/sedova_o_vertical_ribbon_scheme/perf_tests/main.cpp b/tasks/seq/sedova_o_vertical_ribbon_scheme/perf_tests/main.cpp new file mode 100644 index 00000000000..2abc23eeadf --- /dev/null +++ b/tasks/seq/sedova_o_vertical_ribbon_scheme/perf_tests/main.cpp @@ -0,0 +1,126 @@ +#include + +#include +#include + +#include "core/perf/include/perf.hpp" +#include "seq/sedova_o_vertical_ribbon_scheme/include/ops_seq.hpp" + +TEST(sedova_o_vertical_ribbon_scheme_seq, test_pipeline_run) { + int rows_ = 2000; + int cols_ = 2000; + std::vector input_matrix_(rows_ * cols_); + std::vector input_vector_(cols_); + std::vector result_vector_(rows_, 0); + + for (int cols = 0; cols < cols_; ++cols) { + for (int rows = 0; rows < rows_; ++rows) { + input_matrix_[rows + cols * rows_] = (rows + cols * rows_) % 100; + } + } + for (int i = 0; i < cols_; ++i) { + input_vector_[i] = i % 50; + } + + auto taskDataSeq = std::make_shared(); + taskDataSeq->inputs.emplace_back(reinterpret_cast(input_matrix_.data())); + taskDataSeq->inputs_count.emplace_back(input_matrix_.size()); + + taskDataSeq->inputs.emplace_back(reinterpret_cast(input_vector_.data())); + taskDataSeq->inputs_count.emplace_back(input_vector_.size()); + + taskDataSeq->outputs.emplace_back(reinterpret_cast(result_vector_.data())); + taskDataSeq->outputs_count.emplace_back(result_vector_.size()); + + auto taskSequential = std::make_shared(taskDataSeq); + ASSERT_TRUE(taskSequential->validation()); + taskSequential->pre_processing(); + taskSequential->run(); + taskSequential->post_processing(); + + auto perfAttr = std::make_shared(); + perfAttr->num_running = 10; + auto start_time = std::chrono::high_resolution_clock::now(); + perfAttr->current_timer = [&start_time] { + auto now = std::chrono::high_resolution_clock::now(); + std::chrono::duration elapsed = now - start_time; + return elapsed.count(); + }; + + auto perfResults = std::make_shared(); + + auto perfAnalyzer = std::make_shared(taskSequential); + perfAnalyzer->pipeline_run(perfAttr, perfResults); + + ppc::core::Perf::print_perf_statistic(perfResults); + + std::vector expected_result(rows_, 0); + for (int i = 0; i < rows_; ++i) { + int sum = 0; + for (int j = 0; j < cols_; ++j) { + sum += input_matrix_[i + j * rows_] * input_vector_[j]; + } + expected_result[i] = sum; + } + + ASSERT_EQ(result_vector_, expected_result); +} + +TEST(sedova_o_vertical_ribbon_scheme_seq, test_task_run) { + int rows_ = 2000; + int cols_ = 2000; + std::vector input_matrix_(rows_ * cols_); + std::vector input_vector_(cols_); + std::vector result_vector_(rows_, 0); + + for (int cols = 0; cols < cols_; ++cols) { + for (int rows = 0; rows < rows_; ++rows) { + input_matrix_[rows + cols * rows_] = (rows + cols * rows_) % 100; + } + } + for (int i = 0; i < cols_; ++i) { + input_vector_[i] = i % 50; + } + + auto taskDataSeq = std::make_shared(); + taskDataSeq->inputs.emplace_back(reinterpret_cast(input_matrix_.data())); + taskDataSeq->inputs_count.emplace_back(input_matrix_.size()); + + taskDataSeq->inputs.emplace_back(reinterpret_cast(input_vector_.data())); + taskDataSeq->inputs_count.emplace_back(input_vector_.size()); + + taskDataSeq->outputs.emplace_back(reinterpret_cast(result_vector_.data())); + taskDataSeq->outputs_count.emplace_back(result_vector_.size()); + + auto taskSequential = std::make_shared(taskDataSeq); + ASSERT_TRUE(taskSequential->validation()); + taskSequential->pre_processing(); + taskSequential->run(); + taskSequential->post_processing(); + + auto perfAttr = std::make_shared(); + perfAttr->num_running = 10; + auto start_time = std::chrono::high_resolution_clock::now(); + perfAttr->current_timer = [&start_time] { + auto now = std::chrono::high_resolution_clock::now(); + std::chrono::duration elapsed = now - start_time; + return elapsed.count(); + }; + + auto perfResults = std::make_shared(); + + auto perfAnalyzer = std::make_shared(taskSequential); + perfAnalyzer->task_run(perfAttr, perfResults); + + ppc::core::Perf::print_perf_statistic(perfResults); + + std::vector expected_result(rows_, 0); + for (int i = 0; i < rows_; ++i) { + int sum = 0; + for (int j = 0; j < cols_; ++j) { + sum += input_matrix_[i + j * rows_] * input_vector_[j]; + } + expected_result[i] = sum; + } + ASSERT_EQ(result_vector_, expected_result); +} \ No newline at end of file diff --git a/tasks/seq/sedova_o_vertical_ribbon_scheme/src/ops_seq.cpp b/tasks/seq/sedova_o_vertical_ribbon_scheme/src/ops_seq.cpp new file mode 100644 index 00000000000..6a0647bb5e1 --- /dev/null +++ b/tasks/seq/sedova_o_vertical_ribbon_scheme/src/ops_seq.cpp @@ -0,0 +1,53 @@ +#include "seq/sedova_o_vertical_ribbon_scheme/include/ops_seq.hpp" + +#include +#include +#include +#include + +bool sedova_o_vertical_ribbon_scheme_seq::Sequential::validation() { + internal_order_test(); + if (!taskData) { + return false; + } + if (taskData->inputs[0] == nullptr || taskData->inputs[1] == nullptr) { + return false; + } + return taskData->inputs_count[0] > 0 && taskData->inputs_count[1] > 0 && + taskData->inputs_count[0] % taskData->inputs_count[1] == 0 && + taskData->outputs_count[0] == taskData->inputs_count[0] / taskData->inputs_count[1]; +} + +bool sedova_o_vertical_ribbon_scheme_seq::Sequential::pre_processing() { + internal_order_test(); + + matrix_ = reinterpret_cast(taskData->inputs[0]); + count = taskData->inputs_count[0]; + vector_ = reinterpret_cast(taskData->inputs[1]); + cols_ = taskData->inputs_count[1]; + rows_ = count / cols_; + input_vector_.assign(vector_, vector_ + cols_); + result_vector_.assign(rows_, 0); + + return true; +} + +bool sedova_o_vertical_ribbon_scheme_seq::Sequential::run() { + internal_order_test(); + + for (int j = 0; j < cols_; ++j) { + for (int i = 0; i < rows_; ++i) { + result_vector_[i] += matrix_[i + j * rows_] * input_vector_[j]; + } + } + return true; +} + +bool sedova_o_vertical_ribbon_scheme_seq::Sequential::post_processing() { + internal_order_test(); + + int* output_data = reinterpret_cast(taskData->outputs[0]); + std::copy(result_vector_.begin(), result_vector_.end(), output_data); + + return true; +} \ No newline at end of file