1/*
2 * Copyright (c) 2021-2022 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#ifndef HIPERF_CLIENT_H_
16#define HIPERF_CLIENT_H_
17
18#include <chrono>
19#include <string>
20#include <vector>
21
22namespace OHOS {
23namespace Developtools {
24namespace HiPerf {
25namespace HiperfClient {
26const std::string TempBinPath = "/data/local/tmp/";
27const std::string ReplyOK = "OK\n";
28const std::string ReplyFAIL = "FAIL\n";
29const std::string ReplyStart = "START\n";
30const std::string ReplyStop = "STOP\n";
31const std::string ReplyPause = "PAUSE\n";
32const std::string ReplyResume = "RESUME\n";
33const std::string ReplyCheck = "CHECK\n";
34#define HIPERF_EXIT_CODE 0
35
36class RecordOption {
37public:
38    /**
39     * Set output file name, default is perf.data
40     */
41    void SetOutputFilename(const std::string &outputFilename)
42    {
43        outputFileName_ = outputFilename;
44    }
45    /**
46     * Get output file name
47     */
48    const std::string GetOutputFileName() const
49    {
50        return outputFileName_;
51    }
52
53    /**
54     * Get the default events for select.
55     */
56    const std::vector<std::string> &GetSelectEvents() const
57    {
58        return selectEvents_;
59    }
60
61    /**
62     * Collect system-wide information for measures all processes/threads
63     * default is disable.
64     */
65    void SetTargetSystemWide(bool enable);
66    /**
67     * Compress record data. default is disable.
68     */
69    void SetCompressData(bool enable);
70    /**
71     * Specify cpu ID, cpu ID shoule be 0,1,2...
72     */
73    void SetSelectCpus(const std::vector<int> &cpus);
74    /**
75     * Stop in <timeStopSec> seconds. default is 10000 seconds
76     */
77    void SetTimeStopSec(int timeStopSec);
78    /**
79     * Set event sampling frequency. default is 4000 samples every second.
80     */
81    void SetFrequency(int frequency);
82    /**
83     * Set event sampling period for tracepoint events.
84     * recording one sample when <period> events happen.
85     * default is 1
86     */
87    void SetPeriod(int period);
88    /**
89     * Customize the name of the event that needs to be sampled.
90     */
91    void SetSelectEvents(const std::vector<std::string> &selectEvents);
92    /**
93     * Customize the name of the event that needs to be grouped.
94     * the function is added on the basis of the function of the SetSelectEvents().
95     */
96    void SetSelectGroups(const std::vector<std::string> &selectGroups);
97    /**
98     * Set to don't tracing child processes. default is disable
99     */
100    void SetNoInherit(bool enable);
101    /**
102     * Set the limit process id of the collection target.
103     * Conflicts with the SetTargetSystemWide(true).
104     */
105    void SetSelectPids(const std::vector<pid_t> &selectPids);
106    /**
107     * Set default sampling parameters with specifying the select duration.
108     * default is 10 seconds.
109     */
110    void SetCallStackSamplingConfigs(int duration);
111    /**
112     * Set the limit thread id of the collection target.
113     * Conflicts with the SetTargetSystemWide(true).
114     */
115    void SetSelectTids(const std::vector<pid_t> &selectTids);
116    /**
117     * Set don’t record events issued by hiperf itself.
118     */
119    void SetExcludePerf(bool excludePerf);
120    /**
121     * Set the max percent of cpu time used for recording.
122     * percent is in range [1-100], default is 25
123     */
124    void SetCpuPercent(int cpuPercent);
125    /**
126     * Set tracing when threads are scheduled off cpu, default is disable
127     */
128    void SetOffCPU(bool offCPU);
129    /**
130     * Set call-graph (stack chain/backtrace) recording, Default is 'fp'.
131     * as the method to collect the information used to show the call graphs.
132     * the value can be:
133     *  fp: frame pointer
134     *  dwarf: DWARF's CFI - Call Frame Information
135     *      'dwarf,###' set sample stack size, size should be in 8~65528 and 8 byte aligned.
136     */
137    void SetCallGraph(const std::string &sampleTypes);
138    /**
139     * Set to unwind after recording.
140     * If '-g dwarf' used, stack will be unwind while recording by default
141     */
142    void SetDelayUnwind(bool delayUnwind);
143    /**
144     * Set to disable unwinding.
145     * If '-g dwarf' used, stack will be unwind while recording  by default
146     */
147    void SetDisableUnwind(bool disableUnwind);
148    /**
149     * Set callstack don't merged.
150     * If '-g dwarf' is used, to break the 64k stack limit, callstack is merged by default
151     */
152    void SetDisableCallstackMerge(bool disableCallstackMerge);
153    /**
154     * Set directory to look for symbol files, used for unwinding.
155     */
156    void SetSymbolDir(const std::string &symbolDir_);
157    /**
158     * Set to stop recording after <SIZE> bytes of records. Default is unlimited
159     * format like: SIZE[K|M|G]
160     */
161    void SetDataLimit(const std::string &limit);
162    /**
163     * Set a OHOS app name, collect profile info for this app, the app must be debuggable.
164     */
165    void SetAppPackage(const std::string &appPackage);
166    /**
167     * Set the clock id to use for the various time fields in the perf_event_type records.
168     */
169    void SetClockId(const std::string &clockId);
170    /**
171     * Set to take branch stack sampling, filter can be
172     *  any: any type of branch
173     *  any_call: any function call or system call
174     *  any_ret: any function return or system call return
175     *  ind_call: any indirect branch
176     *  call: direct calls, including far (to/from kernel) calls
177     *  u: only when the branch target is at the user level
178     *  k: only when the branch target is in the kernel\n"
179     */
180    void SetVecBranchSampleTypes(const std::vector<std::string> &vecBranchSampleTypes);
181    /**
182     * Set the size of the buffer used to receiving sample data from kernel,
183     * must be a power of two. If not set,  a value <=1024 will be used.
184     */
185    void SetMmapPages(int mmapPages);
186    /**
187     * Set to report with callstack after recording, default is disable
188     */
189    void SetReport(bool report);
190
191    /**
192     * Get the string vector of all options.
193     */
194    const std::vector<std::string> &GetOptionVecString() const
195    {
196        return args_;
197    }
198
199    /**
200     * Get TimeSpec attribute
201     */
202    bool IsTimeSpecified() const
203    {
204        return timeSpec_;
205    }
206private:
207    bool timeSpec_ = false;
208    std::vector<std::string> args_ = {};
209    std::vector<std::string> selectEvents_ = {"hw-cpu-cycles:u"};
210    std::string outputFileName_ = "";
211
212    void SetOption(const std::string &name, bool enable);
213    void SetOption(const std::string &name, int value);
214    void SetOption(const std::string &name, const std::vector<int> &vInt);
215    void SetOption(const std::string &name, const std::string &str);
216    void SetOption(const std::string &name, const std::vector<std::string> &vStr);
217};
218
219class Client {
220public:
221    /**
222     * Set output dir and constuct
223     */
224    explicit Client(const std::string &outputDir = TempBinPath);
225    ~Client();
226    /**
227     * Start record with default options
228     */
229    bool Start();
230    /**
231     * Start record with options of string vector
232     */
233    bool Start(const std::vector<std::string> &args, bool immediately = true);
234    /**
235     * Start record with options of RecordOption
236     */
237    bool Start(const RecordOption &option);
238    /**
239     * Start record synchronizely with specified time
240     */
241    bool RunHiperfCmdSync(const RecordOption &option);
242    /**
243     * prepare record with options of RecordOption
244     */
245    bool PrePare(const RecordOption &option);
246    /**
247     * Start recording after prepare
248     */
249    bool StartRun();
250    /**
251     * Pause recording
252     */
253    bool Pause();
254    /**
255     * Resume recording
256     */
257    bool Resume();
258    /**
259     * Stop recording
260     */
261    bool Stop();
262    /**
263     * Check the client is ready
264     */
265    bool IsReady();
266    /**
267     * Set the output dir
268     */
269    bool Setup(std::string outputDir);
270
271    /**
272     * Get the output dir
273     */
274    const std::string &GetOutputDir() const
275    {
276        return outputDir_;
277    }
278    /**
279     * Get the command path
280     */
281    const std::string &GetCommandPath() const
282    {
283        return executeCommandPath_;
284    }
285    /**
286     * Get the the fullpath of output file
287     */
288    const std::string GetOutputPerfDataPath() const
289    {
290        return outputDir_ + outputFileName_;
291    }
292
293    /**
294     * Child run execv cmd
295     */
296    void ChildRunExecv(std::vector<std::string> &cmd);
297    /**
298     * Prepare execv cmd
299     */
300    void PrepareExecCmd(std::vector<std::string> &cmd);
301    /**
302     * Parent wait for child exit
303     */
304    bool ParentWait(pid_t &wpid, pid_t pid, int &childStatus);
305    void SetDebugMode();
306    void SetDebugMuchMode();
307    void EnableHilog();
308    void KillChild();
309private:
310    static constexpr int64_t HIPERF_TIMEOUT_MILLISECOND = 4000;
311
312    bool WaitCommandReply(std::chrono::milliseconds = std::chrono::milliseconds(HIPERF_TIMEOUT_MILLISECOND));
313    bool SendCommandAndWait(const std::string &cmd);
314    void GetExecCmd(std::vector<std::string> &cmd, int pipeIn, int pipeOut,
315                    const std::vector<std::string> &args);
316
317    void GetExecCmd(std::vector<std::string> &cmd,
318                    const std::vector<std::string> &args);
319    std::string outputDir_ = "";
320    std::string outputFileName_ = "";
321    std::string executeCommandPath_ = "";
322    bool ready_ = false;
323    pid_t myPid_ = -1;
324    bool debug_ = false;
325    bool debugMuch_ = false;
326    bool hilog_ = false;
327
328    int clientToServerFd_ = -1;
329    int serverToClientFd_ = -1;
330    pid_t hperfPid_ = -1;
331    pid_t hperfPrePid_ = -1; // hiperf pid for prepare mode
332};
333} // namespace HiperfClient
334} // namespace HiPerf
335} // namespace Developtools
336} // namespace OHOS
337#endif // HIPERF_CLIENT_H_
338