GCC Code Coverage Report


Directory: ./
File: tasks/kapanova_s_sparse_matrix_mult_ccs/tbb/src/ops_tbb.cpp
Date: 2026-05-11 08:26:31
Exec Total Coverage
Lines: 66 67 98.5%
Functions: 10 10 100.0%
Branches: 46 78 59.0%

Line Branch Exec Source
1 #include "kapanova_s_sparse_matrix_mult_ccs/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 <cstddef>
9 #include <vector>
10
11 #include "kapanova_s_sparse_matrix_mult_ccs/common/include/common.hpp"
12
13 namespace kapanova_s_sparse_matrix_mult_ccs {
14
15
1/2
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
20 KapanovaSSparseMatrixMultCCSTBB::KapanovaSSparseMatrixMultCCSTBB(const InType &in) {
16 SetTypeOfTask(GetStaticTypeOfTask());
17 GetInput() = in;
18 20 }
19
20 20 bool KapanovaSSparseMatrixMultCCSTBB::ValidationImpl() {
21 const auto &a = std::get<0>(GetInput());
22 const auto &b = std::get<1>(GetInput());
23
24
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 if (a.cols != b.rows) {
25 return false;
26 }
27
3/6
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
20 if (a.rows == 0 || a.cols == 0 || b.rows == 0 || b.cols == 0) {
28 return false;
29 }
30
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 if (a.col_ptrs.size() != static_cast<size_t>(a.cols + 1)) {
31 return false;
32 }
33
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 if (b.col_ptrs.size() != static_cast<size_t>(b.cols + 1)) {
34 return false;
35 }
36
2/4
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
20 if (a.col_ptrs[0] != 0 || b.col_ptrs[0] != 0) {
37 return false;
38 }
39
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 if (a.col_ptrs[a.cols] != a.nnz) {
40 return false;
41 }
42
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 if (b.col_ptrs[b.cols] != b.nnz) {
43 return false;
44 }
45
2/4
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
20 if (a.values.size() != static_cast<size_t>(a.nnz) || a.row_indices.size() != static_cast<size_t>(a.nnz)) {
46 return false;
47 }
48
2/4
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 20 times.
20 if (b.values.size() != static_cast<size_t>(b.nnz) || b.row_indices.size() != static_cast<size_t>(b.nnz)) {
49 return false;
50 }
51
52 return true;
53 }
54
55 20 bool KapanovaSSparseMatrixMultCCSTBB::PreProcessingImpl() {
56 20 return true;
57 }
58
59 20 bool KapanovaSSparseMatrixMultCCSTBB::PostProcessingImpl() {
60 20 return true;
61 }
62
63 namespace {
64
65 struct ThreadLocalBuffers {
66 std::vector<double> accum;
67 std::vector<bool> mask;
68 std::vector<size_t> active_rows;
69 std::vector<std::vector<size_t>> col_rows;
70 std::vector<std::vector<double>> col_vals;
71
72
3/10
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 20 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 20 times.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
20 ThreadLocalBuffers(size_t rows, size_t cols) : accum(rows, 0.0), mask(rows, false), col_rows(cols), col_vals(cols) {}
73 };
74
75 20 void ProcessColumnRange(const CCSMatrix &a, const CCSMatrix &b, std::vector<std::vector<size_t>> &col_rows,
76 std::vector<std::vector<double>> &col_vals, std::vector<double> &accum, std::vector<bool> &mask,
77 std::vector<size_t> &active_rows, const tbb::blocked_range<size_t> &range) {
78
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 20 times.
68 for (size_t j = range.begin(); j != range.end(); ++j) {
79
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 48 times.
120 for (size_t k = b.col_ptrs[j]; k < b.col_ptrs[j + 1]; ++k) {
80 72 size_t row_b = b.row_indices[k];
81 72 double val_b = b.values[k];
82
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 72 times.
160 for (size_t zc = a.col_ptrs[row_b]; zc < a.col_ptrs[row_b + 1]; ++zc) {
83 88 size_t i = a.row_indices[zc];
84
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 88 times.
88 double val_a = a.values[zc];
85
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 88 times.
88 accum[i] += val_a * val_b;
86
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 24 times.
88 if (!mask[i]) {
87 mask[i] = true;
88 active_rows.push_back(i);
89 }
90 }
91 }
92
93 std::ranges::sort(active_rows);
94
95
3/4
✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 64 times.
✓ Branch 3 taken 48 times.
112 for (size_t i : active_rows) {
96
1/2
✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
64 if (accum[i] != 0.0) {
97 col_rows[j].push_back(i);
98 col_vals[j].push_back(accum[i]);
99 }
100
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 64 times.
64 accum[i] = 0.0;
101 mask[i] = false;
102 }
103 active_rows.clear();
104 }
105 20 }
106
107 20 void MergeColumnSizes(const tbb::enumerable_thread_specific<ThreadLocalBuffers> &tls_data, size_t cols,
108 std::vector<size_t> &col_sizes) {
109 for (const auto &local : tls_data) {
110
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 20 times.
68 for (size_t j = 0; j < cols; ++j) {
111 48 col_sizes[j] += local.col_rows[j].size();
112 }
113 }
114 20 }
115
116 20 void MergeResults(const tbb::enumerable_thread_specific<ThreadLocalBuffers> &tls_data, size_t cols, CCSMatrix &c) {
117 20 std::vector<size_t> current_pos(cols, 0);
118 for (const auto &local : tls_data) {
119
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 20 times.
68 for (size_t j = 0; j < cols; ++j) {
120 48 size_t start = c.col_ptrs[j] + current_pos[j];
121 const auto &rows = local.col_rows[j];
122 const auto &vals = local.col_vals[j];
123
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 48 times.
112 for (size_t idx = 0; idx < rows.size(); ++idx) {
124 64 c.row_indices[start + idx] = rows[idx];
125 64 c.values[start + idx] = vals[idx];
126 }
127 48 current_pos[j] += rows.size();
128 }
129 }
130 20 }
131
132 } // namespace
133
134 20 bool KapanovaSSparseMatrixMultCCSTBB::RunImpl() {
135 const auto &a = std::get<0>(GetInput());
136 const auto &b = std::get<1>(GetInput());
137 OutType &c = GetOutput();
138
139 20 c.rows = a.rows;
140 20 c.cols = b.cols;
141 20 c.col_ptrs.assign(c.cols + 1, 0);
142 20 c.nnz = 0;
143
144 40 tbb::enumerable_thread_specific<ThreadLocalBuffers> tls_data([&]() { return ThreadLocalBuffers(a.rows, c.cols); });
145
146
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 tbb::parallel_for(tbb::blocked_range<size_t>(0, c.cols, 256), [&](const tbb::blocked_range<size_t> &range) {
147 20 auto &local = tls_data.local();
148 20 ProcessColumnRange(a, b, local.col_rows, local.col_vals, local.accum, local.mask, local.active_rows, range);
149 20 });
150
151
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 std::vector<size_t> col_sizes(c.cols, 0);
152 20 MergeColumnSizes(tls_data, c.cols, col_sizes);
153
154 size_t offset = 0;
155
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 20 times.
68 for (size_t j = 0; j < c.cols; ++j) {
156 48 c.col_ptrs[j] = offset;
157 48 offset += col_sizes[j];
158 }
159 20 c.col_ptrs[c.cols] = offset;
160 20 c.nnz = offset;
161
162
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 c.values.resize(c.nnz);
163
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 c.row_indices.resize(c.nnz);
164
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 MergeResults(tls_data, c.cols, c);
165
166 20 return true;
167 20 }
168
169 } // namespace kapanova_s_sparse_matrix_mult_ccs
170