GCC Code Coverage Report


Directory: ./
File: tasks/dilshodov_a_spmm_double_css/tbb/src/ops_tbb.cpp
Date: 2026-05-11 08:26:31
Exec Total Coverage
Lines: 70 71 98.6%
Functions: 11 11 100.0%
Branches: 58 86 67.4%

Line Branch Exec Source
1 #include "dilshodov_a_spmm_double_css/tbb/include/ops_tbb.hpp"
2
3 #include <tbb/blocked_range.h>
4 #include <tbb/enumerable_thread_specific.h>
5 #include <tbb/parallel_for.h>
6
7 #include <algorithm>
8 #include <cmath>
9 #include <cstddef>
10 #include <utility>
11 #include <vector>
12
13 #include "dilshodov_a_spmm_double_css/common/include/common.hpp"
14
15 namespace dilshodov_a_spmm_double_css {
16
17 namespace {
18 constexpr double kEps = 1e-10;
19
20 bool HasValidDimensions(const SparseMatrixCCS &m) {
21
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 return m.rows_count > 0 && m.cols_count > 0;
22 }
23
24
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 bool HasValidContainers(const SparseMatrixCCS &m) {
25
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 if (m.col_ptrs.size() != static_cast<size_t>(m.cols_count) + 1) {
26 return false;
27 }
28
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 if (m.row_indices.size() != m.values.size()) {
29 return false;
30 }
31
2/4
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
24 if (m.col_ptrs.empty() || m.col_ptrs.front() != 0) {
32 return false;
33 }
34
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 if (m.col_ptrs.back() < 0) {
35 return false;
36 }
37
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (static_cast<size_t>(m.col_ptrs.back()) != m.values.size()) {
38 return false;
39 }
40 return true;
41 }
42
43 24 bool HasValidColumnOrdering(const SparseMatrixCCS &m) {
44
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 24 times.
84 for (int j = 0; j < m.cols_count; ++j) {
45
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
60 if (m.col_ptrs[j] > m.col_ptrs[j + 1]) {
46 return false;
47 }
48 int prev_row = -1;
49
2/2
✓ Branch 0 taken 92 times.
✓ Branch 1 taken 60 times.
152 for (int idx = m.col_ptrs[j]; idx < m.col_ptrs[j + 1]; ++idx) {
50
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 92 times.
92 const int row = m.row_indices[idx];
51
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 92 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 92 times.
92 if (row < 0 || row >= m.rows_count) {
52 return false;
53 }
54
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 92 times.
92 if (row <= prev_row) {
55 return false;
56 }
57 prev_row = row;
58 }
59 }
60 return true;
61 }
62
63
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 bool IsValidCCS(const SparseMatrixCCS &m) {
64
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 return HasValidDimensions(m) && HasValidContainers(m) && HasValidColumnOrdering(m);
65 }
66
67 struct ScratchData {
68 std::vector<double> acc;
69 std::vector<int> marker;
70 std::vector<int> used_rows;
71 };
72
73
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 14 times.
28 void AccumulateColumnProduct(const SparseMatrixCCS &lhs, const SparseMatrixCCS &rhs, int rhs_col, ScratchData &scratch,
74 std::vector<std::pair<int, double>> &col) {
75 scratch.used_rows.clear();
76 col.clear();
77
78
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 28 times.
76 for (int idx_b = rhs.col_ptrs[rhs_col]; idx_b < rhs.col_ptrs[rhs_col + 1]; ++idx_b) {
79 48 const int k = rhs.row_indices[idx_b];
80 48 const double rhs_value = rhs.values[idx_b];
81
82
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 48 times.
112 for (int idx_a = lhs.col_ptrs[k]; idx_a < lhs.col_ptrs[k + 1]; ++idx_a) {
83
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 16 times.
64 const int row = lhs.row_indices[idx_a];
84 64 const double value = lhs.values[idx_a] * rhs_value;
85
86
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 16 times.
64 if (scratch.marker[row] != rhs_col) {
87
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 27 times.
48 scratch.marker[row] = rhs_col;
88 48 scratch.acc[row] = value;
89
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 27 times.
48 scratch.used_rows.push_back(row);
90 } else {
91 16 scratch.acc[row] += value;
92 }
93 }
94 }
95
96 28 col.reserve(scratch.used_rows.size());
97
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 28 times.
76 for (int row : scratch.used_rows) {
98
1/2
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
48 const double value = scratch.acc[row];
99
1/2
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
48 if (std::abs(value) > kEps) {
100 48 col.emplace_back(row, value);
101 }
102 }
103
104 std::ranges::sort(col, {}, &std::pair<int, double>::first);
105 28 }
106
107 12 void BuildOutputFromColumns(const std::vector<std::vector<std::pair<int, double>>> &column_results,
108 SparseMatrixCCS &out) {
109 int offset = 0;
110
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 12 times.
40 for (int col = 0; col < out.cols_count; ++col) {
111
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 28 times.
76 for (const auto &[row, value] : column_results[col]) {
112
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 36 times.
48 out.row_indices.push_back(row);
113
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 36 times.
48 out.values.push_back(value);
114 48 ++offset;
115 }
116 28 out.col_ptrs[col + 1] = offset;
117 }
118 12 }
119
120 } // namespace
121
122
1/2
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
12 DilshodovASpmmDoubleCssTbb::DilshodovASpmmDoubleCssTbb(const InType &in) {
123 SetTypeOfTask(GetStaticTypeOfTask());
124 GetInput() = in;
125 12 }
126
127
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 bool DilshodovASpmmDoubleCssTbb::ValidationImpl() {
128 const auto &lhs = std::get<0>(GetInput());
129 const auto &rhs = std::get<1>(GetInput());
130
3/6
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 12 times.
12 return IsValidCCS(lhs) && IsValidCCS(rhs) && lhs.cols_count == rhs.rows_count;
131 }
132
133 12 bool DilshodovASpmmDoubleCssTbb::PreProcessingImpl() {
134 12 GetOutput() = SparseMatrixCCS{};
135 12 return true;
136 }
137
138 12 bool DilshodovASpmmDoubleCssTbb::RunImpl() {
139 const auto &lhs = std::get<0>(GetInput());
140 const auto &rhs = std::get<1>(GetInput());
141 auto &out = GetOutput();
142
143 12 out.rows_count = lhs.rows_count;
144 12 out.cols_count = rhs.cols_count;
145
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
12 out.col_ptrs.assign(static_cast<size_t>(out.cols_count) + 1, 0);
146 out.row_indices.clear();
147 out.values.clear();
148
149 12 std::vector<std::vector<std::pair<int, double>>> column_results(rhs.cols_count);
150
151 12 ScratchData exemplar;
152
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 exemplar.acc.assign(lhs.rows_count, 0.0);
153
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 exemplar.marker.assign(lhs.rows_count, -1);
154
155
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 tbb::enumerable_thread_specific<ScratchData> tls(exemplar);
156
157
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 tbb::parallel_for(tbb::blocked_range<int>(0, rhs.cols_count), [&](const tbb::blocked_range<int> &range) {
158 28 auto &scratch = tls.local();
159
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 28 times.
56 for (int rhs_col = range.begin(); rhs_col < range.end(); ++rhs_col) {
160 28 AccumulateColumnProduct(lhs, rhs, rhs_col, scratch, column_results[rhs_col]);
161 }
162 28 });
163
164
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 BuildOutputFromColumns(column_results, out);
165
166 12 out.non_zeros = static_cast<int>(out.values.size());
167 12 return true;
168 12 }
169
170 12 bool DilshodovASpmmDoubleCssTbb::PostProcessingImpl() {
171 12 GetOutput().non_zeros = static_cast<int>(GetOutput().values.size());
172 12 return true;
173 }
174
175 } // namespace dilshodov_a_spmm_double_css
176