GCC Code Coverage Report


Directory: ./
File: modules/task/include/task.hpp
Date: 2026-04-03 01:43:48
Exec Total Coverage
Lines: 70 70 100.0%
Functions: 34 36 94.4%
Branches: 68 111 61.3%

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