GCC Code Coverage Report


Directory: ./
File: tasks/safaryan_a_sparse_matrix_mult_crs/all/src/ops_all.cpp
Date: 2026-06-04 20:25:32
Exec Total Coverage
Lines: 71 73 97.3%
Functions: 10 10 100.0%
Branches: 53 86 61.6%

Line Branch Exec Source
1 #include "safaryan_a_sparse_matrix_mult_crs/all/include/ops_all.hpp"
2
3 #include <mpi.h>
4 #include <oneapi/tbb/parallel_for.h>
5
6 #include <algorithm>
7 #include <cmath>
8 #include <cstddef>
9 #include <vector>
10
11 #include "safaryan_a_sparse_matrix_mult_crs/common/include/common.hpp"
12 #include "util/include/util.hpp"
13
14 namespace safaryan_a_sparse_matrix_mult_crs {
15
16
1/2
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
10 SafaryanATaskALL::SafaryanATaskALL(const InType &in) {
17 SetTypeOfTask(GetStaticTypeOfTask());
18 GetInput() = in;
19 10 GetOutput() = SparseMatrixCCS();
20 10 }
21
22 20 bool SafaryanATaskALL::IsMatrixValid(const SparseMatrixCCS &matrix) {
23
2/4
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 20 times.
20 if (matrix.rows < 0 || matrix.cols < 0) {
24 return false;
25 }
26
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 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 20 times.
20 if (matrix.values.size() != matrix.row_indices.size()) {
30 return false;
31 }
32
33
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 20 times.
20 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 20 times.
20 const int total_elements = static_cast<int>(matrix.values.size());
38
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (matrix.col_ptrs[matrix.cols] != total_elements) {
39 return false;
40 }
41
42
2/2
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 20 times.
78 for (size_t i = 0; i < matrix.col_ptrs.size() - 1; ++i) {
43
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 58 times.
58 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 72 times.
✓ Branch 1 taken 20 times.
92 for (size_t i = 0; i < matrix.row_indices.size(); ++i) {
49
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 72 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 72 times.
72 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 10 times.
✗ Branch 1 not taken.
10 bool SafaryanATaskALL::ValidationImpl() {
58 const auto &[a, b] = GetInput();
59
60
2/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
10 if (!IsMatrixValid(a) || !IsMatrixValid(b)) {
61 return false;
62 }
63
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (a.cols != b.rows) {
64 return false;
65 }
66
67 return true;
68 }
69
70 10 bool SafaryanATaskALL::PreProcessingImpl() {
71 const auto &[a, b] = GetInput();
72 10 GetOutput() = SparseMatrixCCS(a.rows, b.cols);
73 10 return true;
74 }
75
76 namespace {
77 28 void ProcessColumn(const SparseMatrixCCS &a, const SparseMatrixCCS &b, int j, std::vector<double> &temp) {
78
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 28 times.
56 for (int b_idx = b.col_ptrs[j]; b_idx < b.col_ptrs[j + 1]; ++b_idx) {
79 28 const int k = b.row_indices[b_idx];
80 28 const double b_val = b.values[b_idx];
81
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 28 times.
70 for (int a_idx = a.col_ptrs[k]; a_idx < a.col_ptrs[k + 1]; ++a_idx) {
82 42 const int i = a.row_indices[a_idx];
83 42 const double a_val = a.values[a_idx];
84 42 temp[i] += a_val * b_val;
85 }
86 }
87 28 }
88
89 20 SparseMatrixCCS BuildColumnRange(const SparseMatrixCCS &a, const SparseMatrixCCS &b, int begin_col, int end_col) {
90 20 SparseMatrixCCS part(a.rows, end_col - begin_col);
91
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 std::vector<double> temp(a.rows, 0.0);
92
93
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 20 times.
48 for (int j = begin_col; j < end_col; ++j) {
94 28 part.col_ptrs[j - begin_col] = static_cast<int>(part.values.size());
95 28 ProcessColumn(a, b, j, temp);
96
97
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 28 times.
112 for (int i = 0; i < a.rows; ++i) {
98
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 42 times.
84 if (std::abs(temp[i]) > 1e-10) {
99
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 38 times.
42 part.values.push_back(temp[i]);
100
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 38 times.
42 part.row_indices.push_back(i);
101 42 temp[i] = 0.0;
102 }
103 }
104 }
105
106
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 part.col_ptrs[end_col - begin_col] = static_cast<int>(part.values.size());
107 20 return part;
108 }
109 } // namespace
110
111 10 SparseMatrixCCS SafaryanATaskALL::MultiplyMatrices(const SparseMatrixCCS &a, const SparseMatrixCCS &b) {
112 10 SparseMatrixCCS result(a.rows, b.cols);
113
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 if (b.cols == 0) {
114 return result;
115 }
116
117
3/6
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
✓ Branch 5 taken 10 times.
✗ Branch 6 not taken.
10 const int chunks_count = std::max(1, std::min(ppc::util::GetNumThreads(), b.cols));
118
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 std::vector<SparseMatrixCCS> parts(chunks_count);
119
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 std::vector<int> begin_cols(chunks_count + 1, 0);
120
121 10 #pragma omp parallel for num_threads(chunks_count) default(none) shared(begin_cols, b, chunks_count)
122 for (int i = 0; i <= chunks_count; ++i) {
123 begin_cols[i] = (b.cols * i) / chunks_count;
124 }
125
126
1/4
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
10 tbb::parallel_for(0, chunks_count, [&](int chunk_id) {
127 20 parts[chunk_id] = BuildColumnRange(a, b, begin_cols[chunk_id], begin_cols[chunk_id + 1]);
128 20 });
129
130
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 10 times.
30 for (int part_id = 0; part_id < chunks_count; ++part_id) {
131 20 const SparseMatrixCCS &part = parts[part_id];
132 20 const int column_offset = begin_cols[part_id];
133
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 20 times.
48 for (int local_col = 0; local_col < part.cols; ++local_col) {
134
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
28 result.col_ptrs[column_offset + local_col] = static_cast<int>(result.values.size());
135
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
28 const int begin = part.col_ptrs[local_col];
136 28 const int end = part.col_ptrs[local_col + 1];
137
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
28 result.values.insert(result.values.end(), part.values.begin() + begin, part.values.begin() + end);
138
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
28 result.row_indices.insert(result.row_indices.end(), part.row_indices.begin() + begin,
139 part.row_indices.begin() + end);
140 }
141 }
142
143
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 result.col_ptrs[b.cols] = static_cast<int>(result.values.size());
144 return result;
145 10 }
146
147 10 bool SafaryanATaskALL::RunImpl() {
148 10 MPI_Barrier(MPI_COMM_WORLD);
149 const auto &[a, b] = GetInput();
150 10 GetOutput() = SparseMatrixCCS(a.rows, b.cols);
151 10 GetOutput() = MultiplyMatrices(a, b);
152 10 MPI_Barrier(MPI_COMM_WORLD);
153 10 return true;
154 }
155
156 10 bool SafaryanATaskALL::PostProcessingImpl() {
157 10 return true;
158 }
159
160 } // namespace safaryan_a_sparse_matrix_mult_crs
161