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