GCC Code Coverage Report


Directory: ./
File: modules/task/include/task.hpp
Date: 2026-02-23 23:20:07
Exec Total Coverage
Lines: 70 70 100.0%
Functions: 87 107 81.3%
Branches: 70 128 54.7%

Line Branch Exec Source
1 #pragma once
2
3 #include <omp.h>
4
5 #include <array>
6 #include <chrono>
7 #include <cstdint>
8 #include <cstdlib>
9 #include <fstream>
10 #include <iomanip>
11 #include <iostream>
12 #include <memory>
13 #include <sstream>
14 #include <stdexcept>
15 #include <string>
16 #include <util/include/util.hpp>
17 #include <utility>
18
19 namespace ppc::task {
20
21 /// @brief Represents the type of task (parallelization technology).
22 /// @details Used to select the implementation type in tests and execution logic.
23 enum class TypeOfTask : uint8_t {
24 /// Use all available implementations
25 kALL,
26 /// MPI (Message Passing Interface)
27 kMPI,
28 /// OpenMP (Open Multi-Processing)
29 kOMP,
30 /// Sequential implementation
31 kSEQ,
32 /// Standard Thread Library (STL threads)
33 kSTL,
34 /// Intel Threading Building Blocks (TBB)
35 kTBB,
36 /// Unknown task type
37 kUnknown,
38 };
39
40 using TaskMapping = std::pair<TypeOfTask, std::string>;
41 using TaskMappingArray = std::array<TaskMapping, 6>;
42
43 const TaskMappingArray kTaskTypeMappings = {{{TypeOfTask::kALL, "all"},
44 {TypeOfTask::kMPI, "mpi"},
45 {TypeOfTask::kOMP, "omp"},
46 {TypeOfTask::kSEQ, "seq"},
47 {TypeOfTask::kSTL, "stl"},
48 {TypeOfTask::kTBB, "tbb"}}};
49
50 6340 inline std::string TypeOfTaskToString(TypeOfTask type) {
51
2/2
✓ Branch 0 taken 19650 times.
✓ Branch 1 taken 40 times.
19690 for (const auto &[key, value] : kTaskTypeMappings) {
52
2/2
✓ Branch 0 taken 6300 times.
✓ Branch 1 taken 13350 times.
19650 if (key == type) {
53 return value;
54 }
55 }
56 40 return "unknown";
57 }
58
59 /// @brief Indicates whether a task is enabled or disabled.
60 enum class StatusOfTask : uint8_t {
61 /// Task is enabled and should be executed
62 kEnabled,
63 /// Task is disabled and will be skipped
64 kDisabled,
65 };
66
67 /// @brief Returns a string representation of the task status.
68 /// @param status_of_task Task status (enabled or disabled).
69 /// @return "enabled" if the task is enabled, otherwise "disabled".
70 inline std::string GetStringTaskStatus(StatusOfTask status_of_task) {
71 if (status_of_task == StatusOfTask::kDisabled) {
72
1/2
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
20 return "disabled";
73 }
74
1/2
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
20 return "enabled";
75 }
76
77 /// @brief Returns a string representation of the task type based on the JSON settings file.
78 /// @param type_of_task Type of the task.
79 /// @param settings_file_path Path to the JSON file containing task type strings.
80 /// @return Formatted string combining the task type and its corresponding value from the file.
81 /// @throws std::runtime_error If the file cannot be opened.
82 6400 inline std::string GetStringTaskType(TypeOfTask type_of_task, const std::string &settings_file_path) {
83 6400 std::ifstream file(settings_file_path);
84
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 6360 times.
6400 if (!file.is_open()) {
85
2/4
✓ Branch 2 taken 40 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 40 times.
✗ Branch 6 not taken.
80 throw std::runtime_error("Failed to open " + settings_file_path);
86 }
87
88 auto list_settings = ppc::util::InitJSONPtr();
89
2/2
✓ Branch 1 taken 6340 times.
✓ Branch 2 taken 20 times.
6360 file >> *list_settings;
90
91
1/2
✓ Branch 1 taken 6340 times.
✗ Branch 2 not taken.
6340 std::string type_str = TypeOfTaskToString(type_of_task);
92
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 6300 times.
6340 if (type_str == "unknown") {
93 40 return type_str;
94 }
95
96
4/8
✓ Branch 1 taken 6300 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6300 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 6280 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 6280 times.
✗ Branch 11 not taken.
31460 return type_str + "_" + std::string((*list_settings)["tasks"][type_str]);
97 6400 }
98
99 enum class StateOfTesting : uint8_t {
100 kFunc,
101 kPerf,
102 };
103
104 template <typename InType, typename OutType>
105 /// @brief Base abstract class representing a generic task with a defined pipeline.
106 /// @tparam InType Input data type.
107 /// @tparam OutType Output data type.
108
6/12
✓ Branch 1 taken 693 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 38 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 60 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 10 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 10 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 10 times.
✗ Branch 17 not taken.
1089 class Task {
109 public:
110 /// @brief Validates input data and task attributes before execution.
111 /// @return True if validation is successful.
112 1616 virtual bool Validation() final {
113
2/2
✓ Branch 0 taken 1271 times.
✓ Branch 1 taken 10 times.
1616 if (stage_ == PipelineStage::kNone || stage_ == PipelineStage::kDone) {
114 1596 stage_ = PipelineStage::kValidation;
115 } else {
116 20 stage_ = PipelineStage::kException;
117
1/2
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
20 throw std::runtime_error("Validation should be called before preprocessing");
118 }
119 1596 return ValidationImpl();
120 }
121
122 /// @brief Performs preprocessing on the input data.
123 /// @return True if preprocessing is successful.
124 1576 virtual bool PreProcessing() final {
125
2/2
✓ Branch 0 taken 1241 times.
✓ Branch 1 taken 20 times.
1576 if (stage_ == PipelineStage::kValidation) {
126 1536 stage_ = PipelineStage::kPreProcessing;
127 } else {
128 40 stage_ = PipelineStage::kException;
129
1/2
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
40 throw std::runtime_error("Preprocessing should be called after validation");
130 }
131
2/2
✓ Branch 0 taken 1041 times.
✓ Branch 1 taken 200 times.
1536 if (state_of_testing_ == StateOfTesting::kFunc) {
132 1136 InternalTimeTest();
133 }
134 1536 return PreProcessingImpl();
135 }
136
137 /// @brief Executes the main logic of the task.
138 /// @return True if execution is successful.
139 1726 virtual bool Run() final {
140
2/2
✓ Branch 0 taken 1316 times.
✓ Branch 1 taken 20 times.
1726 if (stage_ == PipelineStage::kPreProcessing || stage_ == PipelineStage::kRun) {
141 1686 stage_ = PipelineStage::kRun;
142 } else {
143 40 stage_ = PipelineStage::kException;
144
1/2
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
40 throw std::runtime_error("Run should be called after preprocessing");
145 }
146 1686 return RunImpl();
147 }
148
149 /// @brief Performs postprocessing on the output data.
150 /// @return True if postprocessing is successful.
151 1576 virtual bool PostProcessing() final {
152
2/2
✓ Branch 0 taken 1226 times.
✓ Branch 1 taken 35 times.
1576 if (stage_ == PipelineStage::kRun) {
153 1506 stage_ = PipelineStage::kDone;
154 } else {
155 70 stage_ = PipelineStage::kException;
156
1/2
✓ Branch 2 taken 35 times.
✗ Branch 3 not taken.
70 throw std::runtime_error("Postprocessing should be called after run");
157 }
158
2/2
✓ Branch 0 taken 1026 times.
✓ Branch 1 taken 200 times.
1506 if (state_of_testing_ == StateOfTesting::kFunc) {
159 1106 InternalTimeTest();
160 }
161 1466 return PostProcessingImpl();
162 }
163
164 /// @brief Returns the current testing mode.
165 /// @return Reference to the current StateOfTesting.
166 StateOfTesting &GetStateOfTesting() {
167 return state_of_testing_;
168 }
169
170 /// @brief Sets the dynamic task type.
171 /// @param type_of_task Task type to set.
172 void SetTypeOfTask(TypeOfTask type_of_task) {
173
1/2
✓ Branch 1 taken 170 times.
✗ Branch 2 not taken.
956 type_of_task_ = type_of_task;
174 }
175
176 /// @brief Returns the dynamic task type.
177 /// @return Current dynamic task type.
178 [[nodiscard]] TypeOfTask GetDynamicTypeOfTask() const {
179
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 return type_of_task_;
180 }
181
182 /// @brief Returns the current task status.
183 /// @return Task status (enabled or disabled).
184 [[nodiscard]] StatusOfTask GetStatusOfTask() const {
185 return status_of_task_;
186 }
187
188 /// @brief Returns the static task type.
189 /// @return Static task type (default: kUnknown).
190 static constexpr TypeOfTask GetStaticTypeOfTask() {
191 return TypeOfTask::kUnknown;
192 }
193
194 /// @brief Returns a reference to the input data.
195 /// @return Reference to the task's input data.
196 InType &GetInput() {
197
7/13
✓ Branch 1 taken 451 times.
✓ Branch 2 taken 114 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 38 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 60 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 10 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 10 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 10 times.
✗ Branch 17 not taken.
814 return input_;
198 }
199
200 /// @brief Returns a reference to the output data.
201 /// @return Reference to the task's output data.
202 OutType &GetOutput() {
203
5/10
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 110 times.
✓ Branch 2 taken 80 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 38 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 10 times.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
1384 return output_;
204 }
205
206 /// @brief Destructor. Verifies that the pipeline was executed in the correct order.
207 /// @note Terminates the program if the pipeline order is incorrect or incomplete.
208 1706 virtual ~Task() {
209 1736 if (stage_ != PipelineStage::kDone && stage_ != PipelineStage::kException) {
210 ppc::util::DestructorFailureFlag::Set();
211 }
212 #if _OPENMP >= 201811
213 omp_pause_resource_all(omp_pause_soft);
214 #endif
215
4/24
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 833 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 10 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
1736 }
216
217 protected:
218 /// @brief Measures execution time between preprocessing and postprocessing steps.
219 /// @throws std::runtime_error If execution exceeds the allowed time limit.
220 2242 virtual void InternalTimeTest() final {
221
2/2
✓ Branch 0 taken 1041 times.
✓ Branch 1 taken 1026 times.
2242 if (stage_ == PipelineStage::kPreProcessing) {
222 1136 tmp_time_point_ = std::chrono::high_resolution_clock::now();
223 }
224
225
2/2
✓ Branch 0 taken 1026 times.
✓ Branch 1 taken 1041 times.
2242 if (stage_ == PipelineStage::kDone) {
226 1106 auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() -
227 tmp_time_point_)
228 .count();
229 1106 auto diff = static_cast<double>(duration) * 1e-9;
230
231 1106 const auto max_time = ppc::util::GetTaskMaxTime();
232 1106 std::stringstream err_msg;
233
2/2
✓ Branch 0 taken 1006 times.
✓ Branch 1 taken 20 times.
1106 if (diff < max_time) {
234
1/2
✓ Branch 1 taken 1006 times.
✗ Branch 2 not taken.
1066 err_msg << "Test time:" << std::fixed << std::setprecision(10) << diff << '\n';
235 } else {
236
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
40 err_msg << "\nTask execute time need to be: ";
237
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
40 err_msg << "time < " << max_time << " secs.\n";
238
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
40 err_msg << "Original time in secs: " << diff << '\n';
239
1/2
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
120 throw std::runtime_error(err_msg.str().c_str());
240 }
241 1106 }
242 2202 }
243
244 /// @brief User-defined validation logic.
245 /// @return True if validation is successful.
246 virtual bool ValidationImpl() = 0;
247
248 /// @brief User-defined preprocessing logic.
249 /// @return True if preprocessing is successful.
250 virtual bool PreProcessingImpl() = 0;
251
252 /// @brief User-defined task execution logic.
253 /// @return True if a run is successful.
254 virtual bool RunImpl() = 0;
255
256 /// @brief User-defined postprocessing logic.
257 /// @return True if postprocessing is successful.
258 virtual bool PostProcessingImpl() = 0;
259
260 private:
261 InType input_{};
262 OutType output_{};
263 StateOfTesting state_of_testing_ = StateOfTesting::kFunc;
264 TypeOfTask type_of_task_ = TypeOfTask::kUnknown;
265 StatusOfTask status_of_task_ = StatusOfTask::kEnabled;
266 std::chrono::high_resolution_clock::time_point tmp_time_point_;
267 enum class PipelineStage : uint8_t {
268 kNone,
269 kValidation,
270 kPreProcessing,
271 kRun,
272 kDone,
273 kException,
274 } stage_ = PipelineStage::kNone;
275 };
276
277 /// @brief Smart pointer alias for Task.
278 /// @tparam InType Input data type.
279 /// @tparam OutType Output data type.
280 template <typename InType, typename OutType>
281 using TaskPtr = std::shared_ptr<Task<InType, OutType>>;
282
283 /// @brief Constructs and returns a shared pointer to a task with the given input.
284 /// @tparam TaskType Type of the task to create.
285 /// @tparam InType Type of the input.
286 /// @param in Input to pass to the task constructor.
287 /// @return Shared a pointer to the newly created task.
288 template <typename TaskType, typename InType>
289 946 std::shared_ptr<TaskType> TaskGetter(const InType &in) {
290 946 return std::make_shared<TaskType>(in);
291 }
292
293 } // namespace ppc::task
294