GCC Code Coverage Report


Directory: ./
File: tasks/kotelnikova_a_double_matr_mult/tbb/src/ops_tbb.cpp
Date: 2026-04-02 17:12:27
Exec Total Coverage
Lines: 66 68 97.1%
Functions: 10 10 100.0%
Branches: 51 82 62.2%

Line Branch Exec Source
1 #include "kotelnikova_a_double_matr_mult/tbb/include/ops_tbb.hpp"
2
3 #include <tbb/blocked_range.h>
4 #include <tbb/parallel_for.h>
5 #include <tbb/parallel_scan.h>
6 #include <tbb/tbb.h>
7
8 #include <cmath>
9 #include <cstddef>
10 #include <vector>
11
12 #include "kotelnikova_a_double_matr_mult/common/include/common.hpp"
13
14 namespace kotelnikova_a_double_matr_mult {
15
16
1/2
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
20 KotelnikovaATaskTBB::KotelnikovaATaskTBB(const InType &in) {
17 SetTypeOfTask(GetStaticTypeOfTask());
18 GetInput() = in;
19 20 GetOutput() = SparseMatrixCCS();
20 20 }
21
22 40 bool KotelnikovaATaskTBB::IsMatrixValid(const SparseMatrixCCS &matrix) {
23
2/4
✓ Branch 0 taken 40 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 40 times.
40 if (matrix.rows < 0 || matrix.cols < 0) {
24 return false;
25 }
26
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 if (matrix.col_ptrs.size() != static_cast<size_t>(matrix.cols) + 1) {
27 return false;
28 }
29
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 if (matrix.values.size() != matrix.row_indices.size()) {
30 return false;
31 }
32
33
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 40 times.
40 if (matrix.col_ptrs.empty() || matrix.col_ptrs[0] != 0) {
34 return false;
35 }
36
37
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 const int total_elements = static_cast<int>(matrix.values.size());
38
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 if (matrix.col_ptrs[matrix.cols] != total_elements) {
39 return false;
40 }
41
42
2/2
✓ Branch 0 taken 116 times.
✓ Branch 1 taken 40 times.
156 for (size_t i = 0; i < matrix.col_ptrs.size() - 1; ++i) {
43
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 116 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 116 times.
116 if (matrix.col_ptrs[i] > matrix.col_ptrs[i + 1] || matrix.col_ptrs[i] < 0) {
44 return false;
45 }
46 }
47
48
2/2
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 40 times.
184 for (size_t i = 0; i < matrix.row_indices.size(); ++i) {
49
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 144 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 144 times.
144 if (matrix.row_indices[i] < 0 || matrix.row_indices[i] >= matrix.rows) {
50 return false;
51 }
52 }
53
54 return true;
55 }
56
57
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 bool KotelnikovaATaskTBB::ValidationImpl() {
58 const auto &[a, b] = GetInput();
59
60
2/4
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
20 if (!IsMatrixValid(a) || !IsMatrixValid(b)) {
61 return false;
62 }
63
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (a.cols != b.rows) {
64 return false;
65 }
66
67 return true;
68 }
69
70 20 bool KotelnikovaATaskTBB::PreProcessingImpl() {
71 const auto &[a, b] = GetInput();
72 20 GetOutput() = SparseMatrixCCS(a.rows, b.cols);
73 20 return true;
74 }
75
76 namespace {
77 112 std::vector<double> ComputeColumn(const SparseMatrixCCS &a, const SparseMatrixCCS &b, int col_idx) {
78 112 std::vector<double> temp(a.rows, 0.0);
79
80
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 112 times.
224 for (int b_idx = b.col_ptrs[col_idx]; b_idx < b.col_ptrs[col_idx + 1]; ++b_idx) {
81 112 const int k = b.row_indices[b_idx];
82 112 const double b_val = b.values[b_idx];
83
84
2/2
✓ Branch 0 taken 168 times.
✓ Branch 1 taken 112 times.
280 for (int a_idx = a.col_ptrs[k]; a_idx < a.col_ptrs[k + 1]; ++a_idx) {
85 168 const int i = a.row_indices[a_idx];
86 168 temp[i] += a.values[a_idx] * b_val;
87 }
88 }
89
90 112 return temp;
91 }
92
93 int CountNonZero(const std::vector<double> &column, double epsilon) {
94 int count = 0;
95
4/4
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 84 times.
✓ Branch 2 taken 168 times.
✓ Branch 3 taken 56 times.
224 for (double val : column) {
96
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 84 times.
168 if (std::abs(val) > epsilon) {
97 84 ++count;
98 }
99 }
100 return count;
101 }
102
103 void FillColumn(const std::vector<double> &column, double epsilon, std::vector<int> &row_indices,
104 std::vector<double> &values, int start_pos) {
105 int pos = start_pos;
106
2/2
✓ Branch 0 taken 168 times.
✓ Branch 1 taken 56 times.
224 for (size_t i = 0; i < column.size(); ++i) {
107
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 84 times.
168 if (std::abs(column[i]) > epsilon) {
108 84 row_indices[pos] = static_cast<int>(i);
109 84 values[pos] = column[i];
110 84 ++pos;
111 }
112 }
113 }
114
115 } // namespace
116
117 // Оптимизированная версия с grain size и partitioner
118 20 SparseMatrixCCS KotelnikovaATaskTBB::MultiplyMatrices(const SparseMatrixCCS &a, const SparseMatrixCCS &b) {
119 20 SparseMatrixCCS result(a.rows, b.cols);
120
121 20 const double epsilon = 1e-10;
122 const int grain_size = 8; // Аналог chunk size в OpenMP
123
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 std::vector<int> col_start(b.cols, 0);
124
125 // Первый проход: подсчет ненулевых элементов с grain size и simple_partitioner
126 40 tbb::parallel_for(tbb::blocked_range<int>(0, b.cols, grain_size),
127
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
40 [&](const tbb::blocked_range<int> &range) {
128
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 20 times.
76 for (int j = range.begin(); j < range.end(); ++j) {
129 56 std::vector<double> column = ComputeColumn(a, b, j);
130
1/2
✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
112 col_start[j] = CountNonZero(column, epsilon);
131 }
132 20 },
133 20 tbb::simple_partitioner() // Минимизирует overhead для небольших задач
134 );
135
136 // Префиксная сумма для построения col_ptrs
137
1/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
20 std::vector<int> col_ptr(b.cols + 1, 0);
138
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 20 times.
76 for (int j = 0; j < b.cols; ++j) {
139 56 col_ptr[j + 1] = col_ptr[j] + col_start[j];
140 }
141
142
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 const int total_nnz = col_ptr[b.cols];
143
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 result.values.resize(total_nnz);
144
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 result.row_indices.resize(total_nnz);
145
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 result.col_ptrs = col_ptr;
146
147 // Второй проход: заполнение данных с grain size и simple_partitioner
148
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
40 tbb::parallel_for(tbb::blocked_range<int>(0, b.cols, grain_size), [&](const tbb::blocked_range<int> &range) {
149
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 20 times.
76 for (int j = range.begin(); j < range.end(); ++j) {
150 56 std::vector<double> column = ComputeColumn(a, b, j);
151 56 FillColumn(column, epsilon, result.row_indices, result.values, col_ptr[j]);
152 }
153
1/4
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
20 }, tbb::simple_partitioner());
154
155 20 return result;
156 }
157
158 20 bool KotelnikovaATaskTBB::RunImpl() {
159 const auto &[a, b] = GetInput();
160 20 GetOutput() = MultiplyMatrices(a, b);
161 20 return true;
162 }
163
164 20 bool KotelnikovaATaskTBB::PostProcessingImpl() {
165 20 return true;
166 }
167
168 } // namespace kotelnikova_a_double_matr_mult
169