GCC Code Coverage Report


Directory: ./
File: tasks/tsarkov_k_lexicographic_string_compare/mpi/src/ops_mpi.cpp
Date: 2026-02-23 23:20:07
Exec Total Coverage
Lines: 56 56 100.0%
Functions: 6 6 100.0%
Branches: 32 44 72.7%

Line Branch Exec Source
1 #include "tsarkov_k_lexicographic_string_compare/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <algorithm>
6 #include <cstddef>
7 #include <cstdint>
8 #include <limits>
9 #include <string>
10 #include <utility>
11 #include <vector>
12
13 #include "tsarkov_k_lexicographic_string_compare/common/include/common.hpp"
14
15 namespace tsarkov_k_lexicographic_string_compare {
16
17 namespace {
18
19 std::vector<char> StringToBuffer(const std::string &s) {
20
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 return {s.begin(), s.end()};
21 }
22
23 std::string BufferToString(const std::vector<char> &buf) {
24 12 return {buf.begin(), buf.end()};
25 }
26
27 24 void BroadcastString(std::string *value, int root, MPI_Comm comm) {
28 24 int rank = 0;
29 24 MPI_Comm_rank(comm, &rank);
30
31 24 int size = 0;
32
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 if (rank == root) {
33 12 size = static_cast<int>(value->size());
34 }
35
36 24 MPI_Bcast(&size, 1, MPI_INT, root, comm);
37
38 24 std::vector<char> buf;
39
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 if (rank == root) {
40 12 buf = StringToBuffer(*value);
41 } else {
42
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 buf.resize(static_cast<std::size_t>(size));
43 }
44
45
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 8 times.
24 if (size > 0) {
46
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 MPI_Bcast(buf.data(), size, MPI_CHAR, root, comm);
47 }
48
49
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 if (rank != root) {
50
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
24 *value = BufferToString(buf);
51 }
52 24 }
53
54 std::uint64_t FindFirstDiffLocal(const std::string &first_str, const std::string &second_str, std::size_t begin,
55 std::size_t end) {
56 const std::size_t no_index = std::numeric_limits<std::size_t>::max();
57 std::size_t first_diff_index = no_index;
58
59
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 10 times.
17 for (std::size_t index = begin; index < end; ++index) {
60
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
7 if (first_str[index] != second_str[index]) {
61 first_diff_index = index;
62 break;
63 }
64 }
65
66 if (first_diff_index == no_index) {
67 return std::numeric_limits<std::uint64_t>::max();
68 }
69 return static_cast<std::uint64_t>(first_diff_index);
70 }
71
72 int CompareAtIndexOrByLength(const std::string &first_str, const std::string &second_str, std::uint64_t global_first) {
73 12 if (global_first == std::numeric_limits<std::uint64_t>::max()) {
74
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
8 return (first_str.size() <= second_str.size()) ? 1 : 0;
75 }
76
77 const auto index = static_cast<std::size_t>(global_first);
78 4 const auto first_ch = static_cast<unsigned char>(first_str[index]);
79 4 const auto second_ch = static_cast<unsigned char>(second_str[index]);
80
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 return (first_ch <= second_ch) ? 1 : 0;
81 }
82
83 } // namespace
84
85
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 TsarkovKLexicographicStringCompareMPI::TsarkovKLexicographicStringCompareMPI(const InType &in) {
86 SetTypeOfTask(GetStaticTypeOfTask());
87 GetInput() = in;
88 12 GetOutput() = 0;
89 12 }
90
91 12 bool TsarkovKLexicographicStringCompareMPI::ValidationImpl() {
92 12 return GetOutput() == 0;
93 }
94
95 12 bool TsarkovKLexicographicStringCompareMPI::PreProcessingImpl() {
96 12 GetOutput() = 0;
97 12 return true;
98 }
99
100 12 bool TsarkovKLexicographicStringCompareMPI::RunImpl() {
101 12 int process_rank = 0;
102 12 int process_count = 1;
103 12 MPI_Comm_rank(MPI_COMM_WORLD, &process_rank);
104 12 MPI_Comm_size(MPI_COMM_WORLD, &process_count);
105
106 std::string first_str;
107 std::string second_str;
108
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 if (process_rank == 0) {
109
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 first_str = GetInput().first;
110
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 second_str = GetInput().second;
111 }
112
113
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 BroadcastString(&first_str, 0, MPI_COMM_WORLD);
114
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 BroadcastString(&second_str, 0, MPI_COMM_WORLD);
115
116 12 const std::size_t min_length = std::min(first_str.size(), second_str.size());
117
118 12 const std::size_t proc_cnt = (process_count > 0) ? static_cast<std::size_t>(process_count) : 1U;
119
120 12 const std::size_t block_size = (min_length + proc_cnt - 1U) / proc_cnt;
121 12 const std::size_t block_begin = std::min(min_length, block_size * static_cast<std::size_t>(process_rank));
122 12 const std::size_t block_end = std::min(min_length, block_begin + block_size);
123
124 12 const std::uint64_t local_first_diff = FindFirstDiffLocal(first_str, second_str, block_begin, block_end);
125
126 12 std::uint64_t global_first_diff = std::numeric_limits<std::uint64_t>::max();
127
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 MPI_Allreduce(&local_first_diff, &global_first_diff, 1, MPI_UINT64_T, MPI_MIN, MPI_COMM_WORLD);
128
129
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
12 const int result = CompareAtIndexOrByLength(first_str, second_str, global_first_diff);
130
131 12 GetOutput() = result;
132 12 return true;
133 }
134
135 12 bool TsarkovKLexicographicStringCompareMPI::PostProcessingImpl() {
136
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
12 return (GetOutput() == 0) || (GetOutput() == 1);
137 }
138
139 } // namespace tsarkov_k_lexicographic_string_compare
140