GCC Code Coverage Report


Directory: ./
File: tasks/borunov_v_complex_ccs/all/src/ops_all.cpp
Date: 2026-06-04 20:25:32
Exec Total Coverage
Lines: 94 95 98.9%
Functions: 11 11 100.0%
Branches: 64 96 66.7%

Line Branch Exec Source
1 #include "borunov_v_complex_ccs/all/include/ops_all.hpp"
2
3 #include <omp.h>
4 #include <tbb/tbb.h>
5
6 #include <cmath>
7 #include <complex>
8 #include <cstddef>
9 #include <vector>
10
11 #include "borunov_v_complex_ccs/common/include/common.hpp"
12 #include "util/include/util.hpp"
13
14 namespace borunov_v_complex_ccs {
15
16
1/2
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 BorunovVComplexCcsALL::BorunovVComplexCcsALL(const InType &in) {
17 SetTypeOfTask(GetStaticTypeOfTask());
18 GetInput() = in;
19
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 GetOutput().resize(1);
20 6 }
21
22 6 bool BorunovVComplexCcsALL::ValidationImpl() {
23 const auto &a = GetInput().first;
24 const auto &b = GetInput().second;
25
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (a.num_cols != b.num_rows) {
26 return false;
27 }
28
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (a.col_ptrs.size() != static_cast<std::size_t>(a.num_cols) + 1 ||
29
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 b.col_ptrs.size() != static_cast<std::size_t>(b.num_cols) + 1) {
30 return false;
31 }
32 return true;
33 }
34
35 6 bool BorunovVComplexCcsALL::PreProcessingImpl() {
36 const auto &a = GetInput().first;
37 const auto &b = GetInput().second;
38 auto &c = GetOutput()[0];
39
40 6 c.num_rows = a.num_rows;
41 6 c.num_cols = b.num_cols;
42
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 c.col_ptrs.assign(c.num_cols + 1, 0);
43 c.values.clear();
44 c.row_indices.clear();
45
46 6 return true;
47 }
48
49 namespace {
50
51 80 void CustomShellSort(std::vector<int> &touched) {
52
2/2
✓ Branch 0 taken 200 times.
✓ Branch 1 taken 80 times.
280 for (std::size_t gap = touched.size() / 2; gap > 0; gap /= 2) {
53
2/2
✓ Branch 0 taken 1408 times.
✓ Branch 1 taken 200 times.
1608 for (std::size_t i = gap; i < touched.size(); ++i) {
54 1408 const int temp = touched[i];
55 std::size_t j = i;
56
4/4
✓ Branch 0 taken 1816 times.
✓ Branch 1 taken 216 times.
✓ Branch 2 taken 624 times.
✓ Branch 3 taken 1192 times.
2032 while (j >= gap && touched[j - gap] > temp) {
57 624 touched[j] = touched[j - gap];
58 j -= gap;
59 }
60 1408 touched[j] = temp;
61 }
62 }
63 80 }
64
65
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 26 times.
80 void ProcessColumn(int j, const SparseMatrix &a, const SparseMatrix &b, int local_j,
66 std::vector<std::complex<double>> &acc, std::vector<int> &marker, std::vector<int> &touched,
67 std::vector<std::complex<double>> &t_vals, std::vector<int> &t_rows, std::vector<int> &t_col_nnz) {
68 touched.clear();
69
70
2/2
✓ Branch 0 taken 308 times.
✓ Branch 1 taken 80 times.
388 for (int bk = b.col_ptrs[j]; bk < b.col_ptrs[j + 1]; ++bk) {
71 308 const int p = b.row_indices[bk];
72 308 const std::complex<double> bval = b.values[bk];
73
74
2/2
✓ Branch 0 taken 946 times.
✓ Branch 1 taken 308 times.
1254 for (int ak = a.col_ptrs[p]; ak < a.col_ptrs[p + 1]; ++ak) {
75
2/2
✓ Branch 0 taken 668 times.
✓ Branch 1 taken 278 times.
946 const int i = a.row_indices[ak];
76
2/2
✓ Branch 0 taken 668 times.
✓ Branch 1 taken 278 times.
946 acc[i] += a.values[ak] * bval;
77
2/2
✓ Branch 0 taken 668 times.
✓ Branch 1 taken 278 times.
946 if (marker[i] != j) {
78
1/2
✓ Branch 0 taken 668 times.
✗ Branch 1 not taken.
668 marker[i] = j;
79 touched.push_back(i);
80 }
81 }
82 }
83
84 80 CustomShellSort(touched);
85
86
2/2
✓ Branch 0 taken 668 times.
✓ Branch 1 taken 80 times.
748 for (int i : touched) {
87
1/2
✓ Branch 0 taken 668 times.
✗ Branch 1 not taken.
668 if (std::abs(acc[i]) > 1e-9) {
88 t_vals.push_back(acc[i]);
89 t_rows.push_back(i);
90 668 ++t_col_nnz[local_j];
91 }
92 668 acc[i] = {0.0, 0.0};
93 }
94 80 }
95
96 24 void ComputeTaskRange(int start_col, int end_col, int tid, const SparseMatrix &a, const SparseMatrix &b,
97 std::vector<std::vector<std::complex<double>>> &vals, std::vector<std::vector<int>> &rows,
98 std::vector<std::vector<int>> &col_nnz) {
99 24 const int cols_count = end_col - start_col;
100 24 col_nnz[tid].assign(cols_count, 0);
101
102 24 std::vector<std::complex<double>> acc(a.num_rows, {0.0, 0.0});
103
1/4
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
24 std::vector<int> marker(a.num_rows, -1);
104 24 std::vector<int> touched;
105
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
24 touched.reserve(static_cast<std::size_t>(a.num_rows));
106
107
2/2
✓ Branch 0 taken 80 times.
✓ Branch 1 taken 24 times.
104 for (int j = start_col; j < end_col; ++j) {
108
1/2
✓ Branch 1 taken 80 times.
✗ Branch 2 not taken.
80 ProcessColumn(j, a, b, j - start_col, acc, marker, touched, vals[tid], rows[tid], col_nnz[tid]);
109 }
110 24 }
111
112 12 void FillColumnPointers(int start_col, int end_col, int num_threads, const std::vector<std::vector<int>> &col_nnz,
113 std::vector<int> &col_ptrs) {
114 12 const int range = end_col - start_col;
115
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 12 times.
36 for (int tid = 0; tid < num_threads; ++tid) {
116 24 const int tid_start_col = start_col + ((range * tid) / num_threads);
117 24 const int tid_end_col = start_col + ((range * (tid + 1)) / num_threads);
118
2/2
✓ Branch 0 taken 80 times.
✓ Branch 1 taken 24 times.
104 for (int j = tid_start_col; j < tid_end_col; ++j) {
119 80 col_ptrs[j + 1] = col_ptrs[j] + col_nnz[tid][j - tid_start_col];
120 }
121 }
122 12 }
123
124 } // namespace
125
126 6 bool BorunovVComplexCcsALL::RunImpl() {
127 6 const auto &a = GetInput().first;
128 6 const auto &b = GetInput().second;
129 auto &c = GetOutput()[0];
130
131 6 const int num_threads = ppc::util::GetNumThreads();
132 6 const int num_cols = b.num_cols;
133
134
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (num_cols == 0) {
135 return true;
136 }
137
138 6 const int half_cols = num_cols / 2;
139
140 6 std::vector<std::vector<std::complex<double>>> omp_vals(num_threads);
141
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 std::vector<std::vector<int>> omp_rows(num_threads);
142
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 std::vector<std::vector<int>> omp_col_nnz(num_threads);
143
144
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (half_cols > 0) {
145 6 #pragma omp parallel num_threads(num_threads) default(none) \
146 shared(a, b, half_cols, num_threads, omp_vals, omp_rows, omp_col_nnz)
147 {
148 const int tid = omp_get_thread_num();
149 const int total_threads = omp_get_num_threads();
150 const int tid_start_col = (half_cols * tid) / total_threads;
151 const int tid_end_col = (half_cols * (tid + 1)) / total_threads;
152 ComputeTaskRange(tid_start_col, tid_end_col, tid, a, b, omp_vals, omp_rows, omp_col_nnz);
153 }
154 }
155
156 6 FillColumnPointers(0, half_cols, num_threads, omp_col_nnz, c.col_ptrs);
157
158
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 std::vector<std::vector<std::complex<double>>> tbb_vals(num_threads);
159
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 std::vector<std::vector<int>> tbb_rows(num_threads);
160
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 std::vector<std::vector<int>> tbb_col_nnz(num_threads);
161
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (num_cols > half_cols) {
162
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 tbb::task_arena arena(num_threads);
163
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 arena.execute([&] {
164 18 tbb::parallel_for(tbb::blocked_range<int>(0, num_threads, 1), [&](const tbb::blocked_range<int> &r) {
165
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 for (int tid = r.begin(); tid < r.end(); ++tid) {
166 12 const int tid_start_col = half_cols + (((num_cols - half_cols) * tid) / num_threads);
167 12 const int tid_end_col = half_cols + (((num_cols - half_cols) * (tid + 1)) / num_threads);
168 12 ComputeTaskRange(tid_start_col, tid_end_col, tid, a, b, tbb_vals, tbb_rows, tbb_col_nnz);
169 }
170 18 }, tbb::static_partitioner());
171 6 });
172 }
173
174 6 FillColumnPointers(half_cols, num_cols, num_threads, tbb_col_nnz, c.col_ptrs);
175
176
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 int total_nnz = c.col_ptrs[num_cols];
177
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 c.values.reserve(total_nnz);
178
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 c.row_indices.reserve(total_nnz);
179
180
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (half_cols > 0) {
181
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 6 times.
18 for (int tid = 0; tid < num_threads; ++tid) {
182
2/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
12 c.values.insert(c.values.end(), omp_vals[tid].begin(), omp_vals[tid].end());
183 12 c.row_indices.insert(c.row_indices.end(), omp_rows[tid].begin(), omp_rows[tid].end());
184 }
185 }
186
187
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (num_cols > half_cols) {
188
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 6 times.
18 for (int tid = 0; tid < num_threads; ++tid) {
189
2/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
12 c.values.insert(c.values.end(), tbb_vals[tid].begin(), tbb_vals[tid].end());
190 12 c.row_indices.insert(c.row_indices.end(), tbb_rows[tid].begin(), tbb_rows[tid].end());
191 }
192 }
193
194 return true;
195 6 }
196
197 6 bool BorunovVComplexCcsALL::PostProcessingImpl() {
198 6 return true;
199 }
200
201 } // namespace borunov_v_complex_ccs
202