GCC Code Coverage Report


Directory: ./
File: tasks/krykov_e_word_count/mpi/src/ops_mpi.cpp
Date: 2025-12-13 04:24:21
Exec Total Coverage
Lines: 72 72 100.0%
Functions: 7 7 100.0%
Branches: 59 84 70.2%

Line Branch Exec Source
1 #include "krykov_e_word_count/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <algorithm>
6 #include <cctype>
7 #include <cstdint>
8 #include <ranges>
9 #include <string>
10 #include <utility>
11 #include <vector>
12
13 #include "krykov_e_word_count/common/include/common.hpp"
14
15 namespace krykov_e_word_count {
16
17 namespace {
18 void ChunkSizesAndDispls(int text_size, int world_size, std::vector<int> &chunk_sizes, std::vector<int> &displs) {
19 44 int base_size = text_size / world_size;
20 44 int remainder = text_size % world_size;
21
22 int offset = 0;
23
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 44 times.
132 for (int i = 0; i < world_size; ++i) {
24
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 24 times.
152 chunk_sizes[i] = base_size + (i < remainder ? 1 : 0);
25 88 displs[i] = offset;
26 88 offset += chunk_sizes[i];
27 }
28 }
29
30 44 uint64_t CountWordsInChunk(const std::vector<char> &local_chunk) {
31 uint64_t local_count = 0;
32 bool in_word = false;
33
2/2
✓ Branch 0 taken 274 times.
✓ Branch 1 taken 44 times.
318 for (char c : local_chunk) {
34
2/2
✓ Branch 0 taken 238 times.
✓ Branch 1 taken 36 times.
274 if (std::isspace(static_cast<unsigned char>(c)) != 0) {
35 in_word = false;
36 } else {
37
2/2
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 180 times.
238 if (!in_word) {
38 in_word = true;
39 58 ++local_count;
40 }
41 }
42 }
43 44 return local_count;
44 }
45
46
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 2 times.
44 std::pair<int, int> StartsEndsFromChunk(const std::vector<char> &local_chunk) {
47 int starts_with_space = 1;
48 int ends_with_space = 1;
49
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 2 times.
44 if (!local_chunk.empty()) {
50
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 5 times.
42 starts_with_space = (std::isspace(static_cast<unsigned char>(local_chunk.front())) != 0) ? 1 : 0;
51
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 7 times.
42 ends_with_space = (std::isspace(static_cast<unsigned char>(local_chunk.back())) != 0) ? 1 : 0;
52 }
53 44 return {starts_with_space, ends_with_space};
54 }
55
56 } // namespace
57
58
1/2
✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
44 KrykovEWordCountMPI::KrykovEWordCountMPI(const InType &in) {
59 SetTypeOfTask(GetStaticTypeOfTask());
60 GetInput() = in;
61 44 GetOutput() = 0;
62 44 }
63
64
1/2
✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
44 bool KrykovEWordCountMPI::ValidationImpl() {
65
2/4
✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 44 times.
44 return (!GetInput().empty()) && (GetOutput() == 0);
66 }
67
68 44 bool KrykovEWordCountMPI::PreProcessingImpl() {
69 const auto &input = GetInput();
70 auto trimmed = input;
71
72 44 trimmed.erase(trimmed.begin(),
73
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 44 times.
58 std::ranges::find_if(trimmed, [](char ch) { return !std::isspace(static_cast<unsigned char>(ch)); }));
74
75
1/2
✓ Branch 2 taken 44 times.
✗ Branch 3 not taken.
44 trimmed.erase(std::ranges::find_if(std::ranges::reverse_view(trimmed),
76 [](char ch) {
77
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 44 times.
58 return !std::isspace(static_cast<unsigned char>(ch));
78 }).base(),
79 trimmed.end());
80
81 GetInput() = trimmed;
82 44 return true;
83 }
84
85 44 bool KrykovEWordCountMPI::RunImpl() {
86 const std::string &text = GetInput();
87
88 44 int world_size = 0;
89 44 int world_rank = 0;
90 44 MPI_Comm_size(MPI_COMM_WORLD, &world_size);
91 44 MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
92
93 44 int text_size = static_cast<int>(text.size());
94 44 MPI_Bcast(&text_size, 1, MPI_INT, 0, MPI_COMM_WORLD);
95
96 44 std::vector<int> chunk_sizes(world_size);
97
1/4
✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
44 std::vector<int> displs(world_size);
98
99 44 ChunkSizesAndDispls(text_size, world_size, chunk_sizes, displs);
100
101
1/2
✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
44 int local_size = chunk_sizes[world_rank];
102
1/4
✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
44 std::vector<char> local_chunk(local_size);
103
104 44 std::vector<char> text_buf;
105
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 22 times.
44 if (world_rank == 0) {
106 22 text_buf.assign(text.begin(), text.end());
107 }
108
109
3/4
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 22 times.
✓ Branch 3 taken 44 times.
✗ Branch 4 not taken.
66 MPI_Scatterv(world_rank == 0 ? text_buf.data() : nullptr, chunk_sizes.data(), displs.data(), MPI_CHAR,
110 local_chunk.data(), local_size, MPI_CHAR, 0, MPI_COMM_WORLD);
111
112 44 uint64_t local_count = CountWordsInChunk(local_chunk);
113
114 44 auto [starts_with_space, ends_with_space] = StartsEndsFromChunk(local_chunk);
115
116
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 37 times.
44 auto start_flag = static_cast<unsigned char>(starts_with_space == 0 ? 1 : 0);
117
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 35 times.
44 auto end_flag = static_cast<unsigned char>(ends_with_space == 0 ? 1 : 0);
118
119
1/4
✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
44 std::vector<unsigned char> all_starts(world_size);
120
2/6
✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 44 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
44 std::vector<unsigned char> all_ends(world_size);
121
122
1/2
✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
44 MPI_Allgather(&start_flag, 1, MPI_UNSIGNED_CHAR, all_starts.data(), 1, MPI_UNSIGNED_CHAR, MPI_COMM_WORLD);
123
124
1/2
✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
44 MPI_Allgather(&end_flag, 1, MPI_UNSIGNED_CHAR, all_ends.data(), 1, MPI_UNSIGNED_CHAR, MPI_COMM_WORLD);
125
126 44 uint64_t total_words = 0;
127
1/2
✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
44 MPI_Allreduce(&local_count, &total_words, 1, MPI_UINT64_T, MPI_SUM, MPI_COMM_WORLD);
128
129 44 uint64_t boundary_fixes = 0;
130
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 22 times.
44 if (world_rank > 0) {
131
4/4
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 3 times.
22 if (all_ends[world_rank - 1] == 1 && all_starts[world_rank] == 1) {
132 12 boundary_fixes = 1;
133 }
134 }
135
136 44 uint64_t total_boundary_fixes = 0;
137
1/2
✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
44 MPI_Allreduce(&boundary_fixes, &total_boundary_fixes, 1, MPI_UINT64_T, MPI_SUM, MPI_COMM_WORLD);
138
139 44 total_words -= total_boundary_fixes;
140
141
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 22 times.
44 if (world_rank == 0) {
142 22 GetOutput() = static_cast<int>(total_words);
143 }
144
145 44 int result = 0;
146
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 22 times.
44 if (world_rank == 0) {
147 22 result = GetOutput();
148 }
149
1/2
✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
44 MPI_Bcast(&result, 1, MPI_INT, 0, MPI_COMM_WORLD);
150
151
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 22 times.
44 if (world_rank != 0) {
152 22 GetOutput() = result;
153 }
154
155 44 return true;
156 }
157
158 44 bool KrykovEWordCountMPI::PostProcessingImpl() {
159 44 return true;
160 }
161
162 } // namespace krykov_e_word_count
163