GCC Code Coverage Report


Directory: ./
File: modules/task/include/task.hpp
Date: 2026-01-02 01:56:52
Exec Total Coverage
Lines: 70 70 100.0%
Functions: 35 37 94.6%
Branches: 67 111 60.4%

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 1104 inline std::string TypeOfTaskToString(TypeOfTask type) {
51
2/2
✓ Branch 0 taken 3858 times.
✓ Branch 1 taken 40 times.
3898 for (const auto &[key, value] : kTaskTypeMappings) {
52
2/2
✓ Branch 0 taken 1064 times.
✓ Branch 1 taken 2794 times.
3858 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 1164 inline std::string GetStringTaskType(TypeOfTask type_of_task, const std::string &settings_file_path) {
83 1164 std::ifstream file(settings_file_path);
84
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 1124 times.
1164 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 1104 times.
✓ Branch 2 taken 20 times.
1124 file >> *list_settings;
90
91
1/2
✓ Branch 1 taken 1104 times.
✗ Branch 2 not taken.
1104 std::string type_str = TypeOfTaskToString(type_of_task);
92
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 1064 times.
1104 if (type_str == "unknown") {
93 40 return type_str;
94 }
95
96
4/8
✓ Branch 1 taken 1064 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1064 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1044 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1044 times.
✗ Branch 11 not taken.
5280 return type_str + "_" + std::string((*list_settings)["tasks"][type_str]);
97 1164 }
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 55 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 30 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.
343 class Task {
109 public:
110 /// @brief Validates input data and task attributes before execution.
111 /// @return True if validation is successful.
112 838 virtual bool Validation() final {
113
2/2
✓ Branch 0 taken 493 times.
✓ Branch 1 taken 10 times.
838 if (stage_ == PipelineStage::kNone || stage_ == PipelineStage::kDone) {
114 818 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 818 return ValidationImpl();
120 }
121
122 /// @brief Performs preprocessing on the input data.
123 /// @return True if preprocessing is successful.
124 798 virtual bool PreProcessing() final {
125
2/2
✓ Branch 0 taken 463 times.
✓ Branch 1 taken 20 times.
798 if (stage_ == PipelineStage::kValidation) {
126 758 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 263 times.
✓ Branch 1 taken 200 times.
758 if (state_of_testing_ == StateOfTesting::kFunc) {
132 358 InternalTimeTest();
133 }
134 758 return PreProcessingImpl();
135 }
136
137 /// @brief Executes the main logic of the task.
138 /// @return True if execution is successful.
139 948 virtual bool Run() final {
140
2/2
✓ Branch 0 taken 538 times.
✓ Branch 1 taken 20 times.
948 if (stage_ == PipelineStage::kPreProcessing || stage_ == PipelineStage::kRun) {
141 908 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 908 return RunImpl();
147 }
148
149 /// @brief Performs postprocessing on the output data.
150 /// @return True if postprocessing is successful.
151 798 virtual bool PostProcessing() final {
152
2/2
✓ Branch 0 taken 448 times.
✓ Branch 1 taken 35 times.
798 if (stage_ == PipelineStage::kRun) {
153 728 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 248 times.
✓ Branch 1 taken 200 times.
728 if (state_of_testing_ == StateOfTesting::kFunc) {
159 328 InternalTimeTest();
160 }
161 688 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 10 times.
✗ Branch 2 not taken.
178 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
6/12
✓ Branch 1 taken 55 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 30 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.
175 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
3/6
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 10 times.
✗ Branch 8 not taken.
198 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 350 virtual ~Task() {
209 380 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/12
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 155 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.
380 }
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 686 virtual void InternalTimeTest() final {
221
2/2
✓ Branch 0 taken 263 times.
✓ Branch 1 taken 248 times.
686 if (stage_ == PipelineStage::kPreProcessing) {
222 358 tmp_time_point_ = std::chrono::high_resolution_clock::now();
223 }
224
225
2/2
✓ Branch 0 taken 248 times.
✓ Branch 1 taken 263 times.
686 if (stage_ == PipelineStage::kDone) {
226 328 auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() -
227 tmp_time_point_)
228 .count();
229 328 auto diff = static_cast<double>(duration) * 1e-9;
230
231 328 const auto max_time = ppc::util::GetTaskMaxTime();
232 328 std::stringstream err_msg;
233
2/2
✓ Branch 0 taken 228 times.
✓ Branch 1 taken 20 times.
328 if (diff < max_time) {
234
1/2
✓ Branch 1 taken 228 times.
✗ Branch 2 not taken.
288 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 328 }
242 646 }
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 168 std::shared_ptr<TaskType> TaskGetter(const InType &in) {
290 168 return std::make_shared<TaskType>(in);
291 }
292
293 } // namespace ppc::task
294