GCC Code Coverage Report


Directory: ./
File: tasks/votincev_d_alternating_values/mpi/src/ops_mpi.cpp
Date: 2025-12-11 15:42:14
Exec Total Coverage
Lines: 60 61 98.4%
Functions: 7 8 87.5%
Branches: 48 64 75.0%

Line Branch Exec Source
1 #include "votincev_d_alternating_values/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <algorithm>
6 #include <vector>
7
8 #include "votincev_d_alternating_values/common/include/common.hpp"
9
10 namespace votincev_d_alternating_values {
11
12
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 VotincevDAlternatingValuesMPI::VotincevDAlternatingValuesMPI(const InType &in) {
13 SetTypeOfTask(GetStaticTypeOfTask());
14
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 GetInput() = in;
15 20 GetOutput() = 0;
16 20 }
17
18 // проверка входных данных не нужна - пустой вектор тоже обрабатывается
19 20 bool VotincevDAlternatingValuesMPI::ValidationImpl() {
20 20 return true;
21 }
22
23 // нет ничего в PreProcessing
24 20 bool VotincevDAlternatingValuesMPI::PreProcessingImpl() {
25 20 return true;
26 }
27
28 // код MPI
29 20 bool VotincevDAlternatingValuesMPI::RunImpl() {
30 // получаю кол-во процессов
31 20 int process_n = 0;
32 20 MPI_Comm_size(MPI_COMM_WORLD, &process_n);
33
34 // получаю ранг процесса
35 20 int proc_rank = 0;
36 20 MPI_Comm_rank(MPI_COMM_WORLD, &proc_rank);
37
38 // вектор значений (его заполняет только 0й процесс)
39 20 std::vector<double> vect_data;
40
41
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
20 if (proc_rank != 0) {
42 10 GetOutput() = -1; // специальное значение
43 }
44
45 // 0й процесс получает данные
46
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
20 if (proc_rank == 0) {
47
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 vect_data = GetInput();
48
49 // если процессов больше, чем размер вектора — уменьшаем
50 // например: вектор = 2 элемента, а процессов запущено 4
51 10 process_n = std::min<int>(process_n, static_cast<int>(vect_data.size()));
52 }
53
54 // рассылаю всем "актуальное" число процессов
55 // т.к. его мог уменьшить процесс 0
56
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 MPI_Bcast(&process_n, 1, MPI_INT, 0, MPI_COMM_WORLD);
57
58 // если вектор пустой
59
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 2 times.
20 if (process_n == 0) {
60 return true;
61 }
62
63
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
18 if (proc_rank == 0) {
64
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 GetOutput() = ProcessMaster(process_n, vect_data); // работа 0-го процесса
65
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
9 } else if (proc_rank < process_n) {
66
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 ProcessWorker(); // работа процессов-работников
67 }
68
69 return true;
70 }
71
72 20 bool VotincevDAlternatingValuesMPI::PostProcessingImpl() {
73 20 return true;
74 }
75
76 // ============ дополнительные функции ============
77
78 // вспомогательная, if с такими условиями выглядит страшно
79 bool VotincevDAlternatingValuesMPI::IsSignChange(const double &a, const double &b) {
80
16/24
✓ Branch 0 taken 1233 times.
✓ Branch 1 taken 1210 times.
✓ Branch 2 taken 611 times.
✓ Branch 3 taken 622 times.
✓ Branch 4 taken 1210 times.
✓ Branch 5 taken 611 times.
✓ Branch 6 taken 620 times.
✓ Branch 7 taken 590 times.
✓ Branch 8 taken 1211 times.
✓ Branch 9 taken 1221 times.
✓ Branch 10 taken 588 times.
✓ Branch 11 taken 623 times.
✓ Branch 12 taken 1221 times.
✓ Branch 13 taken 588 times.
✓ Branch 14 taken 624 times.
✓ Branch 15 taken 597 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
4875 return ((a < 0 && b >= 0) || (a >= 0 && b < 0));
81 }
82
83 // работа 0-го процесса (главного)
84 9 int VotincevDAlternatingValuesMPI::ProcessMaster(int process_n, const std::vector<double> &vect_data) {
85 int all_swaps = 0;
86 9 const int n = static_cast<int>(vect_data.size());
87
88 // делим на части
89 9 const int base = n / process_n; // минимум на обработку
90 9 int remain = n % process_n; // остаток (распределяем между первыми)
91
92 int start_id = 0;
93
94 // распределяем работу между процессами-рабочими
95
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 9 times.
17 for (int worker = 1; worker < process_n; worker++) {
96 8 int part_size = base;
97
98 // если остались "лишние" элементы — раздаём по одному первым процессам
99
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 5 times.
8 if (remain > 0) {
100 3 part_size++;
101 3 remain--;
102 }
103
104 // каждому процессу (кроме последнего) даём ещё +1 элемент справа,
105 // чтобы проверить возможное чередование между границами блоков
106 8 part_size++;
107
108 // отправляем размер части
109 8 MPI_Send(&part_size, 1, MPI_INT, worker, 0, MPI_COMM_WORLD);
110
111 // отправляем сами данные
112 8 MPI_Send(vect_data.data() + start_id, part_size, MPI_DOUBLE, worker, 0, MPI_COMM_WORLD);
113
114 // сдвигаем начало следующего куска
115 8 start_id += part_size - 1; // -1 потому что правый сосед был добавлен
116 }
117
118 // 0й процесс считает пересесчения в своей части
119 int part_size = n - start_id;
120
2/2
✓ Branch 0 taken 2432 times.
✓ Branch 1 taken 9 times.
2441 for (int i = start_id + 1; i < start_id + part_size; i++) {
121
2/2
✓ Branch 0 taken 1211 times.
✓ Branch 1 taken 1221 times.
2432 if (IsSignChange(vect_data[i - 1], vect_data[i])) {
122 1247 all_swaps++;
123 }
124 }
125
126 // собираем ответы от всех рабочих процессов
127
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 9 times.
17 for (int worker = 1; worker < process_n; worker++) {
128 8 int tmp = 0;
129 8 MPI_Recv(&tmp, 1, MPI_INT, worker, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
130 8 all_swaps += tmp;
131 }
132
133 9 return all_swaps;
134 }
135
136 // работа процессов 1,2, ...
137 8 void VotincevDAlternatingValuesMPI::ProcessWorker() {
138 8 int part_size = 0;
139
140 // получаю, сколько элементов прислал процесс 0
141 8 MPI_Recv(&part_size, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
142
143 // выделяю память под кусок
144 8 std::vector<double> data(part_size);
145
146 // получаю свою часть вектора
147
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 MPI_Recv(data.data(), part_size, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
148
149 8 int swap_count = 0;
150
151 // считаю чередования знаков
152
2/2
✓ Branch 0 taken 2443 times.
✓ Branch 1 taken 8 times.
2451 for (int i = 1; i < part_size; i++) {
153
2/2
✓ Branch 0 taken 1233 times.
✓ Branch 1 taken 1210 times.
2443 if (IsSignChange(data[i - 1], data[i])) {
154 1242 swap_count++;
155 }
156 }
157
158 // отправляю результат назад 0-му процессу
159
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 MPI_Send(&swap_count, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
160 8 }
161
162 } // namespace votincev_d_alternating_values
163