GCC Code Coverage Report


Directory: ./
File: tasks/kutergin_v_linear_contrast_stretching/mpi/src/linear_contrast_stretching_mpi.cpp
Date: 2026-01-10 02:40:41
Exec Total Coverage
Lines: 46 46 100.0%
Functions: 5 5 100.0%
Branches: 29 46 63.0%

Line Branch Exec Source
1 #include "../include/linear_contrast_stretching_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <algorithm>
6 #include <cmath>
7 #include <cstddef>
8 #include <vector>
9
10 #include "../../common/include/common.hpp"
11
12 namespace kutergin_v_linear_contrast_stretching {
13
14
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 LinearContrastStretchingMPI::LinearContrastStretchingMPI(const InType &in) {
15 SetTypeOfTask(GetStaticTypeOfTask()); // установка типа задачи
16 GetInput() = in; // сохранение входных данных
17
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (!in.data.empty()) {
18
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 GetOutput().resize(in.data.size()); // инициализация выходных данных
19 }
20 6 }
21
22 6 bool LinearContrastStretchingMPI::ValidationImpl() {
23 6 return !GetInput().data.empty(); // пустое изображение невалидно
24 }
25
26 6 bool LinearContrastStretchingMPI::PreProcessingImpl() {
27 6 return true;
28 }
29
30 6 bool LinearContrastStretchingMPI::RunImpl() {
31 6 int process_rank = 0;
32 6 int process_count = 1;
33 6 MPI_Comm_rank(MPI_COMM_WORLD, &process_rank);
34 6 MPI_Comm_size(MPI_COMM_WORLD, &process_count);
35
36 const int root = 0;
37
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 size_t total_pixel_count = (process_rank == root) ? GetInput().data.size() : 0;
38
39 6 const int base_chunk =
40 6 static_cast<int>(total_pixel_count) / process_count; // целое часть от деления числа пикселей на число процессов
41 6 const int remainder =
42 static_cast<int>(total_pixel_count) % process_count; // остаток от деления числа пикселей на число процессов
43
44 6 std::vector<int> send_counts(process_count); // вектор чисел пикселей на каждый процесс
45
1/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
6 std::vector<int> displs(process_count, 0); // вектор смещений начал "кусков" на каждый процесс
46
47
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (process_rank == root) // root-процесс вычисляет кому сколько пикселей дать и какое будет смещение
48 {
49
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 3 times.
9 for (int i = 0; i < process_count; ++i) {
50
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 3 times.
9 send_counts[i] = base_chunk + (i < remainder ? 1 : 0);
51
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (i > 0) {
52 3 displs[i] = displs[i - 1] + send_counts[i - 1];
53 }
54 }
55 }
56
57
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 int local_chunk_size = 0;
58
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 MPI_Scatter(send_counts.data(), 1, MPI_INT, &local_chunk_size, 1, MPI_INT, root, MPI_COMM_WORLD);
59
60 std::vector<unsigned char> local_chunk(
61
1/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
6 local_chunk_size); // локальный буфер для приема части вектора на каждом процессе
62
63 const auto &image_in_full = GetInput().data;
64 auto &image_out_full = GetOutput();
65
66
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 MPI_Scatterv(image_in_full.data(), send_counts.data(), displs.data(), MPI_UNSIGNED_CHAR, local_chunk.data(),
67 local_chunk_size, MPI_UNSIGNED_CHAR, root, MPI_COMM_WORLD);
68
69 6 unsigned char local_min = 255;
70
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 unsigned char local_max = 0;
71
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (!local_chunk.empty()) {
72 // поиск локальных минимумов и максимумов (на каждом куске вектора)
73 const auto &minmax_it = std::ranges::minmax_element(local_chunk);
74 6 local_min = *minmax_it.min;
75 6 local_max = *minmax_it.max;
76 }
77
78 // получение глобального минимума и максимума (для всего вектора)
79 6 unsigned char global_min = 0;
80 6 unsigned char global_max = 0;
81
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 MPI_Allreduce(&local_min, &global_min, 1, MPI_UNSIGNED_CHAR, MPI_MIN,
82 MPI_COMM_WORLD); // сбор минимума из всех local_min
83
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 MPI_Allreduce(&local_max, &global_max, 1, MPI_UNSIGNED_CHAR, MPI_MAX,
84 MPI_COMM_WORLD); // сбор максимума из всех local_max
85
86
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 if (global_min != global_max) {
87 4 const double scale = 255.0 / (global_max - global_min);
88
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 4 times.
14 for (unsigned char &pixel : local_chunk) {
89 10 double p_out = (pixel - global_min) * scale;
90 10 pixel = static_cast<unsigned char>(std::round(p_out));
91 }
92 }
93
94
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 MPI_Gatherv(local_chunk.data(), local_chunk_size, MPI_UNSIGNED_CHAR, image_out_full.data(), send_counts.data(),
95 displs.data(), MPI_UNSIGNED_CHAR, root, MPI_COMM_WORLD);
96
97 6 return true;
98 }
99
100 6 bool LinearContrastStretchingMPI::PostProcessingImpl() {
101 6 return true;
102 }
103
104 } // namespace kutergin_v_linear_contrast_stretching
105