GCC Code Coverage Report


Directory: ./
File: tasks/kurpiakov_a_sp_comp_mat_mul/stl/src/ops_stl.cpp
Date: 2026-06-04 20:25:32
Exec Total Coverage
Lines: 71 72 98.6%
Functions: 11 11 100.0%
Branches: 62 90 68.9%

Line Branch Exec Source
1 #include "kurpiakov_a_sp_comp_mat_mul/stl/include/ops_stl.hpp"
2
3 #include <algorithm>
4 #include <atomic>
5 #include <cstddef>
6 #include <thread>
7 #include <utility>
8 #include <vector>
9
10 #include "kurpiakov_a_sp_comp_mat_mul/common/include/common.hpp"
11 #include "util/include/util.hpp"
12
13 namespace kurpiakov_a_sp_comp_mat_mul {
14
15 namespace {
16
17 160 bool ValidateCSR(const SparseMatrix &m) {
18
2/4
✓ Branch 0 taken 160 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 160 times.
160 if (m.rows <= 0 || m.cols <= 0) {
19 return false;
20 }
21
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 160 times.
160 if (static_cast<int>(m.row_ptr.size()) != m.rows + 1) {
22 return false;
23 }
24
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 160 times.
160 if (m.row_ptr[0] != 0) {
25 return false;
26 }
27
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 160 times.
160 if (std::cmp_not_equal(m.values.size(), m.row_ptr[m.rows])) {
28 return false;
29 }
30
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 160 times.
160 if (m.col_indices.size() != m.values.size()) {
31 return false;
32 }
33
2/2
✓ Branch 0 taken 312 times.
✓ Branch 1 taken 160 times.
472 for (int i = 0; i < m.rows; ++i) {
34
2/2
✓ Branch 0 taken 320 times.
✓ Branch 1 taken 312 times.
632 for (int j = m.row_ptr[i]; j < m.row_ptr[i + 1]; ++j) {
35
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 320 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 320 times.
320 if (m.col_indices[j] < 0 || m.col_indices[j] >= m.cols) {
36 return false;
37 }
38 }
39 }
40 return true;
41 }
42
43 struct ThreadLocalRowState {
44
1/4
✓ Branch 2 taken 126 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
126 explicit ThreadLocalRowState(int cols) : row_acc(cols), row_used(cols, 0) {}
45
46 std::vector<ComplexD> row_acc;
47 std::vector<char> row_used;
48 std::vector<int> used_cols;
49 };
50
51
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 104 times.
144 void MultiplySingleRow(const SparseMatrix &a, const SparseMatrix &b, int row_idx, ThreadLocalRowState &state,
52 std::vector<ComplexD> &out_values, std::vector<int> &out_cols) {
53 state.used_cols.clear();
54
55
2/2
✓ Branch 0 taken 160 times.
✓ Branch 1 taken 144 times.
304 for (int ja = a.row_ptr[row_idx]; ja < a.row_ptr[row_idx + 1]; ++ja) {
56 160 const int ka = a.col_indices[ja];
57 const ComplexD &a_val = a.values[ja];
58
59
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 160 times.
352 for (int jb = b.row_ptr[ka]; jb < b.row_ptr[ka + 1]; ++jb) {
60
2/2
✓ Branch 0 taken 136 times.
✓ Branch 1 taken 56 times.
192 const int cb = b.col_indices[jb];
61 const ComplexD &b_val = b.values[jb];
62
63
2/2
✓ Branch 0 taken 136 times.
✓ Branch 1 taken 56 times.
192 if (state.row_used[cb] == 0) {
64
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 88 times.
136 state.row_used[cb] = 1;
65 136 state.row_acc[cb] = ComplexD();
66
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 88 times.
136 state.used_cols.push_back(cb);
67 }
68
69 state.row_acc[cb] += a_val * b_val;
70 }
71 }
72
73 std::ranges::sort(state.used_cols);
74
75 out_values.clear();
76 out_cols.clear();
77 144 out_values.reserve(state.used_cols.size());
78 144 out_cols.reserve(state.used_cols.size());
79
80
2/2
✓ Branch 0 taken 136 times.
✓ Branch 1 taken 144 times.
280 for (int col : state.used_cols) {
81
1/2
✓ Branch 0 taken 136 times.
✗ Branch 1 not taken.
136 out_values.push_back(state.row_acc[col]);
82 out_cols.push_back(col);
83 136 state.row_used[col] = 0;
84 }
85 144 }
86
87 80 void ComputeRowsWithThreads(const SparseMatrix &a, const SparseMatrix &b, int rows, int num_threads,
88 std::vector<std::vector<ComplexD>> &row_values, std::vector<std::vector<int>> &row_cols) {
89 80 std::atomic<int> next_row(0);
90 80 std::vector<std::thread> workers;
91
1/2
✓ Branch 1 taken 80 times.
✗ Branch 2 not taken.
80 workers.reserve(num_threads);
92
93
2/2
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 80 times.
206 for (int thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
94
1/2
✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
126 workers.emplace_back([&]() {
95 126 ThreadLocalRowState state(b.cols);
96
97 while (true) {
98
2/2
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 126 times.
270 const int row_idx = next_row.fetch_add(1, std::memory_order_relaxed);
99
2/2
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 126 times.
270 if (row_idx >= rows) {
100 break;
101 }
102
103
1/2
✓ Branch 1 taken 144 times.
✗ Branch 2 not taken.
144 MultiplySingleRow(a, b, row_idx, state, row_values[row_idx], row_cols[row_idx]);
104 }
105 126 });
106 }
107
108
2/2
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 80 times.
206 for (auto &worker : workers) {
109
1/2
✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
126 worker.join();
110 }
111 80 }
112
113 80 SparseMatrix BuildResult(int rows, int cols, const std::vector<std::vector<ComplexD>> &row_values,
114 const std::vector<std::vector<int>> &row_cols) {
115 80 SparseMatrix result(rows, cols);
116
117 std::size_t total_nnz = 0;
118
2/2
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 80 times.
224 for (int i = 0; i < rows; ++i) {
119 144 total_nnz += row_values[i].size();
120 }
121
122
1/2
✓ Branch 1 taken 80 times.
✗ Branch 2 not taken.
80 result.values.reserve(total_nnz);
123
1/2
✓ Branch 1 taken 80 times.
✗ Branch 2 not taken.
80 result.col_indices.reserve(total_nnz);
124
125
2/2
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 80 times.
224 for (int i = 0; i < rows; ++i) {
126
2/4
✓ Branch 1 taken 144 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 144 times.
✗ Branch 5 not taken.
144 result.values.insert(result.values.end(), row_values[i].begin(), row_values[i].end());
127 144 result.col_indices.insert(result.col_indices.end(), row_cols[i].begin(), row_cols[i].end());
128 144 result.row_ptr[i + 1] = static_cast<int>(result.values.size());
129 }
130
131 80 return result;
132 }
133
134 } // namespace
135
136
1/2
✓ Branch 2 taken 80 times.
✗ Branch 3 not taken.
80 KurpiakovACRSMatMulSTL::KurpiakovACRSMatMulSTL(const InType &in) {
137 SetTypeOfTask(GetStaticTypeOfTask());
138 GetInput() = in;
139
1/2
✓ Branch 1 taken 80 times.
✗ Branch 2 not taken.
80 GetOutput() = SparseMatrix();
140 80 }
141
142
1/2
✓ Branch 0 taken 80 times.
✗ Branch 1 not taken.
80 bool KurpiakovACRSMatMulSTL::ValidationImpl() {
143 const auto &[a, b] = GetInput();
144
145
2/4
✓ Branch 0 taken 80 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 80 times.
✗ Branch 3 not taken.
80 if (!ValidateCSR(a) || !ValidateCSR(b)) {
146 return false;
147 }
148
149 80 return a.cols == b.rows;
150 }
151
152 80 bool KurpiakovACRSMatMulSTL::PreProcessingImpl() {
153 80 return true;
154 }
155
156 80 bool KurpiakovACRSMatMulSTL::RunImpl() {
157 const auto &[a, b] = GetInput();
158 80 const int rows = a.rows;
159 80 const int cols = b.cols;
160
161
2/2
✓ Branch 1 taken 44 times.
✓ Branch 2 taken 36 times.
80 const int requested_threads = ppc::util::GetNumThreads();
162
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 38 times.
80 const int num_threads = std::max(1, std::min(requested_threads, rows));
163
164 80 std::vector<std::vector<ComplexD>> row_values(rows);
165
1/2
✓ Branch 1 taken 80 times.
✗ Branch 2 not taken.
80 std::vector<std::vector<int>> row_cols(rows);
166
167
1/2
✓ Branch 1 taken 80 times.
✗ Branch 2 not taken.
80 ComputeRowsWithThreads(a, b, rows, num_threads, row_values, row_cols);
168
1/2
✓ Branch 1 taken 80 times.
✗ Branch 2 not taken.
80 GetOutput() = BuildResult(rows, cols, row_values, row_cols);
169 80 return true;
170 80 }
171
172 80 bool KurpiakovACRSMatMulSTL::PostProcessingImpl() {
173 80 return true;
174 }
175
176 } // namespace kurpiakov_a_sp_comp_mat_mul
177