diff --git a/act b/act new file mode 100644 index 0000000000..7e68ee6795 Binary files /dev/null and b/act differ diff --git a/act.tar.gz b/act.tar.gz new file mode 100644 index 0000000000..2bcea0a85c Binary files /dev/null and b/act.tar.gz differ diff --git a/bin/act b/bin/act new file mode 100644 index 0000000000..7e68ee6795 Binary files /dev/null and b/bin/act differ diff --git a/check_ci_fixed.sh b/check_ci_fixed.sh new file mode 100644 index 0000000000..41dc0bc84e --- /dev/null +++ b/check_ci_fixed.sh @@ -0,0 +1,61 @@ +#!/bin/bash + +echo "🔍 CI Check with System Tools" +echo "==============================" + +# Используем системные инструменты +CLANG_FORMAT="/usr/bin/clang-format" +CLANG_TIDY="/usr/bin/clang-tidy" + +# 1. Проверка форматирования +echo "1. Checking code formatting..." +if [ -f "$CLANG_FORMAT" ]; then + find tasks/sizov_d_string_mismatch_count -name "*.cpp" -o -name "*.hpp" | \ + xargs $CLANG_FORMAT --dry-run --Werror + if [ $? -eq 0 ]; then + echo "✅ Formatting: OK" + else + echo "❌ Formatting: Issues found" + exit 1 + fi +else + echo "⚠️ clang-format not found, skipping formatting check" +fi + +# 2. Проверка clang-tidy +echo "2. Running clang-tidy..." +mkdir -p build +cd build +cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON .. > /dev/null 2>&1 +cd .. + +FAILED=0 +for file in $(find tasks/sizov_d_string_mismatch_count -name "*.cpp" -o -name "*.hpp"); do + echo " $file" + $CLANG_TIDY -p build "$file" 2>&1 | grep -q "error:" && { + echo " ❌ Errors found" + $CLANG_TIDY -p build "$file" 2>&1 | grep "error:" | head -2 + FAILED=1 + } || echo " ✅ OK" +done + +if [ $FAILED -eq 0 ]; then + echo "✅ Clang-tidy: All files passed" +else + echo "❌ Clang-tidy: Some files failed" + exit 1 +fi + +# 3. Проверка сборки +echo "3. Checking build..." +cd build +if make -j4 > /dev/null 2>&1; then + echo "✅ Build: Successful" +else + echo "❌ Build: Failed" + exit 1 +fi +cd .. + +echo "==============================" +echo "🎉 All checks passed!" diff --git a/local_ci_check.sh b/local_ci_check.sh new file mode 100644 index 0000000000..c4b517cd82 --- /dev/null +++ b/local_ci_check.sh @@ -0,0 +1,79 @@ +#!/bin/bash + +set -e + +echo "🚀 Starting Local CI Simulation" +echo "=================================" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' + +# Function to print status +print_status() { + if [ $1 -eq 0 ]; then + echo -e "${GREEN}✓ $2${NC}" + else + echo -e "${RED}✗ $2${NC}" + exit 1 + fi +} + +# 1. Check .clang-format syntax +echo "1. Validating .clang-format configuration..." +clang-format -style=file -dump-config > /dev/null +print_status $? ".clang-format syntax" + +# 2. Code formatting check +echo "2. Checking code formatting..." +find tasks/sizov_d_string_mismatch_count -name "*.cpp" -o -name "*.hpp" | \ + xargs clang-format --dry-run --Werror --ferror-limit=0 +print_status $? "Code formatting" + +# 3. Ensure build directory exists +echo "3. Setting up build environment..." +mkdir -p build +cd build +cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON .. > /dev/null 2>&1 +cd .. +print_status $? "Build setup" + +# 4. Clang-tidy analysis +echo "4. Running clang-tidy analysis..." +FAILED_FILES=0 +for file in $(find tasks/sizov_d_string_mismatch_count -name "*.cpp" -o -name "*.hpp"); do + echo " Analyzing: $file" + if clang-tidy -p build "$file" --format-style=file 2>&1 | grep -q "error:\|warning:"; then + echo -e " ${RED}✗ Issues found${NC}" + clang-tidy -p build "$file" --format-style=file 2>&1 | grep "error:\|warning:" | head -3 + FAILED_FILES=$((FAILED_FILES + 1)) + else + echo -e " ${GREEN}✓ OK${NC}" + fi +done + +if [ $FAILED_FILES -eq 0 ]; then + echo -e "${GREEN}✓ All files passed clang-tidy${NC}" +else + echo -e "${RED}✗ $FAILED_FILES files have clang-tidy issues${NC}" + exit 1 +fi + +# 5. Build verification +echo "5. Verifying build..." +cd build +if make -j4 > build.log 2>&1; then + echo -e "${GREEN}✓ Build successful${NC}" +else + echo -e "${RED}✗ Build failed${NC}" + echo "Build log:" + tail -20 build.log + exit 1 +fi +cd .. + +echo "=================================" +echo -e "${GREEN}🎉 All CI checks passed!${NC}" +echo "You can safely push to your branch" diff --git a/tasks/sizov_d_string_mismatch_count/common/include/common.hpp b/tasks/sizov_d_string_mismatch_count/common/include/common.hpp new file mode 100644 index 0000000000..57887faf6b --- /dev/null +++ b/tasks/sizov_d_string_mismatch_count/common/include/common.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include +#include + +#include "task/include/task.hpp" + +namespace sizov_d_string_mismatch_count { + +using InType = std::tuple; +using OutType = int; +using TestType = std::string; +using BaseTask = ppc::task::Task; + +} // namespace sizov_d_string_mismatch_count diff --git a/tasks/sizov_d_string_mismatch_count/data/strings.txt b/tasks/sizov_d_string_mismatch_count/data/strings.txt new file mode 100644 index 0000000000..dcdda79dd6 --- /dev/null +++ b/tasks/sizov_d_string_mismatch_count/data/strings.txt @@ -0,0 +1,2 @@ +1234567890 +12345X7890 diff --git a/tasks/sizov_d_string_mismatch_count/info.json b/tasks/sizov_d_string_mismatch_count/info.json new file mode 100644 index 0000000000..ec55f60b3e --- /dev/null +++ b/tasks/sizov_d_string_mismatch_count/info.json @@ -0,0 +1,9 @@ +{ + "student": { + "first_name": "Дмитрий", + "last_name": "Сизов", + "middle_name": "Игоревич", + "group_number": "3823Б1ФИ2", + "task_number": "1" + } +} diff --git a/tasks/sizov_d_string_mismatch_count/mpi/include/ops_mpi.hpp b/tasks/sizov_d_string_mismatch_count/mpi/include/ops_mpi.hpp new file mode 100644 index 0000000000..ab88101e4f --- /dev/null +++ b/tasks/sizov_d_string_mismatch_count/mpi/include/ops_mpi.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include + +#include "sizov_d_string_mismatch_count/common/include/common.hpp" +#include "task/include/task.hpp" + +namespace sizov_d_string_mismatch_count { + +class SizovDStringMismatchCountMPI : public BaseTask { + public: + static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() { + return ppc::task::TypeOfTask::kMPI; + } + + explicit SizovDStringMismatchCountMPI(const InType &input); + + private: + std::string str_a_; + std::string str_b_; + int global_result_ = 0; + + bool ValidationImpl() override; + bool PreProcessingImpl() override; + bool RunImpl() override; + bool PostProcessingImpl() override; +}; + +} // namespace sizov_d_string_mismatch_count diff --git a/tasks/sizov_d_string_mismatch_count/mpi/src/ops_mpi.cpp b/tasks/sizov_d_string_mismatch_count/mpi/src/ops_mpi.cpp new file mode 100644 index 0000000000..13c2bbbde5 --- /dev/null +++ b/tasks/sizov_d_string_mismatch_count/mpi/src/ops_mpi.cpp @@ -0,0 +1,68 @@ +#include "sizov_d_string_mismatch_count/mpi/include/ops_mpi.hpp" + +#include + +#include +#include +#include + +#include "sizov_d_string_mismatch_count/common/include/common.hpp" + +namespace sizov_d_string_mismatch_count { +SizovDStringMismatchCountMPI::SizovDStringMismatchCountMPI(const InType &input) { + SetTypeOfTask(GetStaticTypeOfTask()); + GetInput() = input; + GetOutput() = 0; +} + +bool SizovDStringMismatchCountMPI::ValidationImpl() { + const auto &input = GetInput(); + const auto &a = std::get<0>(input); + const auto &b = std::get<1>(input); + return !a.empty() && a.size() == b.size(); +} + +bool SizovDStringMismatchCountMPI::PreProcessingImpl() { + const auto &input = GetInput(); + str_a_ = std::get<0>(input); + str_b_ = std::get<1>(input); + return true; +} + +bool SizovDStringMismatchCountMPI::RunImpl() { + int rank = 0; + int size = 0; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &size); + + const int total_size = static_cast(str_a_.size()); + if (total_size == 0) { + return true; + } + + const int base = total_size / size; + const int remainder = total_size % size; + const int start = (rank * base) + std::min(rank, remainder); + const int local_size = base + (rank < remainder ? 1 : 0); + + std::string_view local_a(str_a_.data() + start, local_size); + std::string_view local_b(str_b_.data() + start, local_size); + + int local_result = 0; + for (int i = 0; i < local_size; ++i) { + if (local_a[i] != local_b[i]) { + ++local_result; + } + } + + MPI_Reduce(&local_result, &global_result_, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD); + MPI_Bcast(&global_result_, 1, MPI_INT, 0, MPI_COMM_WORLD); + + GetOutput() = global_result_; + return true; +} + +bool SizovDStringMismatchCountMPI::PostProcessingImpl() { + return true; +} +} // namespace sizov_d_string_mismatch_count diff --git a/tasks/sizov_d_string_mismatch_count/report.md b/tasks/sizov_d_string_mismatch_count/report.md new file mode 100644 index 0000000000..28bfa83d84 --- /dev/null +++ b/tasks/sizov_d_string_mismatch_count/report.md @@ -0,0 +1,44 @@ +### Отчёт по задаче: "Подсчет числа несовпадающих символов двух строк" +**Вариант:** №27 +**Выполнил студент группы 3823Б1ФИ2:** Сизов Дмитрий Игоревич +**Работу проверили:** преподаватель Нестеров Александр Юрьевич и преподаватель Оболенский Арсений Андреевич + +## Введение +В рамках данной работы реализован алгоритм подсчета несовпадающих символов в двух строках одинаковой длины, а также выполнена его параллелизация с использованием технологии MPI. Целью является ускорение вычислений за счет распределения работы между несколькими процессами. + +## Постановка задачи и формальное описание +Имеются две строки одинаковой длины. Требуется определить количество позиций, на которых символы в строках различаются. +Формально: пусть `A` и `B` — строки длины `n`. Необходимо вычислить: +`count = количество таких i, что A[i] ≠ B[i] для 0 ≤ i < n` + +## Пример +Строка A: `"abcde"` +Строка B: `"abzdf"` +Несовпадения: 2 (позиции 2 и 4) + +## Реализация разделена на модули +- `ops_seq.hpp` и `ops_seq.cpp` — реализация последовательного алгоритма +- `ops_mpi.hpp` и `ops_mpi.cpp` — реализация параллельного алгоритма +- `common.hpp` — общее определение входных/выходных типов + +## Описание последовательной версии +Алгоритм проходит по всем символам строк и сравнивает их попарно. Каждое несовпадение увеличивает счетчик. Итог — общее количество отличий. + +## Описание параллельной версии +Параллельный алгоритм с использованием MPI делит входные строки на блоки, равномерно распределяемые между процессами. Каждый процесс сравнивает символы в своем участке и подсчитывает количество несовпадений. Частичные результаты объединяются с помощью `MPI_Reduce`, а итоговая сумма сохраняется на процессе с рангом 0. +Такой подход позволяет ускорить вычисления за счёт распределённой обработки данных. + +## Тестирования разделены на модули +- `functional/main.cpp` — функциональные тесты +- `performance/main.cpp` — производительные тесты + +## Функциональное тестирование +Функциональные тесты предназначены для проверки корректности работы алгоритма на заранее известных входных данных. +В рамках теста используются строки, считываемые из файла `strings.txt`. Файл содержит две строки, которые сравниваются с помощью обеих реализаций. +Ожидаемый результат рассчитывается в рамках теста: для каждой позиции двух строк выполняется сравнение, и при обнаружении различий счётчик увеличивается. +Результат, возвращаемый алгоритмом, сопоставляется с ожидаемым значением. Это позволяет удостовериться в корректности как последовательной, так и MPI-реализации. + +## Тестирование производительности +В тестировании на производительность формируются две строки по 1 миллиону символов. +Первая строка полностью состоит из символов `'a'`, вторая — копия первой, но с заменой первых 10% символов на `'b'`. +Это гарантирует строго определённое число несовпадений (100 000), что позволяет точно проверить корректность результата. diff --git a/tasks/sizov_d_string_mismatch_count/seq/include/ops_seq.hpp b/tasks/sizov_d_string_mismatch_count/seq/include/ops_seq.hpp new file mode 100644 index 0000000000..0c0931c577 --- /dev/null +++ b/tasks/sizov_d_string_mismatch_count/seq/include/ops_seq.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include + +#include "sizov_d_string_mismatch_count/common/include/common.hpp" +#include "task/include/task.hpp" + +namespace sizov_d_string_mismatch_count { + +class SizovDStringMismatchCountSEQ : public BaseTask { + public: + static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() { + return ppc::task::TypeOfTask::kSEQ; + } + + explicit SizovDStringMismatchCountSEQ(const InType &input); + + private: + std::string str_a_; + std::string str_b_; + int result_ = 0; + + bool ValidationImpl() override; + bool PreProcessingImpl() override; + bool RunImpl() override; + bool PostProcessingImpl() override; +}; + +} // namespace sizov_d_string_mismatch_count diff --git a/tasks/sizov_d_string_mismatch_count/seq/src/ops_seq.cpp b/tasks/sizov_d_string_mismatch_count/seq/src/ops_seq.cpp new file mode 100644 index 0000000000..2fe80558b1 --- /dev/null +++ b/tasks/sizov_d_string_mismatch_count/seq/src/ops_seq.cpp @@ -0,0 +1,46 @@ +#include "sizov_d_string_mismatch_count/seq/include/ops_seq.hpp" + +#include +#include + +#include "sizov_d_string_mismatch_count/common/include/common.hpp" + +namespace sizov_d_string_mismatch_count { + +SizovDStringMismatchCountSEQ::SizovDStringMismatchCountSEQ(const InType &input) { + SetTypeOfTask(GetStaticTypeOfTask()); + GetInput() = input; + GetOutput() = 0; +} + +bool SizovDStringMismatchCountSEQ::ValidationImpl() { + const auto &input = GetInput(); + const auto &a = std::get<0>(input); + const auto &b = std::get<1>(input); + return !a.empty() && a.size() == b.size(); +} + +bool SizovDStringMismatchCountSEQ::PreProcessingImpl() { + const auto &input = GetInput(); + str_a_ = std::get<0>(input); + str_b_ = std::get<1>(input); + result_ = 0; + return true; +} + +bool SizovDStringMismatchCountSEQ::RunImpl() { + result_ = 0; + for (std::size_t i = 0; i < str_a_.size(); ++i) { + if (str_a_[i] != str_b_[i]) { + ++result_; + } + } + return true; +} + +bool SizovDStringMismatchCountSEQ::PostProcessingImpl() { + GetOutput() = result_; + return true; +} + +} // namespace sizov_d_string_mismatch_count diff --git a/tasks/sizov_d_string_mismatch_count/settings.json b/tasks/sizov_d_string_mismatch_count/settings.json new file mode 100644 index 0000000000..0dd4f2b205 --- /dev/null +++ b/tasks/sizov_d_string_mismatch_count/settings.json @@ -0,0 +1,7 @@ +{ + "tasks_type": "processes", + "tasks": { + "mpi": "enabled", + "seq": "enabled" + } +} \ No newline at end of file diff --git a/tasks/sizov_d_string_mismatch_count/tests/functional/main.cpp b/tasks/sizov_d_string_mismatch_count/tests/functional/main.cpp new file mode 100644 index 0000000000..ff284ba431 --- /dev/null +++ b/tasks/sizov_d_string_mismatch_count/tests/functional/main.cpp @@ -0,0 +1,91 @@ +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "sizov_d_string_mismatch_count/common/include/common.hpp" +#include "sizov_d_string_mismatch_count/mpi/include/ops_mpi.hpp" +#include "sizov_d_string_mismatch_count/seq/include/ops_seq.hpp" +#include "util/include/func_test_util.hpp" +#include "util/include/util.hpp" + +namespace sizov_d_string_mismatch_count { + +class SizovDRunFuncTestsStringMismatchCount : public ppc::util::BaseRunFuncTests { + public: + static std::string PrintTestParam(const TestType &test_param) { + return test_param; + } + + protected: + void SetUp() override { + std::string abs_path = ppc::util::GetAbsoluteTaskPath(PPC_ID_sizov_d_string_mismatch_count, "strings.txt"); + + std::ifstream file(abs_path); + if (!file.is_open()) { + throw std::runtime_error("Cannot open strings.txt"); + } + + std::string a; + std::string b; + std::getline(file, a); + std::getline(file, b); + file.close(); + + input_data_ = std::make_tuple(a, b); + is_valid_ = !a.empty() && a.size() == b.size(); + + expected_result_ = 0; + if (is_valid_) { + for (size_t i = 0; i < a.size(); ++i) { + if (a[i] != b[i]) { + ++expected_result_; + } + } + } + } + + InType GetTestInputData() override { + return input_data_; + } + + bool CheckTestOutputData(OutType &output_data) override { + 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_; + OutType expected_result_ = 0; + bool is_valid_ = true; +}; + +namespace { + +TEST_P(SizovDRunFuncTestsStringMismatchCount, CompareStringsFromFile) { + ExecuteTest(GetParam()); +} + +const std::array kTestParam = {"default"}; + +const auto kTaskList = std::tuple_cat(ppc::util::AddFuncTask( + kTestParam, PPC_SETTINGS_sizov_d_string_mismatch_count), + ppc::util::AddFuncTask( + kTestParam, PPC_SETTINGS_sizov_d_string_mismatch_count)); + +const auto kGtestValues = ppc::util::ExpandToValues(kTaskList); +const auto kTestName = SizovDRunFuncTestsStringMismatchCount::PrintFuncTestName; + +INSTANTIATE_TEST_SUITE_P(CompareFromFile, SizovDRunFuncTestsStringMismatchCount, kGtestValues, kTestName); + +} // namespace +} // namespace sizov_d_string_mismatch_count diff --git a/tasks/sizov_d_string_mismatch_count/tests/performance/main.cpp b/tasks/sizov_d_string_mismatch_count/tests/performance/main.cpp new file mode 100644 index 0000000000..76e78a8247 --- /dev/null +++ b/tasks/sizov_d_string_mismatch_count/tests/performance/main.cpp @@ -0,0 +1,54 @@ +#include + +#include +#include +#include +#include + +#include "sizov_d_string_mismatch_count/common/include/common.hpp" +#include "sizov_d_string_mismatch_count/mpi/include/ops_mpi.hpp" +#include "sizov_d_string_mismatch_count/seq/include/ops_seq.hpp" +#include "util/include/perf_test_util.hpp" + +namespace sizov_d_string_mismatch_count { + +class SizovDRunPerfTestsStringMismatchCount : public ppc::util::BaseRunPerfTests { + void SetUp() override { + std::string a(1'000'000, 'a'); + std::string b = a; + + for (std::size_t i = 0; i < a.size() / 10; ++i) { + b[i] = 'b'; + } + + expected_result_ = static_cast(a.size() / 10); + input_data_ = std::make_tuple(std::move(a), std::move(b)); + } + + 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; +}; + +const auto kAllPerfTasks = + ppc::util::MakeAllPerfTasks( + PPC_SETTINGS_sizov_d_string_mismatch_count); + +const auto kGtestValues = ppc::util::TupleToGTestValues(kAllPerfTasks); +const auto kPerfTestName = SizovDRunPerfTestsStringMismatchCount::CustomPerfTestName; + +TEST_P(SizovDRunPerfTestsStringMismatchCount, RunPerfModes) { + ExecuteTest(GetParam()); +} + +INSTANTIATE_TEST_SUITE_P(RunPerf, SizovDRunPerfTestsStringMismatchCount, kGtestValues, kPerfTestName); + +} // namespace sizov_d_string_mismatch_count