• 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 "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