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 "param/sys_param.h"
28 #include "parameter.h"
29 #include "parameters.h"
30 #include "hitrace_meter.h"
31 #include "hitrace/tracechain.h"
32
33 using namespace std;
34 using namespace OHOS::HiviewDFX;
35
36 #define EXPECTANTLY(exp) (__builtin_expect(!!(exp), true))
37 #define UNEXPECTANTLY(exp) (__builtin_expect(!!(exp), false))
38 #define UNUSED_PARAM __attribute__((__unused__))
39
40 namespace {
41 int g_markerFd = -1;
42 std::once_flag g_onceFlag;
43 std::once_flag g_onceWriteMarkerFailedFlag;
44 CachedHandle cachedHandle;
45
46 std::atomic<bool> g_isHitraceMeterDisabled(false);
47 std::atomic<bool> g_isHitraceMeterInit(false);
48 std::atomic<uint64_t> g_tagsProperty(HITRACE_TAG_NOT_READY);
49
50 const std::string KEY_TRACE_TAG = "debug.hitrace.tags.enableflags";
51 const std::string KEY_APP_NUMBER = "debug.hitrace.app_number";
52 const std::string KEY_RO_DEBUGGABLE = "ro.debuggable";
53 const std::string KEY_PREFIX = "debug.hitrace.app_";
54
55 constexpr int VAR_NAME_MAX_SIZE = 400;
56 constexpr int NAME_NORMAL_LEN = 512;
57 constexpr int BUFFER_LEN = 640;
58 constexpr int HITRACEID_LEN = 64;
59
60 static const int PID_BUF_SIZE = 6;
61 static char g_pid[PID_BUF_SIZE];
62 static const std::string EMPTY_TRACE_NAME;
63
64 static char g_markTypes[5] = {'B', 'E', 'S', 'F', 'C'};
65 enum MarkerType { MARKER_BEGIN, MARKER_END, MARKER_ASYNC_BEGIN, MARKER_ASYNC_END, MARKER_INT, MARKER_MAX };
66
67 constexpr uint64_t HITRACE_TAG = 0xD002D33;
68 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HITRACE_TAG, "HitraceMeter"};
69
IsAppValid()70 bool IsAppValid()
71 {
72 // Judge if application-level tracing is enabled.
73 if (OHOS::system::GetBoolParameter(KEY_RO_DEBUGGABLE, 0)) {
74 std::ifstream fs;
75 fs.open("/proc/self/cmdline");
76 if (!fs.is_open()) {
77 fprintf(stderr, "IsAppValid, open /proc/self/cmdline failed.\n");
78 return false;
79 }
80
81 std::string lineStr;
82 std::getline(fs, lineStr);
83 int nums = OHOS::system::GetIntParameter<int>(KEY_APP_NUMBER, 0);
84 for (int i = 0; i < nums; i++) {
85 std::string keyStr = KEY_PREFIX + std::to_string(i);
86 std::string val = OHOS::system::GetParameter(keyStr, "");
87 if (val == "*" || val == lineStr) {
88 fs.close();
89 return true;
90 }
91 }
92 }
93 return false;
94 }
95
GetSysParamTags()96 uint64_t GetSysParamTags()
97 {
98 // Get the system parameters of KEY_TRACE_TAG.
99 uint64_t tags = OHOS::system::GetUintParameter<uint64_t>(KEY_TRACE_TAG, 0);
100 if (tags == 0) {
101 // HiLog::Error(LABEL, "GetUintParameter %s error.\n", KEY_TRACE_TAG.c_str());
102 return 0;
103 }
104
105 IsAppValid();
106 return (tags | HITRACE_TAG_ALWAYS) & HITRACE_TAG_VALID_MASK;
107 }
108
109 // open file "trace_marker".
OpenTraceMarkerFile()110 void OpenTraceMarkerFile()
111 {
112 const std::string debugFile = "/sys/kernel/debug/tracing/trace_marker";
113 const std::string traceFile = "/sys/kernel/tracing/trace_marker";
114 g_markerFd = open(debugFile.c_str(), O_WRONLY | O_CLOEXEC);
115 if (g_markerFd == -1) {
116 HiLog::Error(LABEL, "open trace file %{public}s failed: %{public}d", debugFile.c_str(), errno);
117 g_markerFd = open(traceFile.c_str(), O_WRONLY | O_CLOEXEC);
118 if (g_markerFd == -1) {
119 HiLog::Error(LABEL, "open trace file %{public}s failed: %{public}d", traceFile.c_str(), errno);
120 g_tagsProperty = 0;
121 return;
122 }
123 }
124 // get tags and pid
125 g_tagsProperty = GetSysParamTags();
126 const char* devValue = "true";
127 cachedHandle = CachedParameterCreate(KEY_TRACE_TAG.c_str(), devValue);
128 std::string pidStr = std::to_string(getpid());
129 errno_t ret = strcpy_s(g_pid, PID_BUF_SIZE, pidStr.c_str());
130 if (ret != 0) {
131 strcpy_s(g_pid, PID_BUF_SIZE, pidStr.c_str());
132 }
133 HiLog::Error(LABEL, "pid[%{public}s] first get g_tagsProperty: %{public}s", pidStr.c_str(),
134 to_string(g_tagsProperty.load()).c_str());
135
136 g_isHitraceMeterInit = true;
137 }
138
WriteFailedLog()139 void WriteFailedLog()
140 {
141 HiLog::Error(LABEL, "write trace_marker failed, %{public}d", errno);
142 }
143
WriteToTraceMarker(const char * buf,const int count)144 void WriteToTraceMarker(const char* buf, const int count)
145 {
146 if (UNEXPECTANTLY(count <= 0)) {
147 return;
148 }
149 if (UNEXPECTANTLY(count >= BUFFER_LEN)) {
150 return;
151 }
152 if (write(g_markerFd, buf, count) < 0) {
153 std::call_once(g_onceWriteMarkerFailedFlag, WriteFailedLog);
154 }
155 }
156
AddTraceMarkerLarge(const std::string & name,MarkerType type,const int64_t value)157 void AddTraceMarkerLarge(const std::string& name, MarkerType type, const int64_t value)
158 {
159 std::string record;
160 record += g_markTypes[type];
161 record += "|";
162 record += g_pid;
163 record += "|H:";
164 HiTraceId hiTraceId = HiTraceChain::GetId();
165 if (hiTraceId.IsValid()) {
166 char buf[HITRACEID_LEN] = {0};
167 int bytes = snprintf_s(buf, sizeof(buf), sizeof(buf) - 1, "[%llx,%llx,%llx]#",
168 hiTraceId.GetChainId(), hiTraceId.GetSpanId(), hiTraceId.GetParentSpanId());
169 if (EXPECTANTLY(bytes > 0)) {
170 record += buf;
171 }
172 }
173 record += name;
174 record += " ";
175 if (value != 0) {
176 record += std::to_string(value);
177 }
178 WriteToTraceMarker(record.c_str(), record.size());
179 }
180
AddHitraceMeterMarker(MarkerType type,uint64_t tag,const std::string & name,const int64_t value)181 void AddHitraceMeterMarker(MarkerType type, uint64_t tag, const std::string& name, const int64_t value)
182 {
183 if (UNEXPECTANTLY(g_isHitraceMeterDisabled)) {
184 return;
185 }
186 if (UNEXPECTANTLY(!g_isHitraceMeterInit)) {
187 struct timespec ts = { 0, 0 };
188 if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1 || ts.tv_sec < 20) { // 20 : register after boot 20s
189 return;
190 }
191 std::call_once(g_onceFlag, OpenTraceMarkerFile);
192 }
193 int changed = 0;
194 const char *paramValue = CachedParameterGetChanged(cachedHandle, &changed);
195 if (changed == 1) {
196 HiLog::Info(LABEL, "g_tagsProperty changed, previous is %{public}s.", to_string(g_tagsProperty.load()).c_str());
197 uint64_t tags = strtoull(paramValue, nullptr, 0);
198 g_tagsProperty = (tags | HITRACE_TAG_ALWAYS) & HITRACE_TAG_VALID_MASK;
199 HiLog::Info(LABEL, "g_tagsProperty changed, now is %{public}s.", to_string(g_tagsProperty.load()).c_str());
200 }
201 if (UNEXPECTANTLY(g_tagsProperty & tag) && g_markerFd != -1) {
202 // record fomart: "type|pid|name value".
203 char buf[BUFFER_LEN] = {0};
204 int len = name.length();
205 if (UNEXPECTANTLY(len <= NAME_NORMAL_LEN)) {
206 HiTraceId hiTraceId = HiTraceChain::GetId();
207 bool isHiTraceIdValid = hiTraceId.IsValid();
208 int bytes = 0;
209 if (type == MARKER_BEGIN) {
210 bytes = isHiTraceIdValid ? snprintf_s(buf, sizeof(buf), sizeof(buf) - 1,
211 "B|%s|H:[%llx,%llx,%llx]#%s ", g_pid, hiTraceId.GetChainId(),
212 hiTraceId.GetSpanId(), hiTraceId.GetParentSpanId(), name.c_str())
213 : snprintf_s(buf, sizeof(buf), sizeof(buf) - 1, "B|%s|H:%s ", g_pid, name.c_str());
214 } else if (type == MARKER_END) {
215 bytes = snprintf_s(buf, sizeof(buf), sizeof(buf) - 1,
216 "E|%s|", g_pid);
217 } else {
218 char marktypestr = g_markTypes[type];
219 bytes = isHiTraceIdValid ? snprintf_s(buf, sizeof(buf), sizeof(buf) - 1,
220 "%c|%s|H:[%llx,%llx,%llx]#%s %lld", marktypestr, g_pid,
221 hiTraceId.GetChainId(), hiTraceId.GetSpanId(), hiTraceId.GetParentSpanId(), name.c_str(), value)
222 : snprintf_s(buf, sizeof(buf), sizeof(buf) - 1,
223 "%c|%s|H:%s %lld", marktypestr, g_pid, name.c_str(), value);
224 }
225 WriteToTraceMarker(buf, bytes);
226 } else {
227 AddTraceMarkerLarge(name, type, value);
228 }
229 }
230 }
231 }; // namespace
232
UpdateTraceLabel()233 void UpdateTraceLabel()
234 {
235 if (!g_isHitraceMeterInit) {
236 return;
237 }
238 g_tagsProperty = GetSysParamTags();
239 }
240
SetTraceDisabled(bool disable)241 void SetTraceDisabled(bool disable)
242 {
243 g_isHitraceMeterDisabled = disable;
244 }
245
StartTraceWrapper(uint64_t label,const char * value)246 void StartTraceWrapper(uint64_t label, const char *value)
247 {
248 std::string traceValue = value;
249 StartTrace(label, traceValue);
250 }
251
StartTrace(uint64_t label,const string & value,float limit UNUSED_PARAM)252 void StartTrace(uint64_t label, const string& value, float limit UNUSED_PARAM)
253 {
254 AddHitraceMeterMarker(MARKER_BEGIN, label, value, 0);
255 }
256
StartTraceDebug(bool isDebug,uint64_t label,const string & value,float limit UNUSED_PARAM)257 void StartTraceDebug(bool isDebug, uint64_t label, const string& value, float limit UNUSED_PARAM)
258 {
259 if (!isDebug) {
260 return;
261 }
262 AddHitraceMeterMarker(MARKER_BEGIN, label, value, 0);
263 }
264
StartTraceArgs(uint64_t label,const char * fmt,...)265 void StartTraceArgs(uint64_t label, const char *fmt, ...)
266 {
267 char name[VAR_NAME_MAX_SIZE] = { 0 };
268 va_list args;
269 va_start(args, fmt);
270 int res = vsnprintf_s(name, sizeof(name), sizeof(name) - 1, fmt, args);
271 va_end(args);
272 if (res < 0) {
273 HiLog::Error(LABEL, "vsnprintf_s failed: %{public}d", errno);
274 return;
275 }
276 AddHitraceMeterMarker(MARKER_BEGIN, label, name, 0);
277 }
278
StartTraceArgsDebug(bool isDebug,uint64_t label,const char * fmt,...)279 void StartTraceArgsDebug(bool isDebug, uint64_t label, const char *fmt, ...)
280 {
281 if (!isDebug) {
282 return;
283 }
284 char name[VAR_NAME_MAX_SIZE] = { 0 };
285 va_list args;
286
287 va_start(args, fmt);
288 int res = vsnprintf_s(name, sizeof(name), sizeof(name) - 1, fmt, args);
289 va_end(args);
290 if (res < 0) {
291 HiLog::Error(LABEL, "vsnprintf_s failed: %{public}d", errno);
292 return;
293 }
294 AddHitraceMeterMarker(MARKER_BEGIN, label, name, 0);
295 }
296
FinishTrace(uint64_t label)297 void FinishTrace(uint64_t label)
298 {
299 AddHitraceMeterMarker(MARKER_END, label, EMPTY_TRACE_NAME, 0);
300 }
301
FinishTraceDebug(bool isDebug,uint64_t label)302 void FinishTraceDebug(bool isDebug, uint64_t label)
303 {
304 if (!isDebug) {
305 return;
306 }
307 AddHitraceMeterMarker(MARKER_END, label, EMPTY_TRACE_NAME, 0);
308 }
309
StartAsyncTrace(uint64_t label,const string & value,int32_t taskId,float limit UNUSED_PARAM)310 void StartAsyncTrace(uint64_t label, const string& value, int32_t taskId, float limit UNUSED_PARAM)
311 {
312 AddHitraceMeterMarker(MARKER_ASYNC_BEGIN, label, value, taskId);
313 }
314
StartAsyncTraceWrapper(uint64_t label,const char * value,int32_t taskId)315 void StartAsyncTraceWrapper(uint64_t label, const char *value, int32_t taskId)
316 {
317 std::string traceValue = value;
318 StartAsyncTrace(label, traceValue, taskId);
319 }
320
StartAsyncTraceDebug(bool isDebug,uint64_t label,const string & value,int32_t taskId,float limit UNUSED_PARAM)321 void StartAsyncTraceDebug(bool isDebug, uint64_t label, const string& value, int32_t taskId, float limit UNUSED_PARAM)
322 {
323 if (!isDebug) {
324 return;
325 }
326 AddHitraceMeterMarker(MARKER_ASYNC_BEGIN, label, value, taskId);
327 }
328
StartAsyncTraceArgs(uint64_t label,int32_t taskId,const char * fmt,...)329 void StartAsyncTraceArgs(uint64_t label, int32_t taskId, const char *fmt, ...)
330 {
331 char name[VAR_NAME_MAX_SIZE] = { 0 };
332 va_list args;
333
334 va_start(args, fmt);
335 int res = vsnprintf_s(name, sizeof(name), sizeof(name) - 1, fmt, args);
336 va_end(args);
337 if (res < 0) {
338 HiLog::Error(LABEL, "vsnprintf_s failed: %{public}d", errno);
339 return;
340 }
341 AddHitraceMeterMarker(MARKER_ASYNC_BEGIN, label, name, taskId);
342 }
343
StartAsyncTraceArgsDebug(bool isDebug,uint64_t label,int32_t taskId,const char * fmt,...)344 void StartAsyncTraceArgsDebug(bool isDebug, uint64_t label, int32_t taskId, const char *fmt, ...)
345 {
346 if (!isDebug) {
347 return;
348 }
349 char name[VAR_NAME_MAX_SIZE] = { 0 };
350 va_list args;
351
352 va_start(args, fmt);
353 int res = vsnprintf_s(name, sizeof(name), sizeof(name) - 1, fmt, args);
354 va_end(args);
355 if (res < 0) {
356 HiLog::Error(LABEL, "vsnprintf_s failed: %{public}d", errno);
357 return;
358 }
359 AddHitraceMeterMarker(MARKER_ASYNC_BEGIN, label, name, taskId);
360 }
361
FinishAsyncTrace(uint64_t label,const string & value,int32_t taskId)362 void FinishAsyncTrace(uint64_t label, const string& value, int32_t taskId)
363 {
364 AddHitraceMeterMarker(MARKER_ASYNC_END, label, value, taskId);
365 }
366
FinishAsyncTraceWrapper(uint64_t label,const char * value,int32_t taskId)367 void FinishAsyncTraceWrapper(uint64_t label, const char *value, int32_t taskId)
368 {
369 std::string traceValue = value;
370 FinishAsyncTrace(label, traceValue, taskId);
371 }
372
FinishAsyncTraceDebug(bool isDebug,uint64_t label,const string & value,int32_t taskId)373 void FinishAsyncTraceDebug(bool isDebug, uint64_t label, const string& value, int32_t taskId)
374 {
375 if (!isDebug) {
376 return;
377 }
378 AddHitraceMeterMarker(MARKER_ASYNC_END, label, value, taskId);
379 }
380
FinishAsyncTraceArgs(uint64_t label,int32_t taskId,const char * fmt,...)381 void FinishAsyncTraceArgs(uint64_t label, int32_t taskId, const char *fmt, ...)
382 {
383 char name[VAR_NAME_MAX_SIZE] = { 0 };
384 va_list args;
385
386 va_start(args, fmt);
387 int res = vsnprintf_s(name, sizeof(name), sizeof(name) - 1, fmt, args);
388 va_end(args);
389 if (res < 0) {
390 HiLog::Error(LABEL, "vsnprintf_s failed: %{public}d", errno);
391 return;
392 }
393 AddHitraceMeterMarker(MARKER_ASYNC_END, label, name, taskId);
394 }
395
FinishAsyncTraceArgsDebug(bool isDebug,uint64_t label,int32_t taskId,const char * fmt,...)396 void FinishAsyncTraceArgsDebug(bool isDebug, uint64_t label, int32_t taskId, const char *fmt, ...)
397 {
398 if (!isDebug) {
399 return;
400 }
401 char name[VAR_NAME_MAX_SIZE] = { 0 };
402 va_list args;
403
404 va_start(args, fmt);
405 int res = vsnprintf_s(name, sizeof(name), sizeof(name) - 1, fmt, args);
406 va_end(args);
407 if (res < 0) {
408 HiLog::Error(LABEL, "vsnprintf_s failed: %{public}d", errno);
409 return;
410 }
411 AddHitraceMeterMarker(MARKER_ASYNC_END, label, name, taskId);
412 }
413
MiddleTrace(uint64_t label,const string & beforeValue UNUSED_PARAM,const std::string & afterValue)414 void MiddleTrace(uint64_t label, const string& beforeValue UNUSED_PARAM, const std::string& afterValue)
415 {
416 AddHitraceMeterMarker(MARKER_END, label, EMPTY_TRACE_NAME, 0);
417 AddHitraceMeterMarker(MARKER_BEGIN, label, afterValue, 0);
418 }
419
MiddleTraceDebug(bool isDebug,uint64_t label,const string & beforeValue UNUSED_PARAM,const std::string & afterValue)420 void MiddleTraceDebug(bool isDebug, uint64_t label, const string& beforeValue UNUSED_PARAM,
421 const std::string& afterValue)
422 {
423 if (!isDebug) {
424 return;
425 }
426 AddHitraceMeterMarker(MARKER_END, label, EMPTY_TRACE_NAME, 0);
427 AddHitraceMeterMarker(MARKER_BEGIN, label, afterValue, 0);
428 }
429
CountTrace(uint64_t label,const string & name,int64_t count)430 void CountTrace(uint64_t label, const string& name, int64_t count)
431 {
432 AddHitraceMeterMarker(MARKER_INT, label, name, count);
433 }
434
CountTraceDebug(bool isDebug,uint64_t label,const string & name,int64_t count)435 void CountTraceDebug(bool isDebug, uint64_t label, const string& name, int64_t count)
436 {
437 if (!isDebug) {
438 return;
439 }
440 AddHitraceMeterMarker(MARKER_INT, label, name, count);
441 }
442
CountTraceWrapper(uint64_t label,const char * name,int64_t count)443 void CountTraceWrapper(uint64_t label, const char *name, int64_t count)
444 {
445 std::string traceName = name;
446 CountTrace(label, traceName, count);
447 }
448
HitraceMeterFmtScoped(uint64_t label,const char * fmt,...)449 HitraceMeterFmtScoped::HitraceMeterFmtScoped(uint64_t label, const char *fmt, ...) : mTag(label)
450 {
451 char name[VAR_NAME_MAX_SIZE] = { 0 };
452 va_list args;
453
454 va_start(args, fmt);
455 int res = vsnprintf_s(name, sizeof(name), sizeof(name) - 1, fmt, args);
456 va_end(args);
457 if (res < 0) {
458 HiLog::Error(LABEL, "vsnprintf_s failed: %{public}d", errno);
459 return;
460 }
461 AddHitraceMeterMarker(MARKER_BEGIN, label, name, 0);
462 }
463