• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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