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