GCC Code Coverage Report


Directory: ./
File: tasks/smyshlaev_a_sle_cg_seq/all/src/ops_all.cpp
Date: 2026-05-11 08:26:31
Exec Total Coverage
Lines: 121 126 96.0%
Functions: 10 11 90.9%
Branches: 88 142 62.0%

Line Branch Exec Source
1 #include "smyshlaev_a_sle_cg_seq/all/include/ops_all.hpp"
2
3 #include <mpi.h>
4 #include <omp.h>
5
6 #include <algorithm>
7 #include <cmath>
8 #include <cstddef>
9 #include <vector>
10
11 #include "smyshlaev_a_sle_cg_seq/common/include/common.hpp"
12 #include "util/include/util.hpp"
13
14 namespace smyshlaev_a_sle_cg_seq {
15
16
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 SmyshlaevASleCgTaskALL::SmyshlaevASleCgTaskALL(const InType &in) : BaseTask() {
17 SetTypeOfTask(GetStaticTypeOfTask());
18 8 int rank = 0;
19
2/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
8 if (ppc::util::IsUnderMpirun()) {
20
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
21 }
22
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (rank == 0) {
23 GetInput() = in;
24 }
25 8 }
26
27 8 bool SmyshlaevASleCgTaskALL::ValidationImpl() {
28 8 int rank = 0;
29
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 if (ppc::util::IsUnderMpirun()) {
30 8 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
31 }
32
33 8 int error = 0;
34
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (rank == 0) {
35 const auto &a = GetInput().A;
36 const auto &b = GetInput().b;
37
4/8
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 4 times.
4 if (a.empty() || b.empty() || a.size() != b.size() || a.size() != a[0].size()) {
38 error = 1;
39 }
40 }
41
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 if (ppc::util::IsUnderMpirun()) {
42 8 MPI_Bcast(&error, 1, MPI_INT, 0, MPI_COMM_WORLD);
43 }
44 8 return error == 0;
45 }
46
47 8 bool SmyshlaevASleCgTaskALL::PreProcessingImpl() {
48 8 int rank = 0;
49
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 if (ppc::util::IsUnderMpirun()) {
50 8 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
51 }
52
53
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (rank == 0) {
54 const auto &a = GetInput().A;
55 4 n_ = static_cast<int>(a.size());
56 4 flat_A_.resize(static_cast<size_t>(n_) * n_);
57
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 4 times.
15 for (int i = 0; i < n_; ++i) {
58
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 11 times.
44 for (int j = 0; j < n_; ++j) {
59 33 flat_A_[(static_cast<size_t>(i) * n_) + j] = a[i][j];
60 }
61 }
62 }
63 8 return true;
64 }
65
66 8 void SmyshlaevASleCgTaskALL::DistributeInitialData(int rank, bool is_mpi, std::vector<double> &b) {
67
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (is_mpi) {
68 8 MPI_Bcast(&n_, 1, MPI_INT, 0, MPI_COMM_WORLD);
69
70
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (n_ > 0) {
71
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (rank != 0) {
72 4 b.resize(n_);
73 4 flat_A_.resize(static_cast<size_t>(n_) * n_);
74 }
75 8 MPI_Bcast(flat_A_.data(), static_cast<int>(flat_A_.size()), MPI_DOUBLE, 0, MPI_COMM_WORLD);
76 8 MPI_Bcast(b.data(), n_, MPI_DOUBLE, 0, MPI_COMM_WORLD);
77 }
78 }
79 8 }
80
81 24 double SmyshlaevASleCgTaskALL::ComputeDotProductAll(const std::vector<double> &v1, const std::vector<double> &v2,
82 int start, int end, bool is_mpi) {
83 24 double local_sum = 0.0;
84 24 #pragma omp parallel for default(none) shared(start, end, v1, v2) reduction(+ : local_sum)
85 for (int i = start; i < end; ++i) {
86 local_sum += v1[i] * v2[i];
87 }
88 24 double global_sum = local_sum;
89
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 if (is_mpi) {
90 24 MPI_Allreduce(&local_sum, &global_sum, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
91 }
92 24 return global_sum;
93 }
94
95 void SmyshlaevASleCgTaskALL::ComputeApAll(const std::vector<double> &p, std::vector<double> &ap, int start,
96 int end) const {
97 16 const auto &m = flat_A_;
98 16 const int l_n = n_;
99
100 16 #pragma omp parallel for default(none) shared(start, end, p, ap, l_n, m)
101 for (int i = start; i < end; ++i) {
102 double sum = 0.0;
103 for (int j = 0; j < l_n; ++j) {
104 sum += m[(static_cast<size_t>(i) * l_n) + j] * p[j];
105 }
106 ap[i] = sum;
107 }
108 }
109
110 16 double SmyshlaevASleCgTaskALL::UpdateSolutionAndResidual(std::vector<double> &x, std::vector<double> &r,
111 const std::vector<double> &p, const std::vector<double> &ap,
112 double alpha, int start, int end, bool is_mpi) {
113 16 double local_rs_new = 0.0;
114 16 #pragma omp parallel for default(none) shared(start, end, x, p, r, ap, alpha) reduction(+ : local_rs_new)
115 for (int i = start; i < end; ++i) {
116 x[i] += alpha * p[i];
117 r[i] -= alpha * ap[i];
118 local_rs_new += r[i] * r[i];
119 }
120 16 double global_rs_new = local_rs_new;
121
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 if (is_mpi) {
122 16 MPI_Allreduce(&local_rs_new, &global_rs_new, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
123 }
124 16 return global_rs_new;
125 }
126
127 8 void SmyshlaevASleCgTaskALL::SyncVectorP(std::vector<double> &p, int size, bool is_mpi) const {
128
2/4
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
8 if (!is_mpi || n_ <= 0) {
129 return;
130 }
131 8 std::vector<int> counts(size);
132
1/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
8 std::vector<int> displs(size);
133
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 8 times.
24 for (int i = 0; i < size; ++i) {
134
4/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 8 times.
28 counts[i] = (n_ / size) + (i < (n_ % size) ? 1 : 0);
135
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
16 displs[i] = (i == 0) ? 0 : displs[i - 1] + counts[i - 1];
136 }
137
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 MPI_Allgatherv(MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, p.data(), counts.data(), displs.data(), MPI_DOUBLE,
138 MPI_COMM_WORLD);
139 }
140
141 8 void SmyshlaevASleCgTaskALL::FinalGather(std::vector<double> &x, int start, int count, int size, bool is_mpi) {
142
2/4
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
8 if (is_mpi && n_ > 0) {
143 8 std::vector<int> counts(size);
144
1/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
8 std::vector<int> displs(size);
145
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 8 times.
24 for (int i = 0; i < size; ++i) {
146
4/4
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 8 times.
30 counts[i] = (n_ / size) + (i < (n_ % size) ? 1 : 0);
147
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
16 displs[i] = (i == 0) ? 0 : displs[i - 1] + counts[i - 1];
148 }
149 8 int rank = 0;
150
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
151
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (rank == 0) {
152
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 MPI_Gatherv(MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, x.data(), counts.data(), displs.data(), MPI_DOUBLE, 0,
153 MPI_COMM_WORLD);
154
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 res_ = x;
155 } else {
156
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 MPI_Gatherv(x.data() + start, count, MPI_DOUBLE, nullptr, nullptr, nullptr, MPI_DOUBLE, 0, MPI_COMM_WORLD);
157 }
158 8 } else {
159 res_ = x;
160 }
161 8 }
162
163 8 bool SmyshlaevASleCgTaskALL::RunImpl() {
164 8 int rank = 0;
165 8 int size = 1;
166 8 bool is_mpi = ppc::util::IsUnderMpirun();
167
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (is_mpi) {
168 8 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
169 8 MPI_Comm_size(MPI_COMM_WORLD, &size);
170 }
171
172 8 std::vector<double> b_vec;
173
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (rank == 0) {
174
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 b_vec = GetInput().b;
175 }
176
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 DistributeInitialData(rank, is_mpi, b_vec);
177
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (n_ == 0) {
178 return true;
179 }
180
181 int l_n = n_;
182
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1 times.
8 int start = (rank * (l_n / size)) + std::min(rank, l_n % size);
183
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1 times.
8 int count = (l_n / size) + (rank < (l_n % size) ? 1 : 0);
184 8 int end = start + count;
185
186
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 std::vector<double> r = b_vec;
187
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 std::vector<double> p = r;
188
1/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
8 std::vector<double> x(l_n, 0.0);
189
1/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
8 std::vector<double> ap(l_n, 0.0);
190
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 omp_set_num_threads(ppc::util::GetNumThreads());
191
192
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 double rs_old = ComputeDotProductAll(r, r, start, end, is_mpi);
193 const double eps_sq = 1e-18;
194
195
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 for (int iter = 0; iter < l_n * 2; ++iter) {
196
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 if (rs_old < eps_sq) {
197 break;
198 }
199
200 ComputeApAll(p, ap, start, end);
201
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 double p_ap = ComputeDotProductAll(p, ap, start, end, is_mpi);
202
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 if (std::abs(p_ap) < 1e-15) {
203 break;
204 }
205
206
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 double rs_new = UpdateSolutionAndResidual(x, r, p, ap, rs_old / p_ap, start, end, is_mpi);
207
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
16 if (rs_new < eps_sq) {
208 break;
209 }
210
211 8 double beta = rs_new / rs_old;
212 8 #pragma omp parallel for default(none) shared(start, end, p, r, beta)
213 for (int i = start; i < end; ++i) {
214 p[i] = r[i] + (beta * p[i]);
215 }
216
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 SyncVectorP(p, size, is_mpi);
217 rs_old = rs_new;
218 }
219
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 FinalGather(x, start, count, size, is_mpi);
220 return true;
221 }
222
223 8 bool SmyshlaevASleCgTaskALL::PostProcessingImpl() {
224 8 int rank = 0;
225 8 bool is_mpi = ppc::util::IsUnderMpirun();
226
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (is_mpi) {
227 8 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
228 8 MPI_Bcast(&n_, 1, MPI_INT, 0, MPI_COMM_WORLD);
229
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (n_ > 0) {
230
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (rank != 0) {
231 4 res_.resize(n_);
232 }
233 8 MPI_Bcast(res_.data(), n_, MPI_DOUBLE, 0, MPI_COMM_WORLD);
234 }
235 }
236
237
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
8 if (rank == 0 || is_mpi) {
238 8 GetOutput() = res_;
239 }
240 8 return true;
241 }
242
243 } // namespace smyshlaev_a_sle_cg_seq
244