GCC Code Coverage Report


Directory: ./
File: tasks/ilin_a_alternations_signs_of_val_vec/mpi/src/ops_mpi.cpp
Date: 2026-01-27 01:59:34
Exec Total Coverage
Lines: 88 90 97.8%
Functions: 9 10 90.0%
Branches: 60 94 63.8%

Line Branch Exec Source
1 #include "ilin_a_alternations_signs_of_val_vec/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <algorithm>
6 #include <cstddef>
7 #include <vector>
8
9 #include "ilin_a_alternations_signs_of_val_vec/common/include/common.hpp"
10
11 namespace ilin_a_alternations_signs_of_val_vec {
12
13 namespace {
14 constexpr int kRootRank = 0;
15 constexpr int kMinDataSize = 2;
16 } // namespace
17
18
1/2
✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
44 IlinAAlternationsSignsOfValVecMPI::IlinAAlternationsSignsOfValVecMPI(const InType &in) {
19 SetTypeOfTask(GetStaticTypeOfTask());
20
1/2
✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
44 GetInput() = in;
21 44 GetOutput() = 0;
22 44 }
23
24 44 bool IlinAAlternationsSignsOfValVecMPI::ValidationImpl() {
25 44 return GetOutput() == 0;
26 }
27
28 44 bool IlinAAlternationsSignsOfValVecMPI::PreProcessingImpl() {
29 44 return true;
30 }
31
32
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 4 times.
36 int IlinAAlternationsSignsOfValVecMPI::CountLocalSignChanges(const std::vector<int> &segment) {
33 int count = 0;
34 const size_t segment_size = segment.size();
35
36
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 4 times.
36 if (segment_size < kMinDataSize) {
37 return count;
38 }
39
40
2/2
✓ Branch 0 taken 2086 times.
✓ Branch 1 taken 32 times.
2118 for (size_t index = 0; index < segment_size - 1; ++index) {
41 2086 const bool is_negative_current = segment[index] < 0;
42 2086 const bool is_negative_next = segment[index + 1] < 0;
43
2/2
✓ Branch 0 taken 1388 times.
✓ Branch 1 taken 698 times.
2086 if (is_negative_current != is_negative_next) {
44 1388 ++count;
45 }
46 }
47 return count;
48 }
49
50 36 BoundaryInfo IlinAAlternationsSignsOfValVecMPI::GatherEdgeValues(const std::vector<int> &segment) {
51
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 BoundaryInfo info;
52
53
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 const int left_val = segment.empty() ? 0 : segment.front();
54
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 const int right_val = segment.empty() ? 0 : segment.back();
55
56 36 int total_processes = 0;
57
1/2
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
36 MPI_Comm_size(MPI_COMM_WORLD, &total_processes);
58
59 36 const size_t edges_size = static_cast<size_t>(2) * static_cast<size_t>(total_processes);
60
1/2
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
36 info.all_edges.resize(edges_size);
61
62
1/2
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
36 MPI_Gather(&left_val, 1, MPI_INT, info.all_edges.data(), 1, MPI_INT, kRootRank, MPI_COMM_WORLD);
63
1/2
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
36 MPI_Gather(&right_val, 1, MPI_INT, info.all_edges.data() + static_cast<size_t>(total_processes), 1, MPI_INT,
64 kRootRank, MPI_COMM_WORLD);
65
66 36 return info;
67 }
68
69 18 int IlinAAlternationsSignsOfValVecMPI::CountEdgeAlternations(const BoundaryInfo &edges, const int total_processes) {
70 int count = 0;
71
72
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 if (total_processes <= 1) {
73 return count;
74 }
75
76
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 18 times.
36 for (int process_index = 0; process_index < total_processes - 1; ++process_index) {
77 18 const size_t right_index = static_cast<size_t>(total_processes) + static_cast<size_t>(process_index);
78
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 13 times.
18 const size_t left_index = static_cast<size_t>(process_index) + 1;
79 18 const int right_edge = edges.all_edges[right_index];
80 18 const int left_edge = edges.all_edges[left_index];
81 const bool is_negative_right = right_edge < 0;
82 const bool is_negative_left = left_edge < 0;
83
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 13 times.
18 if (is_negative_right != is_negative_left) {
84 5 ++count;
85 }
86 }
87 return count;
88 }
89
90 void IlinAAlternationsSignsOfValVecMPI::CalculateDistribution(const int data_size, const int world_size,
91 std::vector<int> &counts, std::vector<int> &offsets) {
92 36 const int base_size = data_size / world_size;
93 36 const int remainder = data_size % world_size;
94 int current_offset = 0;
95
96
4/6
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 36 times.
✓ Branch 3 taken 18 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
108 for (int process_index = 0; process_index < world_size; ++process_index) {
97
4/6
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 34 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
140 counts[process_index] = base_size + (process_index < remainder ? 1 : 0);
98 72 offsets[process_index] = current_offset;
99 72 current_offset += counts[process_index];
100 }
101 }
102
103 36 void IlinAAlternationsSignsOfValVecMPI::DistributeData(const std::vector<int> &global_data,
104 std::vector<int> &local_data, const int world_rank,
105 const int world_size) {
106
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 18 times.
36 if (world_rank == kRootRank) {
107 18 std::vector<int> counts(world_size);
108
1/4
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
18 std::vector<int> offsets(world_size);
109 18 CalculateDistribution(static_cast<int>(global_data.size()), world_size, counts, offsets);
110
111
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 if (counts[kRootRank] > 0) {
112 18 const auto start_iterator = global_data.begin() + static_cast<ptrdiff_t>(offsets[kRootRank]);
113 const auto end_iterator = start_iterator + static_cast<ptrdiff_t>(counts[kRootRank]);
114 18 std::copy(start_iterator, end_iterator, local_data.begin());
115 }
116
117
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 18 times.
54 for (int process_index = 0; process_index < world_size; ++process_index) {
118
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 18 times.
36 if (process_index == kRootRank) {
119 18 continue;
120 }
121
122
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 const int send_size = counts[process_index];
123
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 if (send_size > 0) {
124 18 const int *send_data = global_data.data() + offsets[process_index];
125
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 MPI_Send(send_data, send_size, MPI_INT, process_index, 0, MPI_COMM_WORLD);
126 }
127 }
128 } else {
129
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 if (!local_data.empty()) {
130 18 MPI_Recv(local_data.data(), static_cast<int>(local_data.size()), MPI_INT, kRootRank, 0, MPI_COMM_WORLD,
131 MPI_STATUS_IGNORE);
132 }
133 }
134 36 }
135
136 44 bool IlinAAlternationsSignsOfValVecMPI::RunImpl() {
137 44 int world_rank = 0;
138 44 int world_size = 0;
139 44 MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
140 44 MPI_Comm_size(MPI_COMM_WORLD, &world_size);
141
142 const std::vector<int> &input_data = GetInput();
143 44 int data_size = static_cast<int>(input_data.size());
144 44 MPI_Bcast(&data_size, 1, MPI_INT, kRootRank, MPI_COMM_WORLD);
145
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 36 times.
44 if (data_size < kMinDataSize) {
146
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (world_rank == kRootRank) {
147 4 GetOutput() = 0;
148 }
149 8 return true;
150 }
151 36 std::vector<int> counts(world_size);
152
1/4
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
36 std::vector<int> offsets(world_size);
153
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 18 times.
36 if (world_rank == kRootRank) {
154 18 CalculateDistribution(data_size, world_size, counts, offsets);
155 }
156
1/2
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
36 MPI_Bcast(counts.data(), world_size, MPI_INT, kRootRank, MPI_COMM_WORLD);
157
1/2
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
36 MPI_Bcast(offsets.data(), world_size, MPI_INT, kRootRank, MPI_COMM_WORLD);
158
1/2
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
36 const int local_size = counts[world_rank];
159
1/4
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
36 std::vector<int> local_data(static_cast<size_t>(local_size));
160
1/2
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
36 DistributeData(input_data, local_data, world_rank, world_size);
161 36 const int local_changes = CountLocalSignChanges(local_data);
162
1/2
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
36 BoundaryInfo edges = GatherEdgeValues(local_data);
163 36 int total_changes = 0;
164
1/2
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
36 MPI_Reduce(&local_changes, &total_changes, 1, MPI_INT, MPI_SUM, kRootRank, MPI_COMM_WORLD);
165
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 18 times.
36 if (world_rank == kRootRank) {
166 18 total_changes += CountEdgeAlternations(edges, world_size);
167 18 GetOutput() = total_changes;
168 }
169
170 return true;
171 }
172
173 44 bool IlinAAlternationsSignsOfValVecMPI::PostProcessingImpl() {
174 44 return true;
175 }
176
177 } // namespace ilin_a_alternations_signs_of_val_vec
178