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