GCC Code Coverage Report


Directory: ./
File: tasks/sabirov_s_linear_filtering_block_partitioning/mpi/src/ops_mpi.cpp
Date: 2026-01-27 01:59:34
Exec Total Coverage
Lines: 80 80 100.0%
Functions: 8 8 100.0%
Branches: 35 48 72.9%

Line Branch Exec Source
1 #include "sabirov_s_linear_filtering_block_partitioning/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <algorithm>
6 #include <array>
7 #include <cstddef>
8 #include <cstdint>
9
10 #include "sabirov_s_linear_filtering_block_partitioning/common/include/common.hpp"
11
12 namespace sabirov_s_linear_filtering_block_partitioning {
13
14
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 SabirovSLinearFilteringBlockPartitioningMPI::SabirovSLinearFilteringBlockPartitioningMPI(const InType &in) {
15 SetTypeOfTask(GetStaticTypeOfTask());
16 GetInput() = in;
17 10 }
18
19 10 bool SabirovSLinearFilteringBlockPartitioningMPI::ValidationImpl() {
20 10 int rank = 0;
21 10 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
22
23
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (rank == 0) {
24 const auto &input = GetInput();
25
4/8
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 5 times.
5 bool valid = !input.Empty() && input.width > 0 && input.height > 0 && input.channels == 3;
26 5 int valid_flag = valid ? 1 : 0;
27 5 MPI_Bcast(&valid_flag, 1, MPI_INT, 0, MPI_COMM_WORLD);
28 return valid;
29 }
30
31 5 int valid_flag = 0;
32 5 MPI_Bcast(&valid_flag, 1, MPI_INT, 0, MPI_COMM_WORLD);
33 5 return valid_flag == 1;
34 }
35
36 10 bool SabirovSLinearFilteringBlockPartitioningMPI::PreProcessingImpl() {
37 10 int rank = 0;
38 10 int size = 0;
39 10 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
40 10 MPI_Comm_size(MPI_COMM_WORLD, &size);
41
42
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (rank == 0) {
43 const auto &input = GetInput();
44 5 GetOutput() = ImageData(input.width, input.height, input.channels);
45
46 // Рассылаем размеры изображения всем процессам
47 5 std::array<int, 3> dims = {input.width, input.height, input.channels};
48 5 MPI_Bcast(dims.data(), 3, MPI_INT, 0, MPI_COMM_WORLD);
49 } else {
50 5 std::array<int, 3> dims = {0, 0, 0};
51 5 MPI_Bcast(dims.data(), 3, MPI_INT, 0, MPI_COMM_WORLD);
52 5 GetInput() = ImageData(dims[0], dims[1], dims[2]);
53 10 GetOutput() = ImageData(dims[0], dims[1], dims[2]);
54 }
55
56 10 return !GetOutput().Empty();
57 }
58
59 namespace {
60 // Вспомогательная функция для фильтрации блока строк
61 10 void FilterRows(const ImageData &input, ImageData &output, int start_row, int end_row) {
62 10 const int width = input.width;
63 10 const int channels = input.channels;
64
65
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 10 times.
74 for (int row = start_row; row < end_row; row++) {
66
2/2
✓ Branch 0 taken 1378 times.
✓ Branch 1 taken 64 times.
1442 for (int col = 0; col < width; col++) {
67
2/2
✓ Branch 0 taken 4134 times.
✓ Branch 1 taken 1378 times.
5512 for (int ch = 0; ch < channels; ch++) {
68 4134 float sum = ApplyGaussianKernel(input, row, col, ch);
69 4134 auto output_idx =
70 4134 ((static_cast<std::size_t>(row) * static_cast<std::size_t>(width) + static_cast<std::size_t>(col)) *
71 4134 static_cast<std::size_t>(channels)) +
72 4134 static_cast<std::size_t>(ch);
73 4134 output.pixels[output_idx] = static_cast<uint8_t>(std::clamp(sum, 0.0F, 255.0F));
74 }
75 }
76 }
77 10 }
78
79 // Вспомогательная функция для рассылки изображения
80 10 void BroadcastImage(ImageData &input, int rank, int size) {
81
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (rank == 0) {
82
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 for (int dest = 1; dest < size; dest++) {
83 5 MPI_Send(input.pixels.data(), static_cast<int>(input.pixels.size()), MPI_UNSIGNED_CHAR, dest, 0, MPI_COMM_WORLD);
84 }
85 } else {
86 5 MPI_Recv(input.pixels.data(), static_cast<int>(input.pixels.size()), MPI_UNSIGNED_CHAR, 0, 0, MPI_COMM_WORLD,
87 MPI_STATUS_IGNORE);
88 }
89 10 }
90
91 // Вспомогательная функция для сбора результатов
92 10 void GatherResults(ImageData &output, int rank, int size, int rows_per_proc, int remainder, int width, int channels) {
93
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (rank == 0) {
94
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 for (int src = 1; src < size; src++) {
95
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 int src_start = (src * rows_per_proc) + std::min(src, remainder);
96
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 int src_end = src_start + rows_per_proc + (src < remainder ? 1 : 0);
97 5 int src_size = (src_end - src_start) * width * channels;
98
99
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (src_size > 0) {
100 5 auto offset =
101 5 static_cast<std::size_t>(src_start) * static_cast<std::size_t>(width) * static_cast<std::size_t>(channels);
102 5 MPI_Recv(output.pixels.data() + offset, src_size, MPI_UNSIGNED_CHAR, src, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
103 }
104 }
105 } else {
106
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 int start_row = (rank * rows_per_proc) + std::min(rank, remainder);
107
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 int end_row = start_row + rows_per_proc + (rank < remainder ? 1 : 0);
108 5 int local_size = (end_row - start_row) * width * channels;
109
110
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (local_size > 0) {
111 5 auto offset =
112 5 static_cast<std::size_t>(start_row) * static_cast<std::size_t>(width) * static_cast<std::size_t>(channels);
113 5 MPI_Send(output.pixels.data() + offset, local_size, MPI_UNSIGNED_CHAR, 0, 1, MPI_COMM_WORLD);
114 }
115 }
116 10 }
117 } // namespace
118
119 10 bool SabirovSLinearFilteringBlockPartitioningMPI::RunImpl() {
120 10 int rank = 0;
121 10 int size = 0;
122 10 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
123 10 MPI_Comm_size(MPI_COMM_WORLD, &size);
124
125 auto &input = GetInput();
126 auto &output = GetOutput();
127
128
2/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
10 if (input.width < 3 || input.height < 3) {
129 return false;
130 }
131
132 const int width = input.width;
133 const int height = input.height;
134 10 const int channels = input.channels;
135
136 // Рассылаем входное изображение от процесса 0 всем процессам
137 10 BroadcastImage(input, rank, size);
138
139 // Вычисляем блочное разбиение (распределяем строки между процессами)
140 10 int rows_per_proc = height / size;
141 10 int remainder = height % size;
142
143
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
10 int start_row = (rank * rows_per_proc) + std::min(rank, remainder);
144
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
10 int end_row = start_row + rows_per_proc + (rank < remainder ? 1 : 0);
145
146 // Каждый процесс фильтрует свои назначенные строки
147 10 FilterRows(input, output, start_row, end_row);
148
149 // Собираем результаты на процессе 0
150 10 GatherResults(output, rank, size, rows_per_proc, remainder, width, channels);
151
152 // Рассылаем полный результат от процесса 0 всем процессам
153 10 MPI_Bcast(output.pixels.data(), static_cast<int>(output.pixels.size()), MPI_UNSIGNED_CHAR, 0, MPI_COMM_WORLD);
154
155 return true;
156 }
157
158 10 bool SabirovSLinearFilteringBlockPartitioningMPI::PostProcessingImpl() {
159 10 return !GetOutput().Empty();
160 }
161
162 } // namespace sabirov_s_linear_filtering_block_partitioning
163