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