1 /*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved.
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 "ffrt_profiler.h"
17
18 #include <charconv>
19 #include <fstream>
20 #include <unistd.h>
21 #include <sched.h>
22 #include <sys/prctl.h>
23
24 #include "logging.h"
25
26 namespace {
27 CachedHandle g_cachedHandle;
28 #define EXPECTANTLY(exp) (__builtin_expect(!!(exp), true))
29 #define UNEXPECTANTLY(exp) (__builtin_expect(!!(exp), false))
30
31 std::mutex g_mtx;
32 std::once_flag g_flag;
33 __thread int g_needReportThreadName = 1;
34 constexpr size_t ALIGNED_MASK = 7;
35 } // namespace
36
37 namespace OHOS::Developtools::Profiler {
38 FfrtProfiler* FfrtProfiler::instance_ = nullptr;
39
GetInstance()40 FfrtProfiler* FfrtProfiler::GetInstance()
41 {
42 if (instance_ == nullptr) {
43 std::unique_lock<std::mutex> lock(g_mtx);
44 if (instance_ == nullptr) {
45 instance_ = new (std::nothrow) FfrtProfiler();
46 }
47 }
48 return instance_;
49 }
50
FfrtProfiler()51 FfrtProfiler::FfrtProfiler()
52 {
53 pid_ = getprocpid();
54 processName_ = GetProcessName(pid_);
55 }
56
~FfrtProfiler()57 FfrtProfiler::~FfrtProfiler() {}
58
IsProfilerEnabled()59 bool FfrtProfiler::IsProfilerEnabled()
60 {
61 CheckFfrtProfilerParam();
62 return enable_;
63 }
64
CheckFfrtProfilerParam()65 void FfrtProfiler::CheckFfrtProfilerParam()
66 {
67 if (UNEXPECTANTLY(g_cachedHandle == nullptr)) {
68 std::unique_lock<std::mutex> lock(g_mtx);
69 if (g_cachedHandle == nullptr) {
70 g_cachedHandle = CachedParameterCreate(PARAM_KAY.c_str(), "");
71 }
72 }
73 int changed = 0;
74 const char *paramValue = CachedParameterGetChanged(g_cachedHandle, &changed);
75 std::call_once(g_flag, [&]() { changed = 1; });
76
77 if (UNEXPECTANTLY(changed == 1) && paramValue != nullptr) {
78 if (!enable_ && strlen(paramValue) > 0) {
79 std::vector<std::string> values;
80 SplitString(paramValue, ",", values);
81 for (auto& item : values) {
82 int32_t pid = static_cast<int32_t>(strtoull(item.c_str(), nullptr, 0));
83 if (((pid > 0) && (pid == pid_)) || ((pid == 0) && (item == processName_))) {
84 Enable();
85 break;
86 }
87 }
88 } else if (enable_ && strlen(paramValue) == 0) {
89 Disable();
90 }
91 }
92 }
93
Enable()94 void FfrtProfiler::Enable()
95 {
96 if (enable_) {
97 return;
98 }
99 socketClent_ = std::make_shared<FfrtProfilerSocketClient>(pid_, this, nullptr);
100 if (!socketClent_->ClientConnectState()) {
101 PROFILER_LOG_ERROR(LOG_CORE, "ffrt profiler start failed");
102 return;
103 }
104 PROFILER_LOG_DEBUG(LOG_CORE, "ffrt profiler clent start, pid: %d, processName: %s", pid_, processName_.c_str());
105 }
106
Disable()107 void FfrtProfiler::Disable()
108 {
109 if (!enable_) {
110 return;
111 }
112 PROFILER_LOG_DEBUG(LOG_CORE, "ffrt profiler clent stop, pid: %d, processName: %s", pid_, processName_.c_str());
113 socketClent_ = nullptr;
114 enable_ = false;
115 }
116
FfrtProfilerTrace(const uint8_t traceType,const std::string & lable,uint64_t cookie)117 void FfrtProfiler::FfrtProfilerTrace(const uint8_t traceType, const std::string& lable, uint64_t cookie)
118 {
119 if (EXPECTANTLY((!enable_))) {
120 return;
121 }
122 FfrtTraceEvent trace;
123 trace.type = TRACE_DATA;
124 trace.traceType = traceType;
125 trace.tid = getproctid();
126 trace.cpu = static_cast<uint8_t>(sched_getcpu());
127 trace.cookie = cookie;
128 clock_gettime(clockType_, &trace.ts);
129 GetThreadName(trace.threadName);
130
131 if (lable.empty()) {
132 FfrtProfilerSendData(reinterpret_cast<const void*>(&trace), sizeof(trace), nullptr, 0);
133 } else {
134 std::string strAligned = lable;
135 size_t paddingCount = (strAligned.size() + 1 + ALIGNED_MASK) & (~ALIGNED_MASK);
136 strAligned.append(paddingCount - strAligned.size() - 1, '\0');
137 FfrtProfilerSendData(reinterpret_cast<const void*>(&trace), sizeof(trace), strAligned.c_str(),
138 strAligned.size() + 1);
139 }
140 }
141
FfrtProfiling(const EventType type,const char * payload,size_t payloadSize)142 void FfrtProfiler::FfrtProfiling(const EventType type, const char* payload, size_t payloadSize)
143 {
144 if (EXPECTANTLY((!enable_)) || payload == nullptr || payloadSize == 0) {
145 return;
146 }
147 FfrtResultBase base;
148 base.type = static_cast<int32_t>(type);
149 base.tid = getproctid();
150 clock_gettime(clockType_, &base.ts);
151 GetThreadName(base.threadName);
152 FfrtProfilerSendData(&base, sizeof(base), payload, payloadSize);
153 }
154
FfrtProfilerSendData(const void * src,size_t size,const char * payload,size_t payloadSize)155 void FfrtProfiler::FfrtProfilerSendData(const void* src, size_t size, const char* payload, size_t payloadSize)
156 {
157 if (EXPECTANTLY((!enable_)) || src == nullptr) {
158 return;
159 }
160 std::weak_ptr<FfrtProfilerSocketClient> weakClient = socketClent_;
161 auto holder = weakClient.lock();
162 if (holder == nullptr) {
163 return;
164 }
165
166 if (!holder->SendFfrtProfilerData(src, size, payload, payloadSize)) {
167 PROFILER_LOG_ERROR(LOG_CORE, "ffrt profiler SendFfrtProfilerData failed");
168 }
169 }
170
GetThreadName(const void * src)171 void FfrtProfiler::GetThreadName(const void* src)
172 {
173 if (!g_needReportThreadName) {
174 return;
175 }
176 prctl(PR_GET_NAME, src);
177 g_needReportThreadName = 0;
178 }
179 } // namespace OHOS::Developtools::Profiler