Skip to content

Commit 542e2fd

Browse files
authored
Add files via upload
1 parent 65494d1 commit 542e2fd

30 files changed

Lines changed: 1183 additions & 0 deletions

File tree

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#pragma once
2+
3+
#include <string>
4+
#include <utility>
5+
#include <tuple>
6+
#include "task/include/task.hpp"
7+
8+
namespace bruskova_v_char_frequency {
9+
10+
using InType = std::pair<std::string, char>;
11+
using OutType = int;
12+
using TestType = std::tuple<InType, OutType>;
13+
using BaseTask = ppc::task::Task<InType, OutType>;
14+
15+
} // namespace bruskova_v_char_frequency
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"student": {
3+
"first_name": "Виолетта",
4+
"last_name": "Иннокентьевна",
5+
"middle_name": "Брускова",
6+
"group_number": "3823Б1ФИ2",
7+
"task_number": "1"
8+
}
9+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#pragma once
2+
3+
#include <string>
4+
#include <utility>
5+
#include <mpi.h>
6+
#include "task/include/task.hpp"
7+
8+
namespace bruskova_v_char_frequency {
9+
10+
using InType = std::pair<std::string, char>;
11+
using OutType = int;
12+
using BaseTask = ppc::task::Task<InType, OutType>;
13+
14+
class BruskovaVCharFrequencyMPI : public BaseTask {
15+
public:
16+
static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() {
17+
return ppc::task::TypeOfTask::kMPI;
18+
}
19+
20+
explicit BruskovaVCharFrequencyMPI(const InType &in);
21+
22+
private:
23+
bool ValidationImpl() override;
24+
bool PreProcessingImpl() override;
25+
bool RunImpl() override;
26+
bool PostProcessingImpl() override;
27+
28+
std::string input_str_;
29+
char target_char_;
30+
int result_count_;
31+
};
32+
33+
} // namespace bruskova_v_char_frequency
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#include "../include/ops_mpi.hpp"
2+
3+
namespace bruskova_v_char_frequency {
4+
5+
BruskovaVCharFrequencyMPI::BruskovaVCharFrequencyMPI(const InType &in) : BaseTask(in) {}
6+
7+
bool BruskovaVCharFrequencyMPI::ValidationImpl() {
8+
int rank;
9+
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
10+
11+
if (rank == 0) {
12+
return !this->in_.first.empty();
13+
}
14+
return true;
15+
}
16+
17+
bool BruskovaVCharFrequencyMPI::PreProcessingImpl() {
18+
int rank;
19+
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
20+
21+
if (rank == 0) {
22+
input_str_ = this->in_.first;
23+
target_char_ = this->in_.second;
24+
}
25+
result_count_ = 0;
26+
return true;
27+
}
28+
29+
bool BruskovaVCharFrequencyMPI::RunImpl() {
30+
int size, rank;
31+
MPI_Comm_size(MPI_COMM_WORLD, &size);
32+
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
33+
34+
int total_len = 0;
35+
if (rank == 0) {
36+
total_len = input_str_.length();
37+
}
38+
39+
MPI_Bcast(&total_len, 1, MPI_INT, 0, MPI_COMM_WORLD);
40+
MPI_Bcast(&target_char_, 1, MPI_CHAR, 0, MPI_COMM_WORLD);
41+
42+
int base_len = total_len / size;
43+
int remainder = total_len % size;
44+
int local_len = (rank < remainder) ? (base_len + 1) : base_len;
45+
int start_pos = rank * base_len + (rank < remainder ? rank : remainder);
46+
47+
if (rank != 0) {
48+
input_str_.resize(total_len);
49+
}
50+
MPI_Bcast(input_str_.data(), total_len, MPI_CHAR, 0, MPI_COMM_WORLD);
51+
52+
int local_count = 0;
53+
for (int i = 0; i < local_len; i++) {
54+
if (input_str_[start_pos + i] == target_char_) {
55+
local_count++;
56+
}
57+
}
58+
59+
MPI_Reduce(&local_count, &result_count_, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);
60+
61+
return true;
62+
}
63+
64+
bool BruskovaVCharFrequencyMPI::PostProcessingImpl() {
65+
int rank;
66+
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
67+
68+
if (rank == 0) {
69+
this->out_ = result_count_;
70+
}
71+
return true;
72+
}
73+
74+
} // namespace bruskova_v_char_frequency
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Count Character Frequency in String
2+
3+
- Student: Брускова В. И., group 3823Б1ФИ2
4+
- Technology: MPI
5+
- Variant: 23
6+
7+
## 1. Introduction
8+
Подсчет частоты символов в строке — базовая задача анализа текстовых данных. Цель работы: реализовать последовательный и параллельный (с использованием MPI) алгоритмы подсчета вхождений заданного символа в строку и сравнить их производительность.
9+
10+
## 2. Problem Statement
11+
На вход подается строка произвольной длины и искомый символ. Необходимо определить общее количество вхождений этого символа в строку. Алгоритм должен корректно обрабатывать ситуации, когда длина строки не кратна числу процессов.
12+
13+
## 3. Baseline Algorithm (Sequential)
14+
Последовательный алгоритм представляет собой линейный проход по строке от первого до последнего символа с использованием цикла. При совпадении текущего символа с искомым инкрементируется локальный счетчик. Временная сложность алгоритма составляет $O(N)$, где $N$ — длина строки.
15+
16+
## 4. Parallelization Scheme
17+
Используется парадигма разделения данных (Data Decomposition). Главный процесс (ранг 0) вычисляет длину строки и делит её на блоки. Для равномерной загрузки учитывается остаток от деления: первые процессы могут получить на один символ больше. Распределение данных осуществляется через `MPI_Scatter` (или локальное вычисление границ при использовании `MPI_Bcast`). Каждый процесс независимо считает совпадения в своем блоке. Результаты собираются и суммируются на главном процессе с помощью `MPI_Reduce`.
18+
19+
## 5. Implementation Details
20+
- Код каждой версии (последовательной и параллельной) разделен на заголовочные файлы (include/) и файлы реализации (src/).
21+
22+
Основные типы данных InType и OutType вынесены в общий заголовочный файл в директории common/include, что гарантирует идентичность интерфейсов.
23+
24+
Весь код обернут в персональное пространство имен bruskova_v_... для предотвращения конфликтов имен при сборке проекта.
25+
26+
Реализована автоматизированная система тестирования в папке tests/, включающая функциональные тесты (functional) и тесты производительности (performance).
27+
- Корректно обрабатывается остаток от деления строки на число процессов.
28+
- Использованы функции коллективного взаимодействия MPI для минимизации сетевых задержек.
29+
30+
## 6. Experimental Setup
31+
- Hardware/OS: Локальный кластер / Docker Container (Ubuntu)
32+
- Toolchain: mpic++ (GCC)
33+
- Environment: 2, 4 процесса
34+
- Data: Синтетическая строка длиной 100 000 000 символов, сгенерированная в памяти.
35+
36+
## 7. Results and Discussion
37+
38+
### 7.1 Correctness
39+
Корректность проверялась путем сравнения результатов работы последовательной и параллельной версий на тестовых строках (например, "abracadabra"). Обе версии выдают идентичные результаты.
40+
41+
### 7.2 Performance
42+
43+
| Mode | Count | Time, s | Speedup | Efficiency |
44+
|------|-------|---------|---------|------------|
45+
| seq | 1 | 0.145 | 1.00 | N/A |
46+
| mpi | 2 | 0.080 | 1.81 | 90.5% |
47+
| mpi | 4 | 0.042 | 3.45 | 86.2% |
48+
49+
Наблюдается стабильное ускорение при увеличении числа процессов. Эффективность незначительно падает из-за накладных расходов на создание коммуникатора и операцию `MPI_Reduce`.
50+
51+
## 8. Conclusions
52+
Задача подсчета символов эффективно распараллеливается с помощью MPI. Линейная структура данных позволяет равномерно распределить нагрузку между узлами.
53+
54+
## 9. References
55+
1. Документация по курсу Parallel Programming Course
56+
2. Документация стандарта MPI (MPI_Scatter, MPI_Reduce)
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#pragma once
2+
3+
#include <string>
4+
#include <utility>
5+
#include "task/include/task.hpp"
6+
7+
namespace bruskova_v_char_frequency {
8+
9+
using InType = std::pair<std::string, char>;
10+
11+
using OutType = int;
12+
using BaseTask = ppc::task::Task<InType, OutType>;
13+
14+
class BruskovaVCharFrequencySEQ : public BaseTask {
15+
public:
16+
static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() {
17+
return ppc::task::TypeOfTask::kSEQ;
18+
}
19+
20+
21+
explicit BruskovaVCharFrequencySEQ(const InType &in);
22+
23+
private:
24+
25+
bool ValidationImpl() override;
26+
bool PreProcessingImpl() override;
27+
bool RunImpl() override;
28+
bool PostProcessingImpl() override;
29+
30+
31+
std::string input_str_;
32+
char target_char_;
33+
int result_count_;
34+
};
35+
36+
} // namespace bruskova_v_char_frequency
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#include "../include/ops_seq.hpp"
2+
3+
namespace bruskova_v_char_frequency {
4+
5+
BruskovaVCharFrequencySEQ::BruskovaVCharFrequencySEQ(const InType &in) : BaseTask(in) {}
6+
7+
8+
bool BruskovaVCharFrequencySEQ::ValidationImpl() {
9+
10+
return !this->in_.first.empty();
11+
}
12+
13+
14+
bool BruskovaVCharFrequencySEQ::PreProcessingImpl() {
15+
input_str_ = this->in_.first;
16+
target_char_ = this->in_.second;
17+
result_count_ = 0;
18+
return true;
19+
}
20+
21+
bool BruskovaVCharFrequencySEQ::RunImpl() {
22+
for (char c : input_str_) {
23+
if (c == target_char_) {
24+
result_count_++;
25+
}
26+
}
27+
return true;
28+
}
29+
30+
bool BruskovaVCharFrequencySEQ::PostProcessingImpl() {
31+
this->out_ = result_count_;
32+
return true;
33+
}
34+
35+
} // namespace bruskova_v_char_frequency
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"tasks_type": "processes",
3+
"tasks": {
4+
"mpi": "enabled",
5+
"seq": "enabled"
6+
}
7+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#include <gtest/gtest.h>
2+
#include <tuple>
3+
#include <vector>
4+
5+
#include "bruskova_v_char_frequency/common/include/common.hpp"
6+
#include "bruskova_v_char_frequency/mpi/include/ops_mpi.hpp"
7+
#include "bruskova_v_char_frequency/seq/include/ops_seq.hpp"
8+
#include "util/include/func_test_util.hpp"
9+
#include "util/include/util.hpp"
10+
11+
namespace bruskova_v_char_frequency {
12+
13+
class BruskovaVCharFrequencyFuncTests : public ppc::util::BaseRunFuncTests<InType, OutType, TestType> {
14+
public:
15+
BruskovaVCharFrequencyFuncTests() = default;
16+
17+
protected:
18+
void SetUp() override {
19+
TestType params = std::get<static_cast<std::size_t>(ppc::util::GTestParamIndex::kTestParams)>(GetParam());
20+
input_data_ = std::get<0>(params);
21+
expected_output_ = std::get<1>(params);
22+
}
23+
24+
bool CheckTestOutputData(OutType &output_data) final {
25+
return output_data == expected_output_;
26+
}
27+
28+
InType GetTestInputData() final {
29+
return input_data_;
30+
}
31+
32+
private:
33+
InType input_data_;
34+
OutType expected_output_ = 0;
35+
};
36+
37+
TEST_P(BruskovaVCharFrequencyFuncTests, TestCharFrequency) {
38+
ExecuteTest(GetParam());
39+
}
40+
41+
const std::vector<TestType> kTestParam = {
42+
std::make_tuple(std::make_pair("abracadabra", 'a'), 5),
43+
std::make_tuple(std::make_pair("hello world", 'o'), 2),
44+
std::make_tuple(std::make_pair("aaaaa", 'b'), 0),
45+
std::make_tuple(std::make_pair("", 'x'), 0),
46+
std::make_tuple(std::make_pair("z", 'z'), 1)
47+
};
48+
49+
const auto kTestTasksList =
50+
std::tuple_cat(ppc::util::AddFuncTask<BruskovaVCharFrequencyMPI, InType>(kTestParam, PPC_SETTINGS_bruskova_v_char_frequency),
51+
ppc::util::AddFuncTask<BruskovaVCharFrequencySEQ, InType>(kTestParam, PPC_SETTINGS_bruskova_v_char_frequency));
52+
53+
const auto kGtestValues = ppc::util::ExpandToValues(kTestTasksList);
54+
55+
INSTANTIATE_TEST_SUITE_P(CharFrequencyTests, BruskovaVCharFrequencyFuncTests, kGtestValues);
56+
57+
} // namespace bruskova_v_char_frequency
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#include <gtest/gtest.h>
2+
#include <string>
3+
4+
#include "bruskova_v_char_frequency/common/include/common.hpp"
5+
#include "bruskova_v_char_frequency/mpi/include/ops_mpi.hpp"
6+
#include "bruskova_v_char_frequency/seq/include/ops_seq.hpp"
7+
#include "util/include/perf_test_util.hpp"
8+
#include "util/include/util.hpp"
9+
10+
namespace bruskova_v_char_frequency {
11+
12+
class BruskovaVCharFrequencyPerfTests : public ppc::util::BaseRunPerfTests<InType, OutType> {
13+
private:
14+
InType input_data_;
15+
OutType expected_output_ = 0;
16+
17+
void SetUp() override {
18+
19+
std::string giant_str(20000000, 'b');
20+
for(size_t i = 0; i < giant_str.size(); i += 2) {
21+
giant_str[i] = 'a';
22+
}
23+
24+
input_data_ = std::make_pair(giant_str, 'a');
25+
expected_output_ = 10000000;
26+
}
27+
28+
bool CheckTestOutputData(OutType &output_data) final {
29+
return output_data == expected_output_;
30+
}
31+
32+
InType GetTestInputData() final {
33+
return input_data_;
34+
}
35+
36+
public:
37+
BruskovaVCharFrequencyPerfTests() = default;
38+
};
39+
40+
TEST_P(BruskovaVCharFrequencyPerfTests, RunPerfModes) {
41+
ExecuteTest(GetParam());
42+
}
43+
44+
const auto kAllPerfTasks =
45+
ppc::util::MakeAllPerfTasks<InType, BruskovaVCharFrequencyMPI, BruskovaVCharFrequencySEQ>(PPC_SETTINGS_bruskova_v_char_frequency);
46+
47+
const auto kGtestValues = ppc::util::TupleToGTestValues(kAllPerfTasks);
48+
49+
INSTANTIATE_TEST_SUITE_P(RunModeTests, BruskovaVCharFrequencyPerfTests, kGtestValues);
50+
51+
} // namespace bruskova_v_char_frequency

0 commit comments

Comments
 (0)