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