• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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