1 /*
2  * Copyright (c) 2023-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef PANDA_LIBPANDABASE_TASKMANAGER_TASK_H
17 #define PANDA_LIBPANDABASE_TASKMANAGER_TASK_H
18 
19 #include "libpandabase/macros.h"
20 #include "libpandabase/utils/bit_utils.h"
21 #include "libpandabase/globals.h"
22 #include "libpandabase/utils/time.h"
23 #include "libpandabase/utils/logger.h"
24 #include <functional>
25 #include <ostream>
26 #include <array>
27 
28 namespace ark::taskmanager {
29 
30 /*
31  * TaskType - represents all types of components that can use TaskManager.
32  * UNKNOWN type - is a service type, it should be the last one in the list.
33  */
34 enum class TaskType : uint8_t { GC, JIT, UNKNOWN };
35 constexpr auto ALL_TASK_TYPES = std::array {TaskType::GC, TaskType::JIT};
36 constexpr uint8_t TASK_TYPE_NEEDED_BITS = MinimumBitsToStore(static_cast<size_t>(TaskType::UNKNOWN) - 1U);
37 static_assert(ALL_TASK_TYPES.size() == static_cast<size_t>(TaskType::UNKNOWN));
38 static_assert(std::is_same<decltype(ALL_TASK_TYPES)::value_type, TaskType>::value);
39 
40 /*
41  * VMType - represents all types of VM that can use TaskManager.
42  * UNKNOWN type - is a service type, it should be the last one in the list.
43  */
44 enum class VMType : uint8_t { DYNAMIC_VM, STATIC_VM, UNKNOWN };
45 constexpr auto ALL_VM_TYPES = std::array {VMType::DYNAMIC_VM, VMType::STATIC_VM};
46 constexpr uint8_t VM_TYPE_NEEDED_BITS = MinimumBitsToStore(static_cast<size_t>(VMType::UNKNOWN) - 1U);
47 static_assert(ALL_VM_TYPES.size() == static_cast<size_t>(VMType::UNKNOWN));
48 static_assert(std::is_same<decltype(ALL_VM_TYPES)::value_type, VMType>::value);
49 
50 /*
51  * TaskExecutionMode - represents all possible modes of tasks execution.
52  * UNKNOWN type - is a service type, it should be the last one in the list.
53  */
54 enum class TaskExecutionMode : uint8_t { FOREGROUND, BACKGROUND, UNKNOWN };
55 constexpr auto ALL_TASK_EXECUTION_MODES = std::array {TaskExecutionMode::FOREGROUND, TaskExecutionMode::BACKGROUND};
56 constexpr uint8_t EXECUTION_MODE_NEEDED_BITS = MinimumBitsToStore(static_cast<size_t>(TaskExecutionMode::UNKNOWN) - 1U);
57 static_assert(ALL_TASK_EXECUTION_MODES.size() == static_cast<size_t>(TaskExecutionMode::UNKNOWN));
58 static_assert(std::is_same<decltype(ALL_TASK_EXECUTION_MODES)::value_type, TaskExecutionMode>::value);
59 
60 /**
61  * @brief TaskProperties is class that consider all enums that are related to Task. It's used to parameterize task
62  * creation.
63  */
64 class TaskProperties {
65     // NOLINTBEGIN(hicpp-signed-bitwise)
66     /*
67      *  TaskProperties representation:
68      *
69      * +-------+-------------------------------+-------+-------+-------+
70      * | 0     |         zeros                 | Task  | VM    |Exec   |
71      * |       |                               |  Type |  Type | Mode  |
72      * +-------+-------------------------------+-------+-------+-------+
73      * +-------+-------------------------------------------------------+
74      * | 1     |         zeros     (invalid)                           |
75      * |       |                                                       |
76      * +-------+-------------------------------------------------------+
77      */
78     using StorageType = uint8_t;
79     // Checking that we have enough bits for correct representation
80     static_assert((TASK_TYPE_NEEDED_BITS + VM_TYPE_NEEDED_BITS + EXECUTION_MODE_NEEDED_BITS) <
81                   (sizeof(StorageType) * BITS_PER_BYTE));
82     StorageType val_;
83 
84     static constexpr StorageType TASK_TYPE_MASK = (1U << TASK_TYPE_NEEDED_BITS) - 1U;
85     static constexpr StorageType TASK_TYPE_SHIFT = VM_TYPE_NEEDED_BITS + EXECUTION_MODE_NEEDED_BITS;
86 
87     static constexpr StorageType VM_TYPE_MASK = (1U << VM_TYPE_NEEDED_BITS) - 1U;
88     static constexpr StorageType VM_TYPE_SHIFT = EXECUTION_MODE_NEEDED_BITS;
89 
90     static constexpr StorageType EXECUTION_MODE_MASK = (1U << EXECUTION_MODE_NEEDED_BITS) - 1U;
91 
GetInternalRepresentation(StorageType taskType, StorageType vmType, StorageType executionMode)92     static inline constexpr StorageType GetInternalRepresentation(StorageType taskType, StorageType vmType,
93                                                                   StorageType executionMode)
94     {
95         return (taskType << TASK_TYPE_SHIFT) | (vmType << VM_TYPE_SHIFT) | executionMode;
96     }
97 
98     static inline constexpr StorageType GetTaskTypeFromInternalRepresentation(StorageType val) noexcept
99     {
100         return (val >> TASK_TYPE_SHIFT) & TASK_TYPE_MASK;
101     }
102 
103     static inline constexpr StorageType GetVMTypeFromInternalRepresentation(StorageType val) noexcept
104     {
105         return (val >> VM_TYPE_SHIFT) & VM_TYPE_MASK;
106     }
107 
108     static inline constexpr StorageType GetExecutionModeFromInternalRepresentation(StorageType val) noexcept
109     {
110         return val & EXECUTION_MODE_MASK;
111     }
112 
113     static constexpr StorageType INVALID_INTERNAL_REPRESENTATION = 1U << (sizeof(StorageType) * BITS_PER_BYTE - 1U);
114 
115 public:
TaskProperties()116     constexpr TaskProperties() : val_(INVALID_INTERNAL_REPRESENTATION) {}
117 
TaskProperties(TaskType taskType, VMType vmType, TaskExecutionMode executionMode)118     constexpr TaskProperties(TaskType taskType, VMType vmType, TaskExecutionMode executionMode)
119         : val_(GetInternalRepresentation(static_cast<StorageType>(taskType), static_cast<StorageType>(vmType),
120                                          static_cast<StorageType>(executionMode)))
121     {
122     }
123 
GetTaskType() const124     constexpr TaskType GetTaskType() const
125     {
126         return static_cast<TaskType>(GetTaskTypeFromInternalRepresentation(val_));
127     }
128 
GetVMType() const129     constexpr VMType GetVMType() const
130     {
131         return static_cast<VMType>(GetVMTypeFromInternalRepresentation(val_));
132     }
133 
GetTaskExecutionMode() const134     constexpr TaskExecutionMode GetTaskExecutionMode() const
135     {
136         return static_cast<TaskExecutionMode>(GetExecutionModeFromInternalRepresentation(val_));
137     }
138 
operator ==(const TaskProperties &lv, const TaskProperties &rv)139     friend constexpr bool operator==(const TaskProperties &lv, const TaskProperties &rv)
140     {
141         return lv.val_ == rv.val_;
142     }
143 
144     class Hash {
145     public:
MaxValue()146         static constexpr size_t MaxValue()
147         {
148             return GetInternalRepresentation(static_cast<StorageType>(TaskType::UNKNOWN) - 1U,
149                                              static_cast<StorageType>(VMType::UNKNOWN) - 1U,
150                                              static_cast<StorageType>(TaskExecutionMode::UNKNOWN) - 1U);
151         }
152 
153         constexpr Hash() = default;
operator ()(const TaskProperties &properties) const154         constexpr size_t operator()(const TaskProperties &properties) const
155         {
156             return properties.val_;
157         }
158     };
159     // NOLINTEND(hicpp-signed-bitwise)
160 };
161 
162 constexpr auto INVALID_TASK_PROPERTIES = TaskProperties();
163 
164 PANDA_PUBLIC_API std::ostream &operator<<(std::ostream &os, TaskType type);
165 PANDA_PUBLIC_API std::ostream &operator<<(std::ostream &os, VMType type);
166 PANDA_PUBLIC_API std::ostream &operator<<(std::ostream &os, TaskExecutionMode mode);
167 PANDA_PUBLIC_API std::ostream &operator<<(std::ostream &os, TaskProperties prop);
168 
169 /**
170  * @brief TaskLifeTimeAggregator structure used to save and log life time of task and execution time.
171  * It's methods doesn't works on release build.
172  */
173 class TaskLifeTimeAggregator {
174 public:
175     NO_COPY_SEMANTIC(TaskLifeTimeAggregator);
176     DEFAULT_MOVE_SEMANTIC(TaskLifeTimeAggregator);
177 
178     PANDA_PUBLIC_API TaskLifeTimeAggregator() = default;
179 
180     /// @brief Saves time of task adding in queue.
181     PANDA_PUBLIC_API void GetAndStoreTimeOfTaskAddingToQueue();
182 
183     /// @brief Saves start time of execution. Use this method before task execution start
184     PANDA_PUBLIC_API void GetAndStoreTimeOfTaskExecutionStart();
185 
186     /// @brief Logs life time and execution time of task. Use this method after task execution end
187     PANDA_PUBLIC_API void GetTimeOfTaskExecutionFinishAndStoreTimeStats(TaskProperties prop);
188 
189     PANDA_PUBLIC_API ~TaskLifeTimeAggregator() = default;
190 
191 private:
192     // Time points for logs
193     uint64_t addingToQueueTime_ {0};
194     uint64_t startExecutionTime_ {0};
195 };
196 
197 class Task {
198 public:
199     PANDA_PUBLIC_API Task() = default;
200     NO_COPY_SEMANTIC(Task);
201     DEFAULT_MOVE_SEMANTIC(Task);
202 
203     using RunnerCallback = std::function<void()>;
204 
205     /**
206      * @brief Tasks are created through this method with the specified arguments.
207      * @param properties - properties of task, it contains TaskType, VMType and ExecutionMote.
208      * @param runner - body of task, that will be executed.
209      */
210     [[nodiscard]] PANDA_PUBLIC_API static Task Create(TaskProperties properties, RunnerCallback runner);
211 
212     /// @brief Returns properties of task
213     PANDA_PUBLIC_API TaskProperties GetTaskProperties() const;
214 
215     /// @brief Executes body of task
216     PANDA_PUBLIC_API void RunTask();
217 
218     /**
219      * @brief Makes task invalid, it should not be executed anymore.
220      * @see INVALID_TASK_PROPERTIES
221      */
222     PANDA_PUBLIC_API void MakeInvalid();
223 
224     /**
225      * @brief Checks if task is invalid
226      * @see INVALID_TASK_PROPERTIES
227      */
228     PANDA_PUBLIC_API bool IsInvalid() const;
229 
230     PANDA_PUBLIC_API void EventOnTaskAdding();
231 
232     PANDA_PUBLIC_API ~Task() = default;
233 
234 private:
Task(TaskProperties properties, RunnerCallback runner)235     Task(TaskProperties properties, RunnerCallback runner) : properties_(properties), runner_(std::move(runner)) {}
236 
237     PANDA_PUBLIC_API void EventOnStartExecution();
238     PANDA_PUBLIC_API void EventOnEndExecution();
239 
240     TaskProperties properties_ {INVALID_TASK_PROPERTIES};
241     RunnerCallback runner_ {nullptr};
242     TaskLifeTimeAggregator lifeTimeStorage_;
243 };
244 
245 }  // namespace ark::taskmanager
246 
247 #endif  // PANDA_LIBPANDABASE_TASKMANAGER_TASK_H
248