1 /*
2 * Copyright (c) 2023-2025 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 #include "perf_collector_impl.h"
16
17 #include <atomic>
18 #include <ctime>
19 #include <fstream>
20
21 #include "hiperf_client.h"
22 #include "hiview_logger.h"
23 #include "memory_collector.h"
24 #include "parameter_ex.h"
25 #include "perf_collect_config.h"
26 #include "perf_decorator.h"
27
28 using namespace OHOS::HiviewDFX::UCollect;
29 using namespace OHOS::Developtools::HiPerf::HiperfClient;
30 namespace OHOS {
31 namespace HiviewDFX {
32 namespace UCollectUtil {
33 namespace {
34 DEFINE_LOG_TAG("UCollectUtil-PerfCollectorImpl");
35 constexpr int DEFAULT_PERF_RECORD_FREQUENCY = 100;
36 constexpr char DEFAULT_PERF_RECORD_CALLGRAPH[] = "fp";
37 constexpr uint32_t MB_TO_KB = 1024;
38 const int64_t ALLOW_COLLECT_MEMORY = PerfCollectConfig::GetAllowMemory(PerfCollectConfig::GetConfigPath());
39 const std::map<PerfCaller, uint8_t> PERF_CONCURRENCY_COUNT =
40 PerfCollectConfig::GetPerfCount(PerfCollectConfig::GetConfigPath());
41 }
42
43 std::atomic<uint8_t> PerfCollectorImpl::inUseCount_(0);
44
PerfCollectorImpl(PerfCaller perfCaller)45 PerfCollectorImpl::PerfCollectorImpl(PerfCaller perfCaller) : perfCaller_(perfCaller)
46 {
47 opt_.SetFrequency(DEFAULT_PERF_RECORD_FREQUENCY);
48 opt_.SetCallGraph(DEFAULT_PERF_RECORD_CALLGRAPH);
49 opt_.SetOffCPU(false);
50 }
51
SetSelectPids(const std::vector<pid_t> & selectPids)52 void PerfCollectorImpl::SetSelectPids(const std::vector<pid_t> &selectPids)
53 {
54 opt_.SetSelectPids(selectPids);
55 }
56
SetTargetSystemWide(bool enable)57 void PerfCollectorImpl::SetTargetSystemWide(bool enable)
58 {
59 opt_.SetTargetSystemWide(enable);
60 }
61
SetTimeStopSec(int timeStopSec)62 void PerfCollectorImpl::SetTimeStopSec(int timeStopSec)
63 {
64 opt_.SetTimeStopSec(timeStopSec);
65 }
66
SetFrequency(int frequency)67 void PerfCollectorImpl::SetFrequency(int frequency)
68 {
69 opt_.SetFrequency(frequency);
70 }
71
SetOffCPU(bool offCPU)72 void PerfCollectorImpl::SetOffCPU(bool offCPU)
73 {
74 opt_.SetOffCPU(offCPU);
75 }
76
SetOutputFilename(const std::string & outputFilename)77 void PerfCollectorImpl::SetOutputFilename(const std::string &outputFilename)
78 {
79 opt_.SetOutputFilename(outputFilename);
80 }
81
SetCallGraph(const std::string & sampleTypes)82 void PerfCollectorImpl::SetCallGraph(const std::string &sampleTypes)
83 {
84 opt_.SetCallGraph(sampleTypes);
85 }
86
SetSelectEvents(const std::vector<std::string> & selectEvents)87 void PerfCollectorImpl::SetSelectEvents(const std::vector<std::string> &selectEvents)
88 {
89 opt_.SetSelectEvents(selectEvents);
90 }
91
SetCpuPercent(int cpuPercent)92 void PerfCollectorImpl::SetCpuPercent(int cpuPercent)
93 {
94 opt_.SetCpuPercent(cpuPercent);
95 }
96
SetReport(bool enable)97 void PerfCollectorImpl::SetReport(bool enable)
98 {
99 opt_.SetReport(enable);
100 }
101
IncreaseUseCount()102 void PerfCollectorImpl::IncreaseUseCount()
103 {
104 inUseCount_.fetch_add(1);
105 }
106
DecreaseUseCount()107 void PerfCollectorImpl::DecreaseUseCount()
108 {
109 inUseCount_.fetch_sub(1);
110 }
111
Create(PerfCaller perfCaller)112 std::shared_ptr<PerfCollector> PerfCollector::Create(PerfCaller perfCaller)
113 {
114 return std::make_shared<PerfDecorator>(std::make_shared<PerfCollectorImpl>(perfCaller));
115 }
116
CheckUseCount()117 CollectResult<bool> PerfCollectorImpl::CheckUseCount()
118 {
119 CollectResult<bool> result;
120 if (PERF_CONCURRENCY_COUNT.find(perfCaller_) == PERF_CONCURRENCY_COUNT.end()) {
121 HIVIEW_LOGI("not find perf caller");
122 result.data = false;
123 result.retCode = UcError::PERF_CALLER_NOT_FIND;
124 return result;
125 }
126 HIVIEW_LOGI("current used count : %{public}d", inUseCount_.load());
127 IncreaseUseCount();
128 if (inUseCount_.load() > PERF_CONCURRENCY_COUNT.at(perfCaller_)) {
129 HIVIEW_LOGI("current used count over limit.");
130 result.data = false;
131 result.retCode = UcError::USAGE_EXCEED_LIMIT;
132 DecreaseUseCount();
133 return result;
134 }
135 result.data = true;
136 result.retCode = UcError::SUCCESS;
137 return result;
138 }
139
CheckAvailableMemory()140 CollectResult<bool> PerfCollectorImpl::CheckAvailableMemory()
141 {
142 auto collector = UCollectUtil::MemoryCollector::Create();
143 CollectResult<SysMemory> data = collector->CollectSysMemory();
144 CollectResult<bool> result;
145 // -1 : means not limit by memory
146 if (ALLOW_COLLECT_MEMORY != -1 && (data.data.memAvailable / MB_TO_KB) < ALLOW_COLLECT_MEMORY) {
147 result.data = false;
148 result.retCode = UcError::PERF_MEMORY_NOT_ALLOW;
149 return result;
150 }
151 result.data = true;
152 result.retCode = UcError::SUCCESS;
153 return result;
154 }
155
StartPerf(const std::string & logDir)156 CollectResult<bool> PerfCollectorImpl::StartPerf(const std::string &logDir)
157 {
158 CollectResult<bool> result = CheckAvailableMemory();
159 if (result.retCode != UCollect::UcError::SUCCESS) {
160 return result;
161 }
162
163 result = CheckUseCount();
164 if (result.retCode != UCollect::UcError::SUCCESS) {
165 return result;
166 }
167
168 HIVIEW_LOGI("start collecting data");
169 hiperfClient_.Setup(logDir);
170 bool ret = hiperfClient_.Start(opt_);
171 result.data = ret;
172 result.retCode = ret ? UcError::SUCCESS : UcError::PERF_COLLECT_FAILED;
173 HIVIEW_LOGI("finished recording with result : %{public}d", ret);
174 DecreaseUseCount();
175 return result;
176 }
177
Prepare(const std::string & logDir)178 CollectResult<bool> PerfCollectorImpl::Prepare(const std::string &logDir)
179 {
180 CollectResult<bool> result = CheckUseCount();
181 if (result.retCode != UCollect::UcError::SUCCESS) {
182 return result;
183 }
184
185 HIVIEW_LOGI("prepare collecting data");
186 hiperfClient_.Setup(logDir);
187 bool ret = hiperfClient_.PrePare(opt_);
188 result.data = ret;
189 result.retCode = ret ? UcError::SUCCESS : UcError::PERF_COLLECT_FAILED;
190 HIVIEW_LOGI("Prepare result : %{public}d", ret);
191 return result;
192 }
193
StartRun()194 CollectResult<bool> PerfCollectorImpl::StartRun()
195 {
196 HIVIEW_LOGI("bgein");
197 CollectResult<bool> result;
198 bool ret = hiperfClient_.StartRun();
199 result.data = ret;
200 result.retCode = ret ? UcError::SUCCESS : UcError::PERF_COLLECT_FAILED;
201 HIVIEW_LOGI("result : %{public}d", ret);
202 return result;
203 }
204
Pause()205 CollectResult<bool> PerfCollectorImpl::Pause()
206 {
207 HIVIEW_LOGI("begin");
208 CollectResult<bool> result;
209 bool ret = hiperfClient_.Pause();
210 result.data = ret;
211 result.retCode = ret ? UcError::SUCCESS : UcError::PERF_COLLECT_FAILED;
212 HIVIEW_LOGI("result : %{public}d", ret);
213 return result;
214 }
215
Resume()216 CollectResult<bool> PerfCollectorImpl::Resume()
217 {
218 HIVIEW_LOGI("begin");
219 CollectResult<bool> result;
220 bool ret = hiperfClient_.Pause();
221 result.data = ret;
222 result.retCode = ret ? UcError::SUCCESS : UcError::PERF_COLLECT_FAILED;
223 HIVIEW_LOGI("result : %{public}d", ret);
224 return result;
225 }
226
Stop()227 CollectResult<bool> PerfCollectorImpl::Stop()
228 {
229 HIVIEW_LOGI("begin");
230 CollectResult<bool> result;
231 bool ret = hiperfClient_.Stop();
232 result.data = ret;
233 result.retCode = ret ? UcError::SUCCESS : UcError::PERF_COLLECT_FAILED;
234 HIVIEW_LOGI("result : %{public}d", ret);
235 DecreaseUseCount();
236 hiperfClient_.KillChild();
237 return result;
238 }
239 } // UCollectUtil
240 } // HivewDFX
241 } // OHOS
242