From 6472c7ebcfd3b9277ea320545654e2cfbe71c9f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BA=D0=B8=D0=BC=D0=BE=D0=B2=20=D0=98=D0=BB=D1=8C?= =?UTF-8?q?=D1=8F?= Date: Mon, 27 Oct 2025 20:42:37 +0300 Subject: [PATCH 1/5] Add test task --- .../common/include/common.hpp | 15 ++++ .../akimov_i_words_string_count/data/pic.jpg | Bin 0 -> 15356 bytes tasks/akimov_i_words_string_count/info.json | 9 ++ .../mpi/include/ops_mpi.hpp | 22 +++++ .../mpi/src/ops_mpi.cpp | 72 +++++++++++++++ tasks/akimov_i_words_string_count/report.md | 0 .../seq/include/ops_seq.hpp | 22 +++++ .../seq/src/ops_seq.cpp | 60 +++++++++++++ .../akimov_i_words_string_count/settings.json | 7 ++ .../tests/.clang-tidy | 13 +++ .../tests/functional/main.cpp | 85 ++++++++++++++++++ .../tests/performance/main.cpp | 40 +++++++++ 12 files changed, 345 insertions(+) create mode 100644 tasks/akimov_i_words_string_count/common/include/common.hpp create mode 100644 tasks/akimov_i_words_string_count/data/pic.jpg create mode 100644 tasks/akimov_i_words_string_count/info.json create mode 100644 tasks/akimov_i_words_string_count/mpi/include/ops_mpi.hpp create mode 100644 tasks/akimov_i_words_string_count/mpi/src/ops_mpi.cpp create mode 100644 tasks/akimov_i_words_string_count/report.md create mode 100644 tasks/akimov_i_words_string_count/seq/include/ops_seq.hpp create mode 100644 tasks/akimov_i_words_string_count/seq/src/ops_seq.cpp create mode 100644 tasks/akimov_i_words_string_count/settings.json create mode 100644 tasks/akimov_i_words_string_count/tests/.clang-tidy create mode 100644 tasks/akimov_i_words_string_count/tests/functional/main.cpp create mode 100644 tasks/akimov_i_words_string_count/tests/performance/main.cpp diff --git a/tasks/akimov_i_words_string_count/common/include/common.hpp b/tasks/akimov_i_words_string_count/common/include/common.hpp new file mode 100644 index 0000000000..6ef653eeba --- /dev/null +++ b/tasks/akimov_i_words_string_count/common/include/common.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include +#include + +#include "task/include/task.hpp" + +namespace akimov_i_words_string_count { + +using InType = int; +using OutType = int; +using TestType = std::tuple; +using BaseTask = ppc::task::Task; + +} // namespace akimov_i_words_string_count diff --git a/tasks/akimov_i_words_string_count/data/pic.jpg b/tasks/akimov_i_words_string_count/data/pic.jpg new file mode 100644 index 0000000000000000000000000000000000000000..34458023494a39d66880a98aa5dcad18eb14b249 GIT binary patch literal 15356 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 + +#include +#include + +#include "akimov_i_words_string_count/common/include/common.hpp" +#include "util/include/util.hpp" + +namespace akimov_i_words_string_count { + +AkimovIWordsStringCountMPI::AkimovIWordsStringCountMPI(const InType &in) { + SetTypeOfTask(GetStaticTypeOfTask()); + GetInput() = in; + GetOutput() = 0; +} + +bool AkimovIWordsStringCountMPI::ValidationImpl() { + return (GetInput() > 0) && (GetOutput() == 0); +} + +bool AkimovIWordsStringCountMPI::PreProcessingImpl() { + GetOutput() = 2 * GetInput(); + return GetOutput() > 0; +} + +bool AkimovIWordsStringCountMPI::RunImpl() { + auto input = GetInput(); + if (input == 0) { + return false; + } + + for (InType i = 0; i < GetInput(); i++) { + for (InType j = 0; j < GetInput(); j++) { + for (InType k = 0; k < GetInput(); k++) { + std::vector tmp(i + j + k, 1); + GetOutput() += std::accumulate(tmp.begin(), tmp.end(), 0); + GetOutput() -= i + j + k; + } + } + } + + const int num_threads = ppc::util::GetNumThreads(); + GetOutput() *= num_threads; + + int rank = 0; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + if (rank == 0) { + GetOutput() /= num_threads; + } else { + int counter = 0; + for (int i = 0; i < num_threads; i++) { + counter++; + } + + if (counter != 0) { + GetOutput() /= counter; + } + } + + MPI_Barrier(MPI_COMM_WORLD); + return GetOutput() > 0; +} + +bool AkimovIWordsStringCountMPI::PostProcessingImpl() { + GetOutput() -= GetInput(); + return GetOutput() > 0; +} + +} // namespace akimov_i_words_string_count diff --git a/tasks/akimov_i_words_string_count/report.md b/tasks/akimov_i_words_string_count/report.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tasks/akimov_i_words_string_count/seq/include/ops_seq.hpp b/tasks/akimov_i_words_string_count/seq/include/ops_seq.hpp new file mode 100644 index 0000000000..a35bca6e0f --- /dev/null +++ b/tasks/akimov_i_words_string_count/seq/include/ops_seq.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include "akimov_i_words_string_count/common/include/common.hpp" +#include "task/include/task.hpp" + +namespace akimov_i_words_string_count { + +class AkimovIWordsStringCountSEQ : public BaseTask { + public: + static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() { + return ppc::task::TypeOfTask::kSEQ; + } + explicit AkimovIWordsStringCountSEQ(const InType &in); + + private: + bool ValidationImpl() override; + bool PreProcessingImpl() override; + bool RunImpl() override; + bool PostProcessingImpl() override; +}; + +} // namespace akimov_i_words_string_count diff --git a/tasks/akimov_i_words_string_count/seq/src/ops_seq.cpp b/tasks/akimov_i_words_string_count/seq/src/ops_seq.cpp new file mode 100644 index 0000000000..0cd218b5e5 --- /dev/null +++ b/tasks/akimov_i_words_string_count/seq/src/ops_seq.cpp @@ -0,0 +1,60 @@ +#include "akimov_i_words_string_count/seq/include/ops_seq.hpp" + +#include +#include + +#include "akimov_i_words_string_count/common/include/common.hpp" +#include "util/include/util.hpp" + +namespace akimov_i_words_string_count { + +AkimovIWordsStringCountSEQ::AkimovIWordsStringCountSEQ(const InType &in) { + SetTypeOfTask(GetStaticTypeOfTask()); + GetInput() = in; + GetOutput() = 0; +} + +bool AkimovIWordsStringCountSEQ::ValidationImpl() { + return (GetInput() > 0) && (GetOutput() == 0); +} + +bool AkimovIWordsStringCountSEQ::PreProcessingImpl() { + GetOutput() = 2 * GetInput(); + return GetOutput() > 0; +} + +bool AkimovIWordsStringCountSEQ::RunImpl() { + if (GetInput() == 0) { + return false; + } + + for (InType i = 0; i < GetInput(); i++) { + for (InType j = 0; j < GetInput(); j++) { + for (InType k = 0; k < GetInput(); k++) { + std::vector tmp(i + j + k, 1); + GetOutput() += std::accumulate(tmp.begin(), tmp.end(), 0); + GetOutput() -= i + j + k; + } + } + } + + const int num_threads = ppc::util::GetNumThreads(); + GetOutput() *= num_threads; + + int counter = 0; + for (int i = 0; i < num_threads; i++) { + counter++; + } + + if (counter != 0) { + GetOutput() /= counter; + } + return GetOutput() > 0; +} + +bool AkimovIWordsStringCountSEQ::PostProcessingImpl() { + GetOutput() -= GetInput(); + return GetOutput() > 0; +} + +} // namespace akimov_i_words_string_count diff --git a/tasks/akimov_i_words_string_count/settings.json b/tasks/akimov_i_words_string_count/settings.json new file mode 100644 index 0000000000..b1a0d52574 --- /dev/null +++ b/tasks/akimov_i_words_string_count/settings.json @@ -0,0 +1,7 @@ +{ + "tasks_type": "processes", + "tasks": { + "mpi": "enabled", + "seq": "enabled" + } +} diff --git a/tasks/akimov_i_words_string_count/tests/.clang-tidy b/tasks/akimov_i_words_string_count/tests/.clang-tidy new file mode 100644 index 0000000000..ef43b7aa8a --- /dev/null +++ b/tasks/akimov_i_words_string_count/tests/.clang-tidy @@ -0,0 +1,13 @@ +InheritParentConfig: true + +Checks: > + -modernize-loop-convert, + -cppcoreguidelines-avoid-goto, + -cppcoreguidelines-avoid-non-const-global-variables, + -misc-use-anonymous-namespace, + -modernize-use-std-print, + -modernize-type-traits + +CheckOptions: + - key: readability-function-cognitive-complexity.Threshold + value: 50 # Relaxed for tests diff --git a/tasks/akimov_i_words_string_count/tests/functional/main.cpp b/tasks/akimov_i_words_string_count/tests/functional/main.cpp new file mode 100644 index 0000000000..1b5ca1b0a0 --- /dev/null +++ b/tasks/akimov_i_words_string_count/tests/functional/main.cpp @@ -0,0 +1,85 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "akimov_i_words_string_count/common/include/common.hpp" +#include "akimov_i_words_string_count/mpi/include/ops_mpi.hpp" +#include "akimov_i_words_string_count/seq/include/ops_seq.hpp" +#include "util/include/func_test_util.hpp" +#include "util/include/util.hpp" + +namespace akimov_i_words_string_count { + +class NesterovARunFuncTestsProcesses : public ppc::util::BaseRunFuncTests { + public: + static std::string PrintTestParam(const TestType &test_param) { + return std::to_string(std::get<0>(test_param)) + "_" + std::get<1>(test_param); + } + + protected: + void SetUp() override { + int width = -1; + int height = -1; + int channels = -1; + std::vector img; + // Read image + { + std::string abs_path = ppc::util::GetAbsoluteTaskPath(PPC_ID_akimov_i_words_string_count, "pic.jpg"); + auto *data = stbi_load(abs_path.c_str(), &width, &height, &channels, 0); + if (data == nullptr) { + throw std::runtime_error("Failed to load image: " + std::string(stbi_failure_reason())); + } + img = std::vector(data, data + (static_cast(width * height * channels))); + stbi_image_free(data); + if (std::cmp_not_equal(width, height)) { + throw std::runtime_error("width != height: "); + } + } + + TestType params = std::get(ppc::util::GTestParamIndex::kTestParams)>(GetParam()); + input_data_ = width - height + std::min(std::accumulate(img.begin(), img.end(), 0), channels); + } + + bool CheckTestOutputData(OutType &output_data) final { + return (input_data_ == output_data); + } + + InType GetTestInputData() final { + return input_data_; + } + + private: + InType input_data_ = 0; +}; + +namespace { + +TEST_P(NesterovARunFuncTestsProcesses, MatmulFromPic) { + ExecuteTest(GetParam()); +} + +const std::array kTestParam = {std::make_tuple(3, "3"), std::make_tuple(5, "5"), std::make_tuple(7, "7")}; + +const auto kTestTasksList = + std::tuple_cat(ppc::util::AddFuncTask(kTestParam, PPC_SETTINGS_akimov_i_words_string_count), + ppc::util::AddFuncTask(kTestParam, PPC_SETTINGS_akimov_i_words_string_count)); + +const auto kGtestValues = ppc::util::ExpandToValues(kTestTasksList); + +const auto kPerfTestName = NesterovARunFuncTestsProcesses::PrintFuncTestName; + +INSTANTIATE_TEST_SUITE_P(PicMatrixTests, NesterovARunFuncTestsProcesses, kGtestValues, kPerfTestName); + +} // namespace + +} // namespace akimov_i_words_string_count diff --git a/tasks/akimov_i_words_string_count/tests/performance/main.cpp b/tasks/akimov_i_words_string_count/tests/performance/main.cpp new file mode 100644 index 0000000000..848ca6038e --- /dev/null +++ b/tasks/akimov_i_words_string_count/tests/performance/main.cpp @@ -0,0 +1,40 @@ +#include + +#include "akimov_i_words_string_count/common/include/common.hpp" +#include "akimov_i_words_string_count/mpi/include/ops_mpi.hpp" +#include "akimov_i_words_string_count/seq/include/ops_seq.hpp" +#include "util/include/perf_test_util.hpp" + +namespace akimov_i_words_string_count { + +class ExampleRunPerfTestProcesses : public ppc::util::BaseRunPerfTests { + const int kCount_ = 100; + InType input_data_{}; + + void SetUp() override { + input_data_ = kCount_; + } + + bool CheckTestOutputData(OutType &output_data) final { + return input_data_ == output_data; + } + + InType GetTestInputData() final { + return input_data_; + } +}; + +TEST_P(ExampleRunPerfTestProcesses, RunPerfModes) { + ExecuteTest(GetParam()); +} + +const auto kAllPerfTasks = + ppc::util::MakeAllPerfTasks(PPC_SETTINGS_akimov_i_words_string_count); + +const auto kGtestValues = ppc::util::TupleToGTestValues(kAllPerfTasks); + +const auto kPerfTestName = ExampleRunPerfTestProcesses::CustomPerfTestName; + +INSTANTIATE_TEST_SUITE_P(RunModeTests, ExampleRunPerfTestProcesses, kGtestValues, kPerfTestName); + +} // namespace akimov_i_words_string_count From 8e71da13c954d7fff760079bb6ab2d8b55ce7d0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BA=D0=B8=D0=BC=D0=BE=D0=B2=20=D0=98=D0=BB=D1=8C?= =?UTF-8?q?=D1=8F?= Date: Mon, 27 Oct 2025 21:20:51 +0300 Subject: [PATCH 2/5] Fix tests name --- .../akimov_i_words_string_count/tests/functional/main.cpp | 8 ++++---- .../tests/performance/main.cpp | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tasks/akimov_i_words_string_count/tests/functional/main.cpp b/tasks/akimov_i_words_string_count/tests/functional/main.cpp index 1b5ca1b0a0..348020a49f 100644 --- a/tasks/akimov_i_words_string_count/tests/functional/main.cpp +++ b/tasks/akimov_i_words_string_count/tests/functional/main.cpp @@ -20,7 +20,7 @@ namespace akimov_i_words_string_count { -class NesterovARunFuncTestsProcesses : public ppc::util::BaseRunFuncTests { +class AkimovIWordsStringCountFuncTests : public ppc::util::BaseRunFuncTests { public: static std::string PrintTestParam(const TestType &test_param) { return std::to_string(std::get<0>(test_param)) + "_" + std::get<1>(test_param); @@ -64,7 +64,7 @@ class NesterovARunFuncTestsProcesses : public ppc::util::BaseRunFuncTests; +const auto kPerfTestName = AkimovIWordsStringCountFuncTests::PrintFuncTestName; -INSTANTIATE_TEST_SUITE_P(PicMatrixTests, NesterovARunFuncTestsProcesses, kGtestValues, kPerfTestName); +INSTANTIATE_TEST_SUITE_P(PicMatrixTests, AkimovIWordsStringCountFuncTests, kGtestValues, kPerfTestName); } // namespace diff --git a/tasks/akimov_i_words_string_count/tests/performance/main.cpp b/tasks/akimov_i_words_string_count/tests/performance/main.cpp index 848ca6038e..7554ce86f0 100644 --- a/tasks/akimov_i_words_string_count/tests/performance/main.cpp +++ b/tasks/akimov_i_words_string_count/tests/performance/main.cpp @@ -7,7 +7,7 @@ namespace akimov_i_words_string_count { -class ExampleRunPerfTestProcesses : public ppc::util::BaseRunPerfTests { +class AkimovIWordsStringCountPerfTests : public ppc::util::BaseRunPerfTests { const int kCount_ = 100; InType input_data_{}; @@ -24,7 +24,7 @@ class ExampleRunPerfTestProcesses : public ppc::util::BaseRunPerfTests Date: Wed, 29 Oct 2025 16:01:12 +0300 Subject: [PATCH 3/5] Task 1 done --- .../common/include/common.hpp | 3 +- .../data/words.txt | 11 ++ .../mpi/include/ops_mpi.hpp | 7 +- .../mpi/src/ops_mpi.cpp | 114 +++++++++++++----- .../seq/include/ops_seq.hpp | 4 + .../seq/src/ops_seq.cpp | 46 ++++--- .../tests/functional/main.cpp | 82 ++++++++----- .../tests/performance/main.cpp | 33 +++-- 8 files changed, 206 insertions(+), 94 deletions(-) create mode 100644 tasks/akimov_i_words_string_count/data/words.txt diff --git a/tasks/akimov_i_words_string_count/common/include/common.hpp b/tasks/akimov_i_words_string_count/common/include/common.hpp index 6ef653eeba..96160bdc92 100644 --- a/tasks/akimov_i_words_string_count/common/include/common.hpp +++ b/tasks/akimov_i_words_string_count/common/include/common.hpp @@ -2,12 +2,13 @@ #include #include +#include #include "task/include/task.hpp" namespace akimov_i_words_string_count { -using InType = int; +using InType = std::vector; using OutType = int; using TestType = std::tuple; using BaseTask = ppc::task::Task; diff --git a/tasks/akimov_i_words_string_count/data/words.txt b/tasks/akimov_i_words_string_count/data/words.txt new file mode 100644 index 0000000000..0dec264e32 --- /dev/null +++ b/tasks/akimov_i_words_string_count/data/words.txt @@ -0,0 +1,11 @@ + This is a sample line with leading and trailing spaces. +Multiple spaces here + Tabs and spaces mixed +Newlines +are +also +handled +Punctuation! Isn't it counted? Yes. +Русские слова тоже считаются + +End. \ No newline at end of file diff --git a/tasks/akimov_i_words_string_count/mpi/include/ops_mpi.hpp b/tasks/akimov_i_words_string_count/mpi/include/ops_mpi.hpp index b1435b9ef4..d2a5cde3fd 100644 --- a/tasks/akimov_i_words_string_count/mpi/include/ops_mpi.hpp +++ b/tasks/akimov_i_words_string_count/mpi/include/ops_mpi.hpp @@ -17,6 +17,11 @@ class AkimovIWordsStringCountMPI : public BaseTask { bool PreProcessingImpl() override; bool RunImpl() override; bool PostProcessingImpl() override; -}; + InType input_buffer_; + InType local_buffer_; + int local_space_count_ = 0; + int global_space_count_ = 0; + int word_count_ = 0; +}; } // namespace akimov_i_words_string_count diff --git a/tasks/akimov_i_words_string_count/mpi/src/ops_mpi.cpp b/tasks/akimov_i_words_string_count/mpi/src/ops_mpi.cpp index e52c823ed7..29b94899ad 100644 --- a/tasks/akimov_i_words_string_count/mpi/src/ops_mpi.cpp +++ b/tasks/akimov_i_words_string_count/mpi/src/ops_mpi.cpp @@ -2,8 +2,10 @@ #include +#include #include #include +#include #include "akimov_i_words_string_count/common/include/common.hpp" #include "util/include/util.hpp" @@ -17,56 +19,108 @@ AkimovIWordsStringCountMPI::AkimovIWordsStringCountMPI(const InType &in) { } bool AkimovIWordsStringCountMPI::ValidationImpl() { - return (GetInput() > 0) && (GetOutput() == 0); + int rank = 0; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if (rank == 0) { + return (!GetInput().empty()) && (GetOutput() == 0); + } + return true; } bool AkimovIWordsStringCountMPI::PreProcessingImpl() { - GetOutput() = 2 * GetInput(); - return GetOutput() > 0; -} + int rank = 0; + int size = 1; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &size); -bool AkimovIWordsStringCountMPI::RunImpl() { - auto input = GetInput(); - if (input == 0) { - return false; + local_space_count_ = 0; + global_space_count_ = 0; + word_count_ = 0; + local_buffer_.clear(); + input_buffer_.clear(); + + std::size_t total = 0; + if (rank == 0) { + input_buffer_ = GetInput(); + total = input_buffer_.size(); + } + + int base = 0; + int remainder = 0; + if (rank == 0) { + base = static_cast(total / static_cast(size)); + remainder = static_cast(total % static_cast(size)); } + MPI_Bcast(&base, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast(&remainder, 1, MPI_INT, 0, MPI_COMM_WORLD); - for (InType i = 0; i < GetInput(); i++) { - for (InType j = 0; j < GetInput(); j++) { - for (InType k = 0; k < GetInput(); k++) { - std::vector tmp(i + j + k, 1); - GetOutput() += std::accumulate(tmp.begin(), tmp.end(), 0); - GetOutput() -= i + j + k; + int my_count = base + ((rank < remainder) ? 1 : 0); + local_buffer_.resize(my_count); + + if (rank == 0) { + std::size_t offset = 0; + for (int proc = 0; proc < size; ++proc) { + int count = base + ((proc < remainder) ? 1 : 0); + if (count == 0) { + + } else if (proc == 0) { + std::memcpy(local_buffer_.data(), input_buffer_.data() + offset, static_cast(count)); + } else { + MPI_Send(input_buffer_.data() + offset, count, MPI_CHAR, proc, 0, MPI_COMM_WORLD); } + offset += static_cast(count); + } + } else { + if (my_count > 0) { + MPI_Recv(local_buffer_.data(), my_count, MPI_CHAR, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + } else { + + } + } + + return true; +} + +bool AkimovIWordsStringCountMPI::RunImpl() { + local_space_count_ = 0; + for (char c : local_buffer_) { + if (c == ' ') { + ++local_space_count_; } } - const int num_threads = ppc::util::GetNumThreads(); - GetOutput() *= num_threads; + MPI_Reduce(&local_space_count_, &global_space_count_, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD); int rank = 0; MPI_Comm_rank(MPI_COMM_WORLD, &rank); - if (rank == 0) { - GetOutput() /= num_threads; - } else { - int counter = 0; - for (int i = 0; i < num_threads; i++) { - counter++; - } - - if (counter != 0) { - GetOutput() /= counter; + if (GetInput().empty()) { + word_count_ = 0; + } else { + const InType &buf = GetInput(); + bool in_word = false; + word_count_ = 0; + for (char c : buf) { + if (c != ' ' && !in_word) { + in_word = true; + ++word_count_; + } else if (c == ' ' && in_word) { + in_word = false; + } + } } } - MPI_Barrier(MPI_COMM_WORLD); - return GetOutput() > 0; + return true; } bool AkimovIWordsStringCountMPI::PostProcessingImpl() { - GetOutput() -= GetInput(); - return GetOutput() > 0; + int rank = 0; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if (rank == 0) { + GetOutput() = word_count_; + } + return true; } } // namespace akimov_i_words_string_count diff --git a/tasks/akimov_i_words_string_count/seq/include/ops_seq.hpp b/tasks/akimov_i_words_string_count/seq/include/ops_seq.hpp index a35bca6e0f..d064d826d2 100644 --- a/tasks/akimov_i_words_string_count/seq/include/ops_seq.hpp +++ b/tasks/akimov_i_words_string_count/seq/include/ops_seq.hpp @@ -17,6 +17,10 @@ class AkimovIWordsStringCountSEQ : public BaseTask { bool PreProcessingImpl() override; bool RunImpl() override; bool PostProcessingImpl() override; + + InType input_buffer_; + int word_count_ = 0; + int space_count_ = 0; }; } // namespace akimov_i_words_string_count diff --git a/tasks/akimov_i_words_string_count/seq/src/ops_seq.cpp b/tasks/akimov_i_words_string_count/seq/src/ops_seq.cpp index 0cd218b5e5..e5fd22f563 100644 --- a/tasks/akimov_i_words_string_count/seq/src/ops_seq.cpp +++ b/tasks/akimov_i_words_string_count/seq/src/ops_seq.cpp @@ -1,7 +1,7 @@ #include "akimov_i_words_string_count/seq/include/ops_seq.hpp" +#include #include -#include #include "akimov_i_words_string_count/common/include/common.hpp" #include "util/include/util.hpp" @@ -15,46 +15,44 @@ AkimovIWordsStringCountSEQ::AkimovIWordsStringCountSEQ(const InType &in) { } bool AkimovIWordsStringCountSEQ::ValidationImpl() { - return (GetInput() > 0) && (GetOutput() == 0); + return (!GetInput().empty()) && (GetOutput() == 0); } bool AkimovIWordsStringCountSEQ::PreProcessingImpl() { - GetOutput() = 2 * GetInput(); - return GetOutput() > 0; + input_buffer_ = GetInput(); + word_count_ = 0; + space_count_ = 0; + return true; } bool AkimovIWordsStringCountSEQ::RunImpl() { - if (GetInput() == 0) { + if (input_buffer_.empty()) { return false; } - for (InType i = 0; i < GetInput(); i++) { - for (InType j = 0; j < GetInput(); j++) { - for (InType k = 0; k < GetInput(); k++) { - std::vector tmp(i + j + k, 1); - GetOutput() += std::accumulate(tmp.begin(), tmp.end(), 0); - GetOutput() -= i + j + k; - } + for (char c : input_buffer_) { + if (c == ' ') { + ++space_count_; } } - const int num_threads = ppc::util::GetNumThreads(); - GetOutput() *= num_threads; - - int counter = 0; - for (int i = 0; i < num_threads; i++) { - counter++; + bool in_word = false; + word_count_ = 0; + for (char c : input_buffer_) { + if (c != ' ' && !in_word) { + in_word = true; + ++word_count_; + } else if (c == ' ' && in_word) { + in_word = false; + } } - if (counter != 0) { - GetOutput() /= counter; - } - return GetOutput() > 0; + return true; } bool AkimovIWordsStringCountSEQ::PostProcessingImpl() { - GetOutput() -= GetInput(); - return GetOutput() > 0; + GetOutput() = word_count_; + return true; } } // namespace akimov_i_words_string_count diff --git a/tasks/akimov_i_words_string_count/tests/functional/main.cpp b/tasks/akimov_i_words_string_count/tests/functional/main.cpp index 348020a49f..fdd7e9f1bf 100644 --- a/tasks/akimov_i_words_string_count/tests/functional/main.cpp +++ b/tasks/akimov_i_words_string_count/tests/functional/main.cpp @@ -1,11 +1,9 @@ #include -#include +#include -#include #include #include -#include -#include +#include #include #include #include @@ -20,7 +18,7 @@ namespace akimov_i_words_string_count { -class AkimovIWordsStringCountFuncTests : public ppc::util::BaseRunFuncTests { +class AkimovIWordsStringCountFromFileFuncTests : public ppc::util::BaseRunFuncTests { public: static std::string PrintTestParam(const TestType &test_param) { return std::to_string(std::get<0>(test_param)) + "_" + std::get<1>(test_param); @@ -28,47 +26,73 @@ class AkimovIWordsStringCountFuncTests : public ppc::util::BaseRunFuncTests img; - // Read image + std::string abs_path = ppc::util::GetAbsoluteTaskPath(PPC_ID_akimov_i_words_string_count, "words.txt"); + + std::ifstream file(abs_path, std::ios::in | std::ios::binary); + if (!file.is_open()) { + throw std::runtime_error("Cannot open words.txt at path: " + abs_path); + } + + std::string content; { - std::string abs_path = ppc::util::GetAbsoluteTaskPath(PPC_ID_akimov_i_words_string_count, "pic.jpg"); - auto *data = stbi_load(abs_path.c_str(), &width, &height, &channels, 0); - if (data == nullptr) { - throw std::runtime_error("Failed to load image: " + std::string(stbi_failure_reason())); - } - img = std::vector(data, data + (static_cast(width * height * channels))); - stbi_image_free(data); - if (std::cmp_not_equal(width, height)) { - throw std::runtime_error("width != height: "); + std::ostringstream ss; + ss << file.rdbuf(); + content = ss.str(); + } + file.close(); + + for (char &c : content) { + if (c == '\n' || c == '\r' || c == '\t') { + c = ' '; } } - TestType params = std::get(ppc::util::GTestParamIndex::kTestParams)>(GetParam()); - input_data_ = width - height + std::min(std::accumulate(img.begin(), img.end(), 0), channels); - } + input_data_ = InType(content.begin(), content.end()); - bool CheckTestOutputData(OutType &output_data) final { - return (input_data_ == output_data); + is_valid_ = !content.empty(); + + expected_result_ = 0; + if (is_valid_) { + bool in_word = false; + for (char c : content) { + if (c != ' ' && !in_word) { + in_word = true; + ++expected_result_; + } else if (c == ' ' && in_word) { + in_word = false; + } + } + } + + (void)std::get(ppc::util::GTestParamIndex::kTestParams)>(GetParam()); } InType GetTestInputData() final { return input_data_; } + bool CheckTestOutputData(OutType &output_data) final { + int rank = 0; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if (!is_valid_ || rank != 0) { + return true; + } + return output_data == expected_result_; + } + private: - InType input_data_ = 0; + InType input_data_; + OutType expected_result_ = 0; + bool is_valid_ = true; }; namespace { -TEST_P(AkimovIWordsStringCountFuncTests, MatmulFromPic) { +TEST_P(AkimovIWordsStringCountFromFileFuncTests, CountWordsFromFile) { ExecuteTest(GetParam()); } -const std::array kTestParam = {std::make_tuple(3, "3"), std::make_tuple(5, "5"), std::make_tuple(7, "7")}; +const std::array kTestParam = {std::make_tuple(0, std::string("default"))}; const auto kTestTasksList = std::tuple_cat(ppc::util::AddFuncTask(kTestParam, PPC_SETTINGS_akimov_i_words_string_count), @@ -76,9 +100,9 @@ const auto kTestTasksList = const auto kGtestValues = ppc::util::ExpandToValues(kTestTasksList); -const auto kPerfTestName = AkimovIWordsStringCountFuncTests::PrintFuncTestName; +const auto kFuncTestName = AkimovIWordsStringCountFromFileFuncTests::PrintTestParam; -INSTANTIATE_TEST_SUITE_P(PicMatrixTests, AkimovIWordsStringCountFuncTests, kGtestValues, kPerfTestName); +INSTANTIATE_TEST_SUITE_P(CountFromFile, AkimovIWordsStringCountFromFileFuncTests, kGtestValues); } // namespace diff --git a/tasks/akimov_i_words_string_count/tests/performance/main.cpp b/tasks/akimov_i_words_string_count/tests/performance/main.cpp index 7554ce86f0..108a319e19 100644 --- a/tasks/akimov_i_words_string_count/tests/performance/main.cpp +++ b/tasks/akimov_i_words_string_count/tests/performance/main.cpp @@ -1,5 +1,9 @@ #include +#include +#include +#include + #include "akimov_i_words_string_count/common/include/common.hpp" #include "akimov_i_words_string_count/mpi/include/ops_mpi.hpp" #include "akimov_i_words_string_count/seq/include/ops_seq.hpp" @@ -8,20 +12,30 @@ namespace akimov_i_words_string_count { class AkimovIWordsStringCountPerfTests : public ppc::util::BaseRunPerfTests { - const int kCount_ = 100; - InType input_data_{}; - + protected: void SetUp() override { - input_data_ = kCount_; - } - - bool CheckTestOutputData(OutType &output_data) final { - return input_data_ == output_data; + const std::size_t words = 1'000'000; + std::string s; + s.reserve(words * 5); + for (std::size_t i = 0; i < words; ++i) { + s += "word"; + if (i + 1 != words) s += ' '; + } + input_data_ = InType(s.begin(), s.end()); + expected_result_ = static_cast(words); } InType GetTestInputData() final { return input_data_; } + + bool CheckTestOutputData(OutType &output_data) final { + return output_data == expected_result_; + } + + private: + InType input_data_; + OutType expected_result_ = 0; }; TEST_P(AkimovIWordsStringCountPerfTests, RunPerfModes) { @@ -29,7 +43,8 @@ TEST_P(AkimovIWordsStringCountPerfTests, RunPerfModes) { } const auto kAllPerfTasks = - ppc::util::MakeAllPerfTasks(PPC_SETTINGS_akimov_i_words_string_count); + ppc::util::MakeAllPerfTasks( + PPC_SETTINGS_akimov_i_words_string_count); const auto kGtestValues = ppc::util::TupleToGTestValues(kAllPerfTasks); From 9ac678fbd100d70e6bb61227aa1cf6f0c24113d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BA=D0=B8=D0=BC=D0=BE=D0=B2=20=D0=98=D0=BB=D1=8C?= =?UTF-8?q?=D1=8F?= Date: Wed, 29 Oct 2025 16:41:29 +0300 Subject: [PATCH 4/5] Apply clang-format / pre-commit fixes --- tasks/akimov_i_words_string_count/mpi/src/ops_mpi.cpp | 4 +--- .../tests/functional/main.cpp | 6 +++--- .../tests/performance/main.cpp | 9 +++++---- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/tasks/akimov_i_words_string_count/mpi/src/ops_mpi.cpp b/tasks/akimov_i_words_string_count/mpi/src/ops_mpi.cpp index 29b94899ad..cf722a8812 100644 --- a/tasks/akimov_i_words_string_count/mpi/src/ops_mpi.cpp +++ b/tasks/akimov_i_words_string_count/mpi/src/ops_mpi.cpp @@ -3,9 +3,9 @@ #include #include +#include #include #include -#include #include "akimov_i_words_string_count/common/include/common.hpp" #include "util/include/util.hpp" @@ -62,7 +62,6 @@ bool AkimovIWordsStringCountMPI::PreProcessingImpl() { for (int proc = 0; proc < size; ++proc) { int count = base + ((proc < remainder) ? 1 : 0); if (count == 0) { - } else if (proc == 0) { std::memcpy(local_buffer_.data(), input_buffer_.data() + offset, static_cast(count)); } else { @@ -74,7 +73,6 @@ bool AkimovIWordsStringCountMPI::PreProcessingImpl() { if (my_count > 0) { MPI_Recv(local_buffer_.data(), my_count, MPI_CHAR, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); } else { - } } diff --git a/tasks/akimov_i_words_string_count/tests/functional/main.cpp b/tasks/akimov_i_words_string_count/tests/functional/main.cpp index fdd7e9f1bf..3c544202d9 100644 --- a/tasks/akimov_i_words_string_count/tests/functional/main.cpp +++ b/tasks/akimov_i_words_string_count/tests/functional/main.cpp @@ -94,9 +94,9 @@ TEST_P(AkimovIWordsStringCountFromFileFuncTests, CountWordsFromFile) { const std::array kTestParam = {std::make_tuple(0, std::string("default"))}; -const auto kTestTasksList = - std::tuple_cat(ppc::util::AddFuncTask(kTestParam, PPC_SETTINGS_akimov_i_words_string_count), - ppc::util::AddFuncTask(kTestParam, PPC_SETTINGS_akimov_i_words_string_count)); +const auto kTestTasksList = std::tuple_cat( + ppc::util::AddFuncTask(kTestParam, PPC_SETTINGS_akimov_i_words_string_count), + ppc::util::AddFuncTask(kTestParam, PPC_SETTINGS_akimov_i_words_string_count)); const auto kGtestValues = ppc::util::ExpandToValues(kTestTasksList); diff --git a/tasks/akimov_i_words_string_count/tests/performance/main.cpp b/tasks/akimov_i_words_string_count/tests/performance/main.cpp index 108a319e19..bbc200b39a 100644 --- a/tasks/akimov_i_words_string_count/tests/performance/main.cpp +++ b/tasks/akimov_i_words_string_count/tests/performance/main.cpp @@ -19,7 +19,9 @@ class AkimovIWordsStringCountPerfTests : public ppc::util::BaseRunPerfTests(words); @@ -42,9 +44,8 @@ TEST_P(AkimovIWordsStringCountPerfTests, RunPerfModes) { ExecuteTest(GetParam()); } -const auto kAllPerfTasks = - ppc::util::MakeAllPerfTasks( - PPC_SETTINGS_akimov_i_words_string_count); +const auto kAllPerfTasks = ppc::util::MakeAllPerfTasks( + PPC_SETTINGS_akimov_i_words_string_count); const auto kGtestValues = ppc::util::TupleToGTestValues(kAllPerfTasks); From 25973fa9a3633860fe22803559edd79d1213275e Mon Sep 17 00:00:00 2001 From: Akimov52 <144248249+Akimov52@users.noreply.github.com> Date: Wed, 29 Oct 2025 17:24:37 +0300 Subject: [PATCH 5/5] Update report.md --- tasks/akimov_i_words_string_count/report.md | 50 +++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/tasks/akimov_i_words_string_count/report.md b/tasks/akimov_i_words_string_count/report.md index e69de29bb2..3475785e73 100644 --- a/tasks/akimov_i_words_string_count/report.md +++ b/tasks/akimov_i_words_string_count/report.md @@ -0,0 +1,50 @@ +### Отчёт по задаче: "Подсчёт числа слов в строке" +**Вариант:** №24 +**Выполнил студент группы 3823Б1ФИ2:** Акимов Илья Александрович +**Работу проверили:** преподаватель Нестеров Александр Юрьевич и преподаватель Оболенский Арсений Андреевич + +## Введение +В данной работе реализован алгоритм подсчёта количества слов в строке. Алгоритм представлен в двух вариантах: последовательная реализация (SEQ) и параллельная реализация с использованием технологии MPI. Цель работы — корректно подсчитать количество слов в строке и ускорить вычисления для больших объемов данных за счёт параллельной обработки. + +## Постановка задачи и формальное описание +Необходимо определить количество слов в строке. Слово — последовательность непробельных символов, разделённая пробелами, табуляциями или переводами строк. + +Формально: пусть `S` — входная строка длины `n`. Необходимо вычислить: +`word_count = количество таких последовательностей символов, которые отделены пробелами и другими разделителями` + +## Пример +Строка: `" This is an example "` +Слова: `"This"`, `"is"`, `"an"`, `"example"` +Количество слов: 4 + +## Реализация разделена на модули +- `ops_seq.hpp` и `ops_seq.cpp` — последовательная реализация подсчёта слов +- `ops_mpi.hpp` и `ops_mpi.cpp` — параллельная реализация с использованием MPI +- `common.hpp` — определения типов данных и базовый класс задачи +- `functional/main.cpp` — функциональные тесты +- `performance/main.cpp` — тесты производительности + +## Описание последовательной версии +Последовательная версия (`AkimovIWordsStringCountSEQ`) сохраняет строку во внутренний буфер и проходит по всем символам. Алгоритм подсчёта слов работает следующим образом: + +1. Для каждого символа проверяется, является ли он пробелом. +2. Если текущий символ — начало слова (не пробел, предыдущий был пробел или начало строки), счётчик слов увеличивается. +3. Итоговый результат сохраняется в `GetOutput()`. + +## Описание параллельной версии +Параллельная версия (`AkimovIWordsStringCountMPI`) распределяет входную строку между процессами MPI: + +1. Процесс с рангом 0 делит строку на равные блоки для всех процессов. +2. Каждый процесс получает свой блок и подсчитывает количество пробелов в нём. +3. Частичные результаты объединяются с помощью `MPI_Reduce`. +4. На процессе с рангом 0 выполняется финальный подсчёт слов по всей строке, корректно учитывая границы блоков. + +Такой подход позволяет эффективно обрабатывать очень большие строки, распределяя работу между процессами. + +## Тестирования + +### Функциональное тестирование +Функциональные тесты проверяют корректность работы алгоритмов на заранее известных данных. Тесты считывают строки из файла `words.txt`, заменяя табуляции и переводы строк на пробелы. Для каждой позиции строки алгоритм определяет, начинается ли слово, и увеличивает счётчик. + +### Тестирование производительности +Для тестирования производительности формируется строка из 1 миллиона слов `"word"`, разделённых пробелами. Это гарантирует предсказуемый результат (1 000 000 слов), позволяя точно проверять корректность работы как последовательной, так и параллельной версий.