1570af302Sopenharmony_ci
2570af302Sopenharmony_ci/*
3570af302Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd.
4570af302Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
5570af302Sopenharmony_ci * you may not use this file except in compliance with the License.
6570af302Sopenharmony_ci * You may obtain a copy of the License at
7570af302Sopenharmony_ci *
8570af302Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
9570af302Sopenharmony_ci *
10570af302Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
11570af302Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
12570af302Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13570af302Sopenharmony_ci * See the License for the specific language governing permissions and
14570af302Sopenharmony_ci * limitations under the License.
15570af302Sopenharmony_ci */
16570af302Sopenharmony_ci
17570af302Sopenharmony_ci#include <trace/trace_marker.h>
18570af302Sopenharmony_ci
19570af302Sopenharmony_ci#include <errno.h>
20570af302Sopenharmony_ci#include <fcntl.h>
21570af302Sopenharmony_ci#include <stdbool.h>
22570af302Sopenharmony_ci#include <stdio.h>
23570af302Sopenharmony_ci#include <stdlib.h>
24570af302Sopenharmony_ci#include <string.h>
25570af302Sopenharmony_ci#include <sys/types.h>
26570af302Sopenharmony_ci#include <unistd.h>
27570af302Sopenharmony_ci#include "musl_log.h"
28570af302Sopenharmony_ci#ifdef OHOS_ENABLE_PARAMETER
29570af302Sopenharmony_ci#include "sys_param.h"
30570af302Sopenharmony_ci#endif
31570af302Sopenharmony_ci
32570af302Sopenharmony_ci#ifndef MUSL_TEMP_FAILURE_RETRY
33570af302Sopenharmony_ci#define MUSL_TEMP_FAILURE_RETRY(exp)           \
34570af302Sopenharmony_ci    ({                                         \
35570af302Sopenharmony_ci    long int _rc;                              \
36570af302Sopenharmony_ci    do {                                       \
37570af302Sopenharmony_ci        _rc = (long int)(exp);                 \
38570af302Sopenharmony_ci    } while ((_rc == -1) && (errno == EINTR)); \
39570af302Sopenharmony_ci    _rc;                                       \
40570af302Sopenharmony_ci    })
41570af302Sopenharmony_ci#endif
42570af302Sopenharmony_ci
43570af302Sopenharmony_ci#define LIKELY(exp) (__builtin_expect(!!(exp), 1))
44570af302Sopenharmony_ci
45570af302Sopenharmony_ci#ifdef OHOS_ENABLE_PARAMETER
46570af302Sopenharmony_ci#define TRACE_PROPERTY_FLAG "debug.hitrace.tags.enableflags"
47570af302Sopenharmony_cistatic uint64_t g_trace_switch_status = 0;
48570af302Sopenharmony_ci
49570af302Sopenharmony_ciuint64_t get_uint64_sysparam(CachedHandle cachedhandle)
50570af302Sopenharmony_ci{
51570af302Sopenharmony_ci    char *param_value = CachedParameterGet(cachedhandle);
52570af302Sopenharmony_ci    if (param_value != NULL) {
53570af302Sopenharmony_ci        return strtoull(param_value, NULL, 0);
54570af302Sopenharmony_ci    }
55570af302Sopenharmony_ci    return 0;
56570af302Sopenharmony_ci}
57570af302Sopenharmony_ci#endif
58570af302Sopenharmony_ci
59570af302Sopenharmony_civoid trace_marker_reset(void)
60570af302Sopenharmony_ci{
61570af302Sopenharmony_ci#ifdef OHOS_ENABLE_PARAMETER
62570af302Sopenharmony_ci    static CachedHandle trace_switch_handle = NULL;
63570af302Sopenharmony_ci    if (trace_switch_handle == NULL) {
64570af302Sopenharmony_ci        trace_switch_handle = CachedParameterCreate(TRACE_PROPERTY_FLAG, "0");
65570af302Sopenharmony_ci    }
66570af302Sopenharmony_ci    g_trace_switch_status = get_uint64_sysparam(trace_switch_handle);
67570af302Sopenharmony_ci#else
68570af302Sopenharmony_ci    return;
69570af302Sopenharmony_ci#endif
70570af302Sopenharmony_ci}
71570af302Sopenharmony_ci
72570af302Sopenharmony_ci// Check whether the user space trace function is enabled
73570af302Sopenharmony_cistatic inline bool is_enable_trace(uint64_t label)
74570af302Sopenharmony_ci{
75570af302Sopenharmony_ci#ifdef OHOS_ENABLE_PARAMETER
76570af302Sopenharmony_ci    return (((g_trace_switch_status & label) != 0) || ((g_trace_switch_status & HITRACE_TAG_ALWAYS) != 0));
77570af302Sopenharmony_ci#else
78570af302Sopenharmony_ci    return false;
79570af302Sopenharmony_ci#endif
80570af302Sopenharmony_ci}
81570af302Sopenharmony_ci
82570af302Sopenharmony_ci// Get the fd of trace_marker
83570af302Sopenharmony_cistatic inline int get_trace_marker_fd(void)
84570af302Sopenharmony_ci{
85570af302Sopenharmony_ci    int trace_marker_fd = MUSL_TEMP_FAILURE_RETRY(open("/sys/kernel/tracing/trace_marker", O_CLOEXEC | O_WRONLY | O_APPEND));
86570af302Sopenharmony_ci    if (trace_marker_fd == -1) {
87570af302Sopenharmony_ci        trace_marker_fd = MUSL_TEMP_FAILURE_RETRY(open("/sys/kernel/debug/tracing/trace_marker", O_CLOEXEC | O_WRONLY | O_APPEND));
88570af302Sopenharmony_ci    }
89570af302Sopenharmony_ci    return trace_marker_fd;
90570af302Sopenharmony_ci}
91570af302Sopenharmony_ci
92570af302Sopenharmony_ci/* Write the function call information to the trace_marker node in kernel space,
93570af302Sopenharmony_ciused on the same thread as trace_marker_end(),with the symbol "B". */
94570af302Sopenharmony_civoid trace_marker_begin(uint64_t label, const char *message, const char *value)
95570af302Sopenharmony_ci{
96570af302Sopenharmony_ci    if (LIKELY((!is_enable_trace(label) || message == NULL))) {
97570af302Sopenharmony_ci        return;
98570af302Sopenharmony_ci    }
99570af302Sopenharmony_ci
100570af302Sopenharmony_ci    int trace_marker_fd = get_trace_marker_fd();
101570af302Sopenharmony_ci    if (trace_marker_fd == -1) {
102570af302Sopenharmony_ci        return;
103570af302Sopenharmony_ci    }
104570af302Sopenharmony_ci
105570af302Sopenharmony_ci    char buf[TRACE_MARKER_MESSAGE_LEN] = {0};
106570af302Sopenharmony_ci    int len = 0;
107570af302Sopenharmony_ci    if (value == NULL) {
108570af302Sopenharmony_ci        len = snprintf(buf, TRACE_MARKER_MESSAGE_LEN, "B|%d|%s", getpid(), message);
109570af302Sopenharmony_ci    } else {
110570af302Sopenharmony_ci        len = snprintf(buf, TRACE_MARKER_MESSAGE_LEN, "B|%d|%s %s", getpid(), message, value);
111570af302Sopenharmony_ci    }
112570af302Sopenharmony_ci    if (len > 0 && len < sizeof(buf)) {
113570af302Sopenharmony_ci        int ret = MUSL_TEMP_FAILURE_RETRY(write(trace_marker_fd, buf, len));
114570af302Sopenharmony_ci        if (ret == -1) {
115570af302Sopenharmony_ci            MUSL_LOGE("fail to write B. %d", ret);
116570af302Sopenharmony_ci        }
117570af302Sopenharmony_ci    } else {
118570af302Sopenharmony_ci        MUSL_LOGE("B length error. %d", len);
119570af302Sopenharmony_ci    }
120570af302Sopenharmony_ci
121570af302Sopenharmony_ci    // close file descriptor of trace_marker
122570af302Sopenharmony_ci    close(trace_marker_fd);
123570af302Sopenharmony_ci}
124570af302Sopenharmony_ci
125570af302Sopenharmony_ci/* Write the terminator to the trace_marker node of the kernel space,
126570af302Sopenharmony_ciused on the same thread as trace_marker_begin(),with the symbol "E". */
127570af302Sopenharmony_civoid trace_marker_end(uint64_t label)
128570af302Sopenharmony_ci{
129570af302Sopenharmony_ci    if (LIKELY(!is_enable_trace(label))) {
130570af302Sopenharmony_ci        return;
131570af302Sopenharmony_ci    }
132570af302Sopenharmony_ci
133570af302Sopenharmony_ci    int trace_marker_fd = get_trace_marker_fd();
134570af302Sopenharmony_ci    if (trace_marker_fd == -1) {
135570af302Sopenharmony_ci        return;
136570af302Sopenharmony_ci    }
137570af302Sopenharmony_ci
138570af302Sopenharmony_ci    char buf[TRACE_MARKER_MESSAGE_LEN] = {0};
139570af302Sopenharmony_ci    int len = snprintf(buf, TRACE_MARKER_MESSAGE_LEN, "E|%d", getpid());
140570af302Sopenharmony_ci    if (len > 0 && len < sizeof(buf)) {
141570af302Sopenharmony_ci        int ret = MUSL_TEMP_FAILURE_RETRY(write(trace_marker_fd, buf, len));
142570af302Sopenharmony_ci        if (ret == -1) {
143570af302Sopenharmony_ci            MUSL_LOGE("fail to write E. %d", ret);
144570af302Sopenharmony_ci        }
145570af302Sopenharmony_ci    } else {
146570af302Sopenharmony_ci        MUSL_LOGE("E length error. %d", len);
147570af302Sopenharmony_ci    }
148570af302Sopenharmony_ci
149570af302Sopenharmony_ci    // close file descriptor of trace_marker
150570af302Sopenharmony_ci    close(trace_marker_fd);
151570af302Sopenharmony_ci}
152570af302Sopenharmony_ci
153570af302Sopenharmony_ci/* Write the function call information to the trace_marker node in kernel space,
154570af302Sopenharmony_ciused in a different thread than trace_marker_async_end(),with the symbol "S". */
155570af302Sopenharmony_civoid trace_marker_async_begin(uint64_t label, const char *message, const char *value, int taskId)
156570af302Sopenharmony_ci{
157570af302Sopenharmony_ci    if (LIKELY((!is_enable_trace(label) || message == NULL))) {
158570af302Sopenharmony_ci        return;
159570af302Sopenharmony_ci    }
160570af302Sopenharmony_ci
161570af302Sopenharmony_ci    int trace_marker_fd = get_trace_marker_fd();
162570af302Sopenharmony_ci    if (trace_marker_fd == -1) {
163570af302Sopenharmony_ci        return;
164570af302Sopenharmony_ci    }
165570af302Sopenharmony_ci
166570af302Sopenharmony_ci    char buf[TRACE_MARKER_MESSAGE_LEN] = {0};
167570af302Sopenharmony_ci    int len = 0;
168570af302Sopenharmony_ci    if (value == NULL) {
169570af302Sopenharmony_ci        len = snprintf(buf, TRACE_MARKER_MESSAGE_LEN, "S|%d|%s %d", getpid(), message, taskId);
170570af302Sopenharmony_ci    } else {
171570af302Sopenharmony_ci        len = snprintf(buf, TRACE_MARKER_MESSAGE_LEN, "S|%d|%s|%s %d", getpid(), message, value, taskId);
172570af302Sopenharmony_ci    }
173570af302Sopenharmony_ci    if (len > 0 && len < sizeof(buf)) {
174570af302Sopenharmony_ci        int ret = MUSL_TEMP_FAILURE_RETRY(write(trace_marker_fd, buf, len));
175570af302Sopenharmony_ci        if (ret == -1) {
176570af302Sopenharmony_ci            MUSL_LOGE("fail to write S. %d", ret);
177570af302Sopenharmony_ci        }
178570af302Sopenharmony_ci    } else {
179570af302Sopenharmony_ci        MUSL_LOGE("S length error. %d", len);
180570af302Sopenharmony_ci    }
181570af302Sopenharmony_ci
182570af302Sopenharmony_ci    // close file descriptor of trace_marker
183570af302Sopenharmony_ci    close(trace_marker_fd);
184570af302Sopenharmony_ci}
185570af302Sopenharmony_ci
186570af302Sopenharmony_ci/* Write the terminator to the trace_marker node in kernel space,
187570af302Sopenharmony_ciused in a different thread than trace_marker_async_begin(),with the symbol "F". */
188570af302Sopenharmony_civoid trace_marker_async_end(uint64_t label, const char *message, const char *value, int taskId)
189570af302Sopenharmony_ci{
190570af302Sopenharmony_ci    if (LIKELY((!is_enable_trace(label) || message == NULL))) {
191570af302Sopenharmony_ci        return;
192570af302Sopenharmony_ci    }
193570af302Sopenharmony_ci
194570af302Sopenharmony_ci    int trace_marker_fd = get_trace_marker_fd();
195570af302Sopenharmony_ci    if (trace_marker_fd == -1) {
196570af302Sopenharmony_ci        return;
197570af302Sopenharmony_ci    }
198570af302Sopenharmony_ci
199570af302Sopenharmony_ci    char buf[TRACE_MARKER_MESSAGE_LEN] = {0};
200570af302Sopenharmony_ci    int len = 0;
201570af302Sopenharmony_ci    if (value == NULL) {
202570af302Sopenharmony_ci        len = snprintf(buf, TRACE_MARKER_MESSAGE_LEN, "F|%d|%s %d", getpid(), message, taskId);
203570af302Sopenharmony_ci    } else {
204570af302Sopenharmony_ci        len = snprintf(buf, TRACE_MARKER_MESSAGE_LEN, "F|%d|%s|%s %d", getpid(), message, value, taskId);
205570af302Sopenharmony_ci    }
206570af302Sopenharmony_ci    if (len > 0 && len < sizeof(buf)) {
207570af302Sopenharmony_ci        int ret = MUSL_TEMP_FAILURE_RETRY(write(trace_marker_fd, buf, len));
208570af302Sopenharmony_ci        if (ret == -1) {
209570af302Sopenharmony_ci            MUSL_LOGE("fail to write F. %d", ret);
210570af302Sopenharmony_ci        }
211570af302Sopenharmony_ci    } else {
212570af302Sopenharmony_ci        MUSL_LOGE("F length error. %d", len);
213570af302Sopenharmony_ci    }
214570af302Sopenharmony_ci
215570af302Sopenharmony_ci    // close file descriptor of trace_marker
216570af302Sopenharmony_ci    close(trace_marker_fd);
217570af302Sopenharmony_ci}
218570af302Sopenharmony_ci
219570af302Sopenharmony_ci// A numeric variable used to mark a pre trace, with the symbol "C".
220570af302Sopenharmony_civoid trace_marker_count(uint64_t label, const char *message, int value)
221570af302Sopenharmony_ci{
222570af302Sopenharmony_ci    if (LIKELY((!is_enable_trace(label) || message == NULL))) {
223570af302Sopenharmony_ci        return;
224570af302Sopenharmony_ci    }
225570af302Sopenharmony_ci
226570af302Sopenharmony_ci    int trace_marker_fd = get_trace_marker_fd();
227570af302Sopenharmony_ci    if (trace_marker_fd == -1) {
228570af302Sopenharmony_ci        return;
229570af302Sopenharmony_ci    }
230570af302Sopenharmony_ci
231570af302Sopenharmony_ci    char buf[TRACE_MARKER_MESSAGE_LEN] = {0};
232570af302Sopenharmony_ci    int len = snprintf(buf, TRACE_MARKER_MESSAGE_LEN, "C|%d|%s %d", getpid(), message, value);
233570af302Sopenharmony_ci    if (len > 0 && len < sizeof(buf)) {
234570af302Sopenharmony_ci        int ret = MUSL_TEMP_FAILURE_RETRY(write(trace_marker_fd, buf, len));
235570af302Sopenharmony_ci        if (ret == -1) {
236570af302Sopenharmony_ci            MUSL_LOGE("fail to write C. %d", ret);
237570af302Sopenharmony_ci        }
238570af302Sopenharmony_ci    } else {
239570af302Sopenharmony_ci        MUSL_LOGE("C length error. %d", len);
240570af302Sopenharmony_ci    }
241570af302Sopenharmony_ci
242570af302Sopenharmony_ci    // close file descriptor of trace_marker
243570af302Sopenharmony_ci    close(trace_marker_fd);
244570af302Sopenharmony_ci}
245570af302Sopenharmony_ci
246