1 /*
2  * Copyright (c) 2020 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 #ifndef OHOS_ACELITE_JS_PROFILER_H
16 #define OHOS_ACELITE_JS_PROFILER_H
17 #include <cstdint>
18 #include <stddef.h>
19 #include "acelite_config.h"
20 #include "js_config.h"
21 #include "memory_heap.h"
22 #include "non_copyable.h"
23 
24 /*
25  * Wrapper macro, use directly in code after including this header file.
26  */
27 #if IS_ENABLED(JS_PROFILER)
28 // start tracing for one given phase, and return a traceId which will be used when calling STOP_TRACING
29 #define START_TRACING(traceTag) JSProfiler::GetInstance()->PushTrace(traceTag, 0, 0)
30 // start tracing for one given phase, and provids the component name together
31 #define START_TRACING_WITH_COMPONENT_NAME(traceTag, componentNameId) \
32     JSProfiler::GetInstance()->PushTrace(traceTag, componentNameId, 0)
33 #define START_TRACING_WITH_EXTRA_INFO(traceTag, componentNameId, extraInfoId) \
34     JSProfiler::GetInstance()->PushTrace(traceTag, componentNameId, extraInfoId)
35 // stop tracing
36 #define STOP_TRACING() JSProfiler::GetInstance()->PopTrace()
37 #define OUTPUT_TRACE() JSProfiler::GetInstance()->Output()
38 #else // ENABLED(JS_PROFILER)
39 #define START_TRACING(traceTag)
40 #define START_TRACING_WITH_COMPONENT_NAME(traceTag, componentNameId)
41 #define START_TRACING_WITH_EXTRA_INFO(traceTag, componentNameId, extraInfoId)
42 #define STOP_TRACING()
43 #define OUTPUT_TRACE()
44 #endif // ENABLED(JS_PROFILER)
45 
46 // invoked into compiling only if performance measurement enabled
47 #if IS_ENABLED(JS_PROFILER)
48 namespace OHOS {
49 namespace ACELite {
50 /**
51  * Define all trace point tags for performance measurement.
52  *
53  * NOTE: KEEP SYNC WITH g_PerformanceTagName in cpp file
54  */
55 enum PerformanceTag {
56     P_UNKNOWN = 0X00,
57     LAUNCH,
58     ENGINE_INIT,
59     FWK_INIT,
60     JS_BEGIN,
61     JS_FWK_EVAL,           // 5
62     JS_APP_INIT,           // 6
63     JS_INIT_STATE,         // 7
64     JS_INIT_DATA_GET_DATA, // 8
65     JS_INIT_DATA_PROXY,    // 9
66     JS_INIT_DATA_OBSERVE,  // 10
67     JS_END,
68     FWK_CODE_LOAD,
69     FWK_CODE_EVAL,
70     APP_CODE_LOAD,
71     APP_CODE_EVAL,
72     PAGE_CODE_LOAD,
73     PAGE_CODE_EVAL,
74     STYLESHEET_INIT,
75     APP_ON_CREATE,
76     APP_ON_DESTROY,
77     ROUTER_REPLACE,
78     PAGE_TRANSFER_DATA,
79     PAGE_ON_INIT,
80     PAGE_ON_READY,
81     PAGE_ON_SHOW,
82     PAGE_ON_BACKGROUND,
83     PAGE_ON_DESTROY,
84     RENDER,
85     ADD_TO_ROOT_VIEW,
86     RENDER_CREATE_COMPONENT,
87     RENDER_COMBINE_STYLE,
88     RENDER_BIND_JS_OBJECT,
89     RENDER_PARSE_ATTR,
90     RENDER_PARSE_EVENT,
91     RENDER_APPLY_STYLE,
92     RENDER_PROCESS_CHILDREN,
93     SET_ATTR_PARSE_EXPRESSION,
94     SET_ATTR_STRING_OF,
95     SET_ATTR_PARSE_KEY_ID,
96     SET_ATTR_SET_TO_NATIVE,
97     APPLY_STYLE_ITEM,
98     WATCHER_CALLBACK_FUNC,
99     FOR_WATCHER_CALLBACK_FUNC,
100     WATCHER_CONSTRUCT
101 };
102 
103 /**
104  * The max count of tracing we can support at the same time.
105  * NOTE: please define this value as a multiple of 2, and dont make it's bigger than 256
106  */
107 constexpr uint8_t maxCountAllAtOnce = 16;
108 
109 // need more data slots for static profiling mode, as we record them all before output the result
110 constexpr uint16_t maxTracingDataCount = 512;
111 
112 /**
113  * Performance data holder.
114  */
115 struct PerformanceData {
116     uint64_t start; // count in clock ticks (usually 1ms)
117     uint64_t end;
118     uint8_t label;       // what's the phase this time cost data is representing
119     uint8_t description; // other description, NOTE: we don't do string copy, so const char* must be given
120     uint8_t component;
121 };
122 
123 #if (FEATURE_ACELITE_MC_JS_PROFILER == 1)
124 static constexpr uint8_t MSG_LENGTH = 20;
125 
126 struct ProfilerMsg {
127     char msg[MSG_LENGTH] = {'\0'};
128 };
129 #endif
130 
131 /**
132  * @brief The JSProfiler class is an runtime performance recorder and outputter, used for recording
133  *        runtime timecost mainly. Implemented for development and will be disabled for release version.
134  */
135 class JSProfiler final : public MemoryHeap {
136 public:
137     ACE_DISALLOW_COPY_AND_MOVE(JSProfiler);
138     /**
139      * @brief Default constructor.
140      */
141     JSProfiler();
142 
143     /**
144      * @brief Default destructor.
145      */
146     ~JSProfiler();
147 
148     /**
149      * @brief Use static global variable for easy access in different source code file.
150      *
151      * @return global JSProfiler object
152      */
153     static JSProfiler *GetInstance();
154 
155     /**
156      * Called to free all performance data records and the global JSProfiler object.
157      */
158     void Release();
159 
160 #if (FEATURE_ACELITE_MC_JS_PROFILER == 1)
161     /**
162      * @brief Flush output to file.
163      */
164     static void FlushProfilerMsg(void *data);
165 #endif
166 
167     /**
168      * @brief Clean all performance record in data_.
169      */
170     void ResetData();
171 
172     /**
173      * @brief Record the current timestamp for the given tag.
174      *
175      * @param [in] tag The given phase's trace name, must be given.
176      * @param [in] name The component name of the current tracing phase, default is null.
177      * @param [in] description The extra description string id (must can be parsed by KeyParser)
178      * for this trace, default is null.
179      *
180      */
181     void PushTrace(PerformanceTag tag, uint8_t name, uint8_t description);
182 
183     /**
184      * @brief Calculate the time interval and log out.
185      *
186      */
187     void PopTrace();
188 
189     /**
190      * @brief Calculate all time cost and output to trace.
191      *
192      * NOTE: Delay the elapsed time calculating to this method to save band width.
193      */
194     void Output();
195 
196     /**
197      * @brief Get current timestamp for recording.
198      *
199      * @return the current timestamp, count in clock tick, will be converted into ms during output performance data
200      */
201     uint64_t GetCurrentClockTick() const;
202 
203     /**
204      * @brief Calculate the elapsed milliseconds from two input clock timestamp.
205      *
206      * @param [in] start The start timestamp, must count in clock tick.
207      * @param [in] end The end timestamp, must count in clock tick.
208      *
209      * @return the elapsed time from start to end, count in ms
210      */
211     uint64_t CalculateElapsedTime(uint64_t start, uint64_t end) const;
212 
213     /**
214      * @brief Check if the profiler is enabled or not.
215      *
216      * @return true for enabled, false for not
217      */
218     bool IsEnabled();
219 
220     /**
221      * @brief malloc data buffer for saving performance data.
222      */
223     void PrepareDataBuffer();
224 
225 private:
226     /**
227      * The trace id stack, MAX_COUNT_ALL_AT_ONCE at the same time
228      */
229     uint16_t traceIdStack_[maxTracingDataCount] = {0};
230 
231     /**
232      * The tracing data
233      */
234     PerformanceData *data_ = nullptr;
235 
236     uint16_t dataCount_ = 0;
237     uint16_t traceIdSlot_ = 0;
238     bool enabled_ = false;
239 #if (FEATURE_ACELITE_MC_JS_PROFILER == 1)
240     static constexpr uint8_t PROFILER_MSG_LENGTH = 128;
241     static constexpr uint8_t TEXT_LENGTH = 30;
242     ProfilerMsg *msg_ = nullptr;
243 #endif
244 };
245 } // namespace ACELite
246 } // namespace OHOS
247 
248 #endif // ENABLED(JS_PROFILER)
249 #endif // OHOS_ACELITE_JS_PROFILER_H
250