1 /*
2 * Copyright (C) 2022 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 #include <atomic>
17 #include <cinttypes>
18 #include <climits>
19 #include <ctime>
20 #include <fcntl.h>
21 #include <fstream>
22 #include <mutex>
23 #include <unistd.h>
24 #include <vector>
25 #include "securec.h"
26 #include "hilog/log.h"
27 #include "parameter.h"
28 #include "parameters.h"
29 #include "hitrace_meter.h"
30
31 using namespace std;
32 using namespace OHOS::HiviewDFX;
33
34 #define EXPECTANTLY(exp) (__builtin_expect(!!(exp), true))
35 #define UNEXPECTANTLY(exp) (__builtin_expect(!!(exp), false))
36 #define UNUSED_PARAM __attribute__((__unused__))
37
38 namespace {
39 int g_markerFd = -1;
40 std::once_flag g_onceFlag;
41
42 std::atomic<bool> g_isHitraceMeterDisabled(false);
43 std::atomic<bool> g_isHitraceMeterInit(false);
44 std::atomic<uint64_t> g_tagsProperty(HITRACE_TAG_NOT_READY);
45
46 const std::string KEY_TRACE_TAG = "debug.hitrace.tags.enableflags";
47 const std::string KEY_APP_NUMBER = "debug.hitrace.app_number";
48 const std::string KEY_RO_DEBUGGABLE = "ro.debuggable";
49 const std::string KEY_PREFIX = "debug.hitrace.app_";
50
51 constexpr int NAME_MAX_SIZE = 1000;
52 constexpr int VAR_NAME_MAX_SIZE = 256;
53
54 static std::vector<std::string> g_markTypes = {"B", "E", "S", "F", "C"};
55 enum MarkerType { MARKER_BEGIN, MARKER_END, MARKER_ASYNC_BEGIN, MARKER_ASYNC_END, MARKER_INT, MARKER_MAX };
56
57 constexpr uint64_t HITRACE_TAG = 0xD002D33;
58 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HITRACE_TAG, "HitraceMeter"};
59
ParameterChange(const char * key,const char * value,void * context)60 static void ParameterChange(const char* key, const char* value, void* context)
61 {
62 HiLog::Info(LABEL, "ParameterChange enableflags %{public}s", value);
63 UpdateTraceLabel();
64 }
65
IsAppValid()66 bool IsAppValid()
67 {
68 // Judge if application-level tracing is enabled.
69 if (OHOS::system::GetBoolParameter(KEY_RO_DEBUGGABLE, 0)) {
70 std::ifstream fs;
71 fs.open("/proc/self/cmdline");
72 if (!fs.is_open()) {
73 fprintf(stderr, "IsAppValid, open /proc/self/cmdline failed.\n");
74 return false;
75 }
76
77 std::string lineStr;
78 std::getline(fs, lineStr);
79 int nums = OHOS::system::GetIntParameter<int>(KEY_APP_NUMBER, 0);
80 for (int i = 0; i < nums; i++) {
81 std::string keyStr = KEY_PREFIX + std::to_string(i);
82 std::string val = OHOS::system::GetParameter(keyStr, "");
83 if (val == "*" || val == lineStr) {
84 fs.close();
85 return true;
86 }
87 }
88 }
89 return false;
90 }
91
GetSysParamTags()92 uint64_t GetSysParamTags()
93 {
94 // Get the system parameters of KEY_TRACE_TAG.
95 uint64_t tags = OHOS::system::GetUintParameter<uint64_t>(KEY_TRACE_TAG, 0);
96 if (tags == 0) {
97 // HiLog::Error(LABEL, "GetUintParameter %s error.\n", KEY_TRACE_TAG.c_str());
98 return 0;
99 }
100
101 IsAppValid();
102 return (tags | HITRACE_TAG_ALWAYS) & HITRACE_TAG_VALID_MASK;
103 }
104
105 // open file "trace_marker".
OpenTraceMarkerFile()106 void OpenTraceMarkerFile()
107 {
108 const std::string debugFile = "/sys/kernel/debug/tracing/trace_marker";
109 const std::string traceFile = "/sys/kernel/tracing/trace_marker";
110 g_markerFd = open(debugFile.c_str(), O_WRONLY | O_CLOEXEC);
111 if (g_markerFd == -1) {
112 HiLog::Error(LABEL, "open trace file %{public}s failed: %{public}d", debugFile.c_str(), errno);
113 g_markerFd = open(traceFile.c_str(), O_WRONLY | O_CLOEXEC);
114 if (g_markerFd == -1) {
115 HiLog::Error(LABEL, "open trace file %{public}s failed: %{public}d", traceFile.c_str(), errno);
116 g_tagsProperty = 0;
117 return;
118 }
119 }
120 g_tagsProperty = GetSysParamTags();
121
122 if (WatchParameter(KEY_TRACE_TAG.c_str(), ParameterChange, nullptr) != 0) {
123 HiLog::Error(LABEL, "WatchParameter %{public}s failed", KEY_TRACE_TAG.c_str());
124 return;
125 }
126 g_isHitraceMeterInit = true;
127 }
128 }; // namespace
129
AddHitraceMeterMarker(MarkerType type,uint64_t tag,const std::string & name,const std::string & value)130 void AddHitraceMeterMarker(MarkerType type, uint64_t tag, const std::string& name, const std::string& value)
131 {
132 if (UNEXPECTANTLY(g_isHitraceMeterDisabled)) {
133 return;
134 }
135 if (UNEXPECTANTLY(!g_isHitraceMeterInit)) {
136 struct timespec ts = { 0, 0 };
137 if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1 || ts.tv_sec < 20) { // 20 : register after boot 20s
138 return;
139 }
140 std::call_once(g_onceFlag, OpenTraceMarkerFile);
141 }
142 if (UNEXPECTANTLY(g_tagsProperty & tag)) {
143 // record fomart: "type|pid|name value".
144 std::string record = g_markTypes[type] + "|";
145 record += std::to_string(getpid()) + "|";
146 record += (name.size() < NAME_MAX_SIZE) ? name : name.substr(0, NAME_MAX_SIZE);
147 record += " " + value;
148 if (write(g_markerFd, record.c_str(), record.size()) < 0) {
149 HiLog::Error(LABEL, "write trace_marker failed, %{public}d", errno);
150 }
151 }
152 }
153
UpdateTraceLabel()154 void UpdateTraceLabel()
155 {
156 if (!g_isHitraceMeterInit) {
157 return;
158 }
159 g_tagsProperty = GetSysParamTags();
160 }
161
SetTraceDisabled(bool disable)162 void SetTraceDisabled(bool disable)
163 {
164 g_isHitraceMeterDisabled = disable;
165 }
166
StartTrace(uint64_t label,const string & value,float limit UNUSED_PARAM)167 void StartTrace(uint64_t label, const string& value, float limit UNUSED_PARAM)
168 {
169 string traceName = "H:" + value;
170 AddHitraceMeterMarker(MARKER_BEGIN, label, traceName, "");
171 }
172
StartTraceDebug(bool isDebug,uint64_t label,const string & value,float limit UNUSED_PARAM)173 void StartTraceDebug(bool isDebug, uint64_t label, const string& value, float limit UNUSED_PARAM)
174 {
175 if (!isDebug) {
176 return;
177 }
178 string traceName = "H:" + value;
179 AddHitraceMeterMarker(MARKER_BEGIN, label, traceName, "");
180 }
181
StartTraceArgs(uint64_t label,const char * fmt,...)182 void StartTraceArgs(uint64_t label, const char *fmt, ...)
183 {
184 char name[VAR_NAME_MAX_SIZE] = { 0 };
185 va_list args;
186 va_start(args, fmt);
187 int res = vsnprintf_s(name, sizeof(name), sizeof(name) - 1, fmt, args);
188 va_end(args);
189 if (res < 0) {
190 HiLog::Error(LABEL, "vsnprintf_s failed: %{public}d", errno);
191 return;
192 }
193 StartTrace(label, name, -1);
194 }
195
StartTraceArgsDebug(bool isDebug,uint64_t label,const char * fmt,...)196 void StartTraceArgsDebug(bool isDebug, uint64_t label, const char *fmt, ...)
197 {
198 if (!isDebug) {
199 return;
200 }
201 char name[VAR_NAME_MAX_SIZE] = { 0 };
202 va_list args;
203
204 va_start(args, fmt);
205 int res = vsnprintf_s(name, sizeof(name), sizeof(name) - 1, fmt, args);
206 va_end(args);
207 if (res < 0) {
208 HiLog::Error(LABEL, "vsnprintf_s failed: %{public}d", errno);
209 return;
210 }
211 StartTrace(label, name, -1);
212 }
213
FinishTrace(uint64_t label)214 void FinishTrace(uint64_t label)
215 {
216 AddHitraceMeterMarker(MARKER_END, label, "", "");
217 }
218
FinishTraceDebug(bool isDebug,uint64_t label)219 void FinishTraceDebug(bool isDebug, uint64_t label)
220 {
221 if (!isDebug) {
222 return;
223 }
224 AddHitraceMeterMarker(MARKER_END, label, "", "");
225 }
226
StartAsyncTrace(uint64_t label,const string & value,int32_t taskId,float limit UNUSED_PARAM)227 void StartAsyncTrace(uint64_t label, const string& value, int32_t taskId, float limit UNUSED_PARAM)
228 {
229 string traceName = "H:" + value;
230 AddHitraceMeterMarker(MARKER_ASYNC_BEGIN, label, traceName, std::to_string(taskId));
231 }
232
StartAsyncTraceDebug(bool isDebug,uint64_t label,const string & value,int32_t taskId,float limit UNUSED_PARAM)233 void StartAsyncTraceDebug(bool isDebug, uint64_t label, const string& value, int32_t taskId, float limit UNUSED_PARAM)
234 {
235 if (!isDebug) {
236 return;
237 }
238 string traceName = "H:" + value;
239 AddHitraceMeterMarker(MARKER_ASYNC_BEGIN, label, traceName, std::to_string(taskId));
240 }
241
StartAsyncTraceArgs(uint64_t label,int32_t taskId,const char * fmt,...)242 void StartAsyncTraceArgs(uint64_t label, int32_t taskId, const char *fmt, ...)
243 {
244 char name[VAR_NAME_MAX_SIZE] = { 0 };
245 va_list args;
246
247 va_start(args, fmt);
248 int res = vsnprintf_s(name, sizeof(name), sizeof(name) - 1, fmt, args);
249 va_end(args);
250 if (res < 0) {
251 HiLog::Error(LABEL, "vsnprintf_s failed: %{public}d", errno);
252 return;
253 }
254 StartAsyncTrace(label, name, taskId, -1);
255 }
256
StartAsyncTraceArgsDebug(bool isDebug,uint64_t label,int32_t taskId,const char * fmt,...)257 void StartAsyncTraceArgsDebug(bool isDebug, uint64_t label, int32_t taskId, const char *fmt, ...)
258 {
259 if (!isDebug) {
260 return;
261 }
262 char name[VAR_NAME_MAX_SIZE] = { 0 };
263 va_list args;
264
265 va_start(args, fmt);
266 int res = vsnprintf_s(name, sizeof(name), sizeof(name) - 1, fmt, args);
267 va_end(args);
268 if (res < 0) {
269 HiLog::Error(LABEL, "vsnprintf_s failed: %{public}d", errno);
270 return;
271 }
272 StartAsyncTrace(label, name, taskId, -1);
273 }
274
FinishAsyncTrace(uint64_t label,const string & value,int32_t taskId)275 void FinishAsyncTrace(uint64_t label, const string& value, int32_t taskId)
276 {
277 string traceName = "H:" + value;
278 AddHitraceMeterMarker(MARKER_ASYNC_END, label, traceName, std::to_string(taskId));
279 }
280
FinishAsyncTraceDebug(bool isDebug,uint64_t label,const string & value,int32_t taskId)281 void FinishAsyncTraceDebug(bool isDebug, uint64_t label, const string& value, int32_t taskId)
282 {
283 if (!isDebug) {
284 return;
285 }
286 string traceName = "H:" + value;
287 AddHitraceMeterMarker(MARKER_ASYNC_END, label, traceName, std::to_string(taskId));
288 }
289
FinishAsyncTraceArgs(uint64_t label,int32_t taskId,const char * fmt,...)290 void FinishAsyncTraceArgs(uint64_t label, int32_t taskId, const char *fmt, ...)
291 {
292 char name[VAR_NAME_MAX_SIZE] = { 0 };
293 va_list args;
294
295 va_start(args, fmt);
296 int res = vsnprintf_s(name, sizeof(name), sizeof(name) - 1, fmt, args);
297 va_end(args);
298 if (res < 0) {
299 HiLog::Error(LABEL, "vsnprintf_s failed: %{public}d", errno);
300 return;
301 }
302 FinishAsyncTrace(label, name, taskId);
303 }
304
FinishAsyncTraceArgsDebug(bool isDebug,uint64_t label,int32_t taskId,const char * fmt,...)305 void FinishAsyncTraceArgsDebug(bool isDebug, uint64_t label, int32_t taskId, const char *fmt, ...)
306 {
307 if (!isDebug) {
308 return;
309 }
310 char name[VAR_NAME_MAX_SIZE] = { 0 };
311 va_list args;
312
313 va_start(args, fmt);
314 int res = vsnprintf_s(name, sizeof(name), sizeof(name) - 1, fmt, args);
315 va_end(args);
316 if (res < 0) {
317 HiLog::Error(LABEL, "vsnprintf_s failed: %{public}d", errno);
318 return;
319 }
320 FinishAsyncTrace(label, name, taskId);
321 }
322
MiddleTrace(uint64_t label,const string & beforeValue UNUSED_PARAM,const std::string & afterValue)323 void MiddleTrace(uint64_t label, const string& beforeValue UNUSED_PARAM, const std::string& afterValue)
324 {
325 string traceName = "H:" + afterValue;
326 AddHitraceMeterMarker(MARKER_END, label, "", "");
327 AddHitraceMeterMarker(MARKER_BEGIN, label, traceName, "");
328 }
329
MiddleTraceDebug(bool isDebug,uint64_t label,const string & beforeValue UNUSED_PARAM,const std::string & afterValue)330 void MiddleTraceDebug(bool isDebug, uint64_t label, const string& beforeValue UNUSED_PARAM,
331 const std::string& afterValue)
332 {
333 if (!isDebug) {
334 return;
335 }
336 string traceName = "H:" + afterValue;
337 AddHitraceMeterMarker(MARKER_END, label, "", "");
338 AddHitraceMeterMarker(MARKER_BEGIN, label, traceName, "");
339 }
340
CountTrace(uint64_t label,const string & name,int64_t count)341 void CountTrace(uint64_t label, const string& name, int64_t count)
342 {
343 string traceName = "H:" + name;
344 AddHitraceMeterMarker(MARKER_INT, label, traceName, std::to_string(count));
345 }
346
CountTraceDebug(bool isDebug,uint64_t label,const string & name,int64_t count)347 void CountTraceDebug(bool isDebug, uint64_t label, const string& name, int64_t count)
348 {
349 if (!isDebug) {
350 return;
351 }
352 string traceName = "H:" + name;
353 AddHitraceMeterMarker(MARKER_INT, label, traceName, std::to_string(count));
354 }
355
HitraceMeterFmtScoped(uint64_t label,const char * fmt,...)356 HitraceMeterFmtScoped::HitraceMeterFmtScoped(uint64_t label, const char *fmt, ...) : mTag(label)
357 {
358 char name[VAR_NAME_MAX_SIZE] = { 0 };
359 va_list args;
360
361 va_start(args, fmt);
362 int res = vsnprintf_s(name, sizeof(name), sizeof(name) - 1, fmt, args);
363 va_end(args);
364 if (res < 0) {
365 HiLog::Error(LABEL, "vsnprintf_s failed: %{public}d", errno);
366 return;
367 }
368 StartTrace(label, name, -1);
369 }
370