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