perfprofdcore.cc 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732
  1. /*
  2. **
  3. ** Copyright 2015, The Android Open Source Project
  4. **
  5. ** Licensed under the Apache License, Version 2.0 (the "License");
  6. ** you may not use this file except in compliance with the License.
  7. ** You may obtain a copy of the License at
  8. **
  9. ** http://www.apache.org/licenses/LICENSE-2.0
  10. **
  11. ** Unless required by applicable law or agreed to in writing, software
  12. ** distributed under the License is distributed on an "AS IS" BASIS,
  13. ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. ** See the License for the specific language governing permissions and
  15. ** limitations under the License.
  16. */
  17. #include <assert.h>
  18. #include <dirent.h>
  19. #include <errno.h>
  20. #include <fcntl.h>
  21. #include <signal.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <sys/stat.h>
  26. #include <sys/types.h>
  27. #include <sys/wait.h>
  28. #include <time.h>
  29. #include <unistd.h>
  30. #include <memory>
  31. #include <sstream>
  32. #include <string>
  33. #include <android-base/file.h>
  34. #include <android-base/logging.h>
  35. #include <android-base/macros.h>
  36. #include <android-base/scopeguard.h>
  37. #include <android-base/stringprintf.h>
  38. #ifdef __BIONIC__
  39. #include <android-base/properties.h>
  40. #endif
  41. #ifdef __ANDROID__
  42. #include <healthhalutils/HealthHalUtils.h>
  43. #endif
  44. #include "perfprofd_record.pb.h"
  45. #include "config.h"
  46. #include "cpuconfig.h"
  47. #include "perf_data_converter.h"
  48. #include "perfprofdcore.h"
  49. #include "perfprofd_io.h"
  50. #include "perfprofd_perf.h"
  51. #include "symbolizer.h"
  52. //
  53. // Perf profiling daemon -- collects system-wide profiles using
  54. //
  55. // simpleperf record -a
  56. //
  57. // and encodes them so that they can be uploaded by a separate service.
  58. //
  59. //......................................................................
  60. using ProtoUniquePtr = std::unique_ptr<android::perfprofd::PerfprofdRecord>;
  61. //
  62. // Output file from 'perf record'.
  63. //
  64. #define PERF_OUTPUT "perf.data"
  65. //
  66. // This enum holds the results of the "should we profile" configuration check.
  67. //
  68. typedef enum {
  69. // All systems go for profile collection.
  70. DO_COLLECT_PROFILE,
  71. // The selected configuration directory doesn't exist.
  72. DONT_PROFILE_MISSING_CONFIG_DIR,
  73. // Destination directory does not contain the semaphore file that
  74. // the perf profile uploading service creates when it determines
  75. // that the user has opted "in" for usage data collection. No
  76. // semaphore -> no user approval -> no profiling.
  77. DONT_PROFILE_MISSING_SEMAPHORE,
  78. // No perf executable present
  79. DONT_PROFILE_MISSING_PERF_EXECUTABLE,
  80. // We're running in the emulator, perf won't be able to do much
  81. DONT_PROFILE_RUNNING_IN_EMULATOR
  82. } CKPROFILE_RESULT;
  83. static bool common_initialized = false;
  84. //
  85. // Are we running in the emulator? If so, stub out profile collection
  86. // Starts as uninitialized (-1), then set to 1 or 0 at init time.
  87. //
  88. static int running_in_emulator = -1;
  89. //
  90. // Is this a debug build ('userdebug' or 'eng')?
  91. //
  92. static bool is_debug_build = false;
  93. //
  94. // Random number generator seed (set at startup time).
  95. //
  96. static unsigned short random_seed[3];
  97. //
  98. // Convert a CKPROFILE_RESULT to a string
  99. //
  100. static const char *ckprofile_result_to_string(CKPROFILE_RESULT result)
  101. {
  102. switch (result) {
  103. case DO_COLLECT_PROFILE:
  104. return "DO_COLLECT_PROFILE";
  105. case DONT_PROFILE_MISSING_CONFIG_DIR:
  106. return "missing config directory";
  107. case DONT_PROFILE_MISSING_SEMAPHORE:
  108. return "missing semaphore file";
  109. case DONT_PROFILE_MISSING_PERF_EXECUTABLE:
  110. return "missing 'perf' executable";
  111. case DONT_PROFILE_RUNNING_IN_EMULATOR:
  112. return "running in emulator";
  113. default:
  114. return "unknown";
  115. }
  116. }
  117. //
  118. // Check to see whether we should perform a profile collection
  119. //
  120. static CKPROFILE_RESULT check_profiling_enabled(const Config& config)
  121. {
  122. //
  123. // Profile collection in the emulator doesn't make sense
  124. //
  125. assert(running_in_emulator != -1);
  126. if (running_in_emulator) {
  127. return DONT_PROFILE_RUNNING_IN_EMULATOR;
  128. }
  129. if (!config.IsProfilingEnabled()) {
  130. return DONT_PROFILE_MISSING_CONFIG_DIR;
  131. }
  132. // Check for existence of simpleperf/perf executable
  133. std::string pp = config.perf_path;
  134. if (access(pp.c_str(), R_OK|X_OK) == -1) {
  135. LOG(WARNING) << "unable to access/execute " << pp;
  136. return DONT_PROFILE_MISSING_PERF_EXECUTABLE;
  137. }
  138. //
  139. // We are good to go
  140. //
  141. return DO_COLLECT_PROFILE;
  142. }
  143. bool get_booting()
  144. {
  145. #ifdef __BIONIC__
  146. return android::base::GetBoolProperty("sys.boot_completed", false) != true;
  147. #else
  148. return false;
  149. #endif
  150. }
  151. //
  152. // Constructor takes a timeout (in seconds) and a child pid; If an
  153. // alarm set for the specified number of seconds triggers, then a
  154. // SIGKILL is sent to the child. Destructor resets alarm. Example:
  155. //
  156. // pid_t child_pid = ...;
  157. // { AlarmHelper h(10, child_pid);
  158. // ... = read_from_child(child_pid, ...);
  159. // }
  160. //
  161. // NB: this helper is not re-entrant-- avoid nested use or
  162. // use by multiple threads
  163. //
  164. class AlarmHelper {
  165. public:
  166. AlarmHelper(unsigned num_seconds, pid_t child)
  167. {
  168. struct sigaction sigact;
  169. assert(child);
  170. assert(child_ == 0);
  171. memset(&sigact, 0, sizeof(sigact));
  172. sigact.sa_sigaction = handler;
  173. sigaction(SIGALRM, &sigact, &oldsigact_);
  174. child_ = child;
  175. alarm(num_seconds);
  176. }
  177. ~AlarmHelper()
  178. {
  179. alarm(0);
  180. child_ = 0;
  181. sigaction(SIGALRM, &oldsigact_, NULL);
  182. }
  183. static void handler(int, siginfo_t *, void *);
  184. private:
  185. struct sigaction oldsigact_;
  186. static pid_t child_;
  187. };
  188. pid_t AlarmHelper::child_;
  189. void AlarmHelper::handler(int, siginfo_t *, void *)
  190. {
  191. LOG(WARNING) << "SIGALRM timeout";
  192. kill(child_, SIGKILL);
  193. }
  194. //
  195. // This implementation invokes "dumpsys media.camera" and inspects the
  196. // output to determine if any camera clients are active. NB: this is
  197. // currently disable (via config option) until the selinux issues can
  198. // be sorted out. Another possible implementation (not yet attempted)
  199. // would be to use the binder to call into the native camera service
  200. // via "ICameraService".
  201. //
  202. bool get_camera_active()
  203. {
  204. int pipefds[2];
  205. if (pipe2(pipefds, O_CLOEXEC) != 0) {
  206. PLOG(ERROR) << "pipe2() failed";
  207. return false;
  208. }
  209. pid_t pid = fork();
  210. if (pid == -1) {
  211. PLOG(ERROR) << "fork() failed";
  212. close(pipefds[0]);
  213. close(pipefds[1]);
  214. return false;
  215. } else if (pid == 0) {
  216. // child
  217. close(pipefds[0]);
  218. dup2(pipefds[1], fileno(stderr));
  219. dup2(pipefds[1], fileno(stdout));
  220. const char *argv[10];
  221. unsigned slot = 0;
  222. argv[slot++] = "/system/bin/dumpsys";
  223. argv[slot++] = "media.camera";
  224. argv[slot++] = nullptr;
  225. execvp(argv[0], (char * const *)argv);
  226. PLOG(ERROR) << "execvp() failed";
  227. return false;
  228. }
  229. // parent
  230. AlarmHelper helper(10, pid);
  231. close(pipefds[1]);
  232. // read output
  233. bool have_cam = false;
  234. bool have_clients = true;
  235. std::string dump_output;
  236. bool result = android::base::ReadFdToString(pipefds[0], &dump_output);
  237. close(pipefds[0]);
  238. if (result) {
  239. std::stringstream ss(dump_output);
  240. std::string line;
  241. while (std::getline(ss,line,'\n')) {
  242. if (line.find("Camera module API version:") !=
  243. std::string::npos) {
  244. have_cam = true;
  245. }
  246. if (line.find("No camera module available") !=
  247. std::string::npos ||
  248. line.find("No active camera clients yet") !=
  249. std::string::npos) {
  250. have_clients = false;
  251. }
  252. }
  253. }
  254. // reap child (no zombies please)
  255. int st = 0;
  256. TEMP_FAILURE_RETRY(waitpid(pid, &st, 0));
  257. return have_cam && have_clients;
  258. }
  259. bool get_charging()
  260. {
  261. #ifdef __ANDROID__
  262. using android::sp;
  263. using android::hardware::Return;
  264. using android::hardware::health::V2_0::get_health_service;
  265. using android::hardware::health::V2_0::HealthInfo;
  266. using android::hardware::health::V2_0::IHealth;
  267. using android::hardware::health::V2_0::Result;
  268. sp<IHealth> service = get_health_service();
  269. if (service == nullptr) {
  270. LOG(ERROR) << "Failed to get health HAL";
  271. return false;
  272. }
  273. Result res = Result::UNKNOWN;
  274. HealthInfo val;
  275. Return<void> ret =
  276. service->getHealthInfo([&](Result out_res, HealthInfo out_val) {
  277. res = out_res;
  278. val = out_val;
  279. });
  280. if (!ret.isOk()) {
  281. LOG(ERROR) << "Failed to call getChargeStatus on health HAL: " << ret.description();
  282. return false;
  283. }
  284. if (res != Result::SUCCESS) {
  285. LOG(ERROR) << "Failed to retrieve charge status from health HAL: result = "
  286. << toString(res);
  287. return false;
  288. }
  289. return val.legacy.chargerAcOnline || val.legacy.chargerUsbOnline ||
  290. val.legacy.chargerWirelessOnline;
  291. #else
  292. return false;
  293. #endif
  294. }
  295. static bool postprocess_proc_stat_contents(const std::string &pscontents,
  296. long unsigned *idleticks,
  297. long unsigned *remainingticks)
  298. {
  299. long unsigned usertime, nicetime, systime, idletime, iowaittime;
  300. long unsigned irqtime, softirqtime;
  301. int rc = sscanf(pscontents.c_str(), "cpu %lu %lu %lu %lu %lu %lu %lu",
  302. &usertime, &nicetime, &systime, &idletime,
  303. &iowaittime, &irqtime, &softirqtime);
  304. if (rc != 7) {
  305. return false;
  306. }
  307. *idleticks = idletime;
  308. *remainingticks = usertime + nicetime + systime + iowaittime + irqtime + softirqtime;
  309. return true;
  310. }
  311. unsigned collect_cpu_utilization()
  312. {
  313. std::string contents;
  314. long unsigned idle[2];
  315. long unsigned busy[2];
  316. for (unsigned iter = 0; iter < 2; ++iter) {
  317. if (!android::base::ReadFileToString("/proc/stat", &contents)) {
  318. return 0;
  319. }
  320. if (!postprocess_proc_stat_contents(contents, &idle[iter], &busy[iter])) {
  321. return 0;
  322. }
  323. if (iter == 0) {
  324. sleep(1);
  325. }
  326. }
  327. long unsigned total_delta = (idle[1] + busy[1]) - (idle[0] + busy[0]);
  328. long unsigned busy_delta = busy[1] - busy[0];
  329. return busy_delta * 100 / total_delta;
  330. }
  331. static void annotate_encoded_perf_profile(android::perfprofd::PerfprofdRecord* profile,
  332. const Config& config,
  333. unsigned cpu_utilization)
  334. {
  335. //
  336. // Incorporate cpu utilization (collected prior to perf run)
  337. //
  338. if (config.collect_cpu_utilization) {
  339. profile->SetExtension(quipper::cpu_utilization, cpu_utilization);
  340. }
  341. //
  342. // Load average as reported by the kernel
  343. //
  344. std::string load;
  345. double fload = 0.0;
  346. if (android::base::ReadFileToString("/proc/loadavg", &load) &&
  347. sscanf(load.c_str(), "%lf", &fload) == 1) {
  348. int iload = static_cast<int>(fload * 100.0);
  349. profile->SetExtension(quipper::sys_load_average, iload);
  350. } else {
  351. PLOG(ERROR) << "Failed to read or scan /proc/loadavg";
  352. }
  353. //
  354. // Device still booting? Camera in use? Plugged into charger?
  355. //
  356. bool is_booting = get_booting();
  357. if (config.collect_booting) {
  358. profile->SetExtension(quipper::booting, is_booting);
  359. }
  360. if (config.collect_camera_active) {
  361. profile->SetExtension(quipper::camera_active, is_booting ? false : get_camera_active());
  362. }
  363. if (config.collect_charging_state) {
  364. profile->SetExtension(quipper::on_charger, get_charging());
  365. }
  366. //
  367. // Examine the contents of wake_unlock to determine whether the
  368. // device display is on or off. NB: is this really the only way to
  369. // determine this info?
  370. //
  371. std::string disp;
  372. if (android::base::ReadFileToString("/sys/power/wake_unlock", &disp)) {
  373. bool ison = (strstr(disp.c_str(), "PowerManagerService.Display") == 0);
  374. profile->SetExtension(quipper::display_on, ison);
  375. } else {
  376. PLOG(ERROR) << "Failed to read /sys/power/wake_unlock";
  377. }
  378. }
  379. static ProtoUniquePtr encode_to_proto(const std::string &data_file_path,
  380. const Config& config,
  381. unsigned cpu_utilization,
  382. perfprofd::Symbolizer* symbolizer) {
  383. //
  384. // Open and read perf.data file
  385. //
  386. ProtoUniquePtr encodedProfile(
  387. android::perfprofd::RawPerfDataToAndroidPerfProfile(data_file_path,
  388. symbolizer,
  389. config.symbolize_everything));
  390. if (encodedProfile == nullptr) {
  391. return nullptr;
  392. }
  393. // All of the info in 'encodedProfile' is derived from the perf.data file;
  394. // here we tack display status, cpu utilization, system load, etc.
  395. annotate_encoded_perf_profile(encodedProfile.get(), config, cpu_utilization);
  396. return encodedProfile;
  397. }
  398. PROFILE_RESULT encode_to_proto(const std::string &data_file_path,
  399. const char *encoded_file_path,
  400. const Config& config,
  401. unsigned cpu_utilization,
  402. perfprofd::Symbolizer* symbolizer)
  403. {
  404. ProtoUniquePtr encodedProfile = encode_to_proto(data_file_path,
  405. config,
  406. cpu_utilization,
  407. symbolizer);
  408. //
  409. // Issue error if no samples
  410. //
  411. if (encodedProfile == nullptr || encodedProfile->events_size() == 0) {
  412. return ERR_PERF_ENCODE_FAILED;
  413. }
  414. return android::perfprofd::SerializeProtobuf(encodedProfile.get(),
  415. encoded_file_path,
  416. config.compress)
  417. ? OK_PROFILE_COLLECTION
  418. : ERR_WRITE_ENCODED_FILE_FAILED;
  419. }
  420. //
  421. // Remove all files in the destination directory during initialization
  422. //
  423. static void cleanup_destination_dir(const std::string& dest_dir)
  424. {
  425. DIR* dir = opendir(dest_dir.c_str());
  426. if (dir != NULL) {
  427. struct dirent* e;
  428. while ((e = readdir(dir)) != 0) {
  429. if (e->d_name[0] != '.') {
  430. std::string file_path = dest_dir + "/" + e->d_name;
  431. remove(file_path.c_str());
  432. }
  433. }
  434. closedir(dir);
  435. } else {
  436. PLOG(WARNING) << "unable to open destination dir " << dest_dir << " for cleanup";
  437. }
  438. }
  439. //
  440. // Collect a perf profile. Steps for this operation are:
  441. // - kick off 'perf record'
  442. // - read perf.data, convert to protocol buf
  443. //
  444. static ProtoUniquePtr collect_profile(Config& config)
  445. {
  446. //
  447. // Collect cpu utilization if enabled
  448. //
  449. unsigned cpu_utilization = 0;
  450. if (config.collect_cpu_utilization) {
  451. cpu_utilization = collect_cpu_utilization();
  452. }
  453. //
  454. // Form perf.data file name, perf error output file name
  455. //
  456. const std::string& destdir = config.destination_directory;
  457. std::string data_file_path(destdir);
  458. data_file_path += "/";
  459. data_file_path += PERF_OUTPUT;
  460. std::string perf_stderr_path(destdir);
  461. perf_stderr_path += "/perferr.txt";
  462. //
  463. // Remove any existing perf.data file -- if we don't do this, perf
  464. // will rename the old file and we'll have extra cruft lying around.
  465. //
  466. struct stat statb;
  467. if (stat(data_file_path.c_str(), &statb) == 0) { // if file exists...
  468. if (unlink(data_file_path.c_str())) { // then try to remove
  469. PLOG(WARNING) << "unable to unlink previous perf.data file";
  470. }
  471. }
  472. //
  473. // The "mpdecision" daemon can cause problems for profile
  474. // collection: if it decides to online a CPU partway through the
  475. // 'perf record' run, the activity on that CPU will be invisible to
  476. // perf, and if it offlines a CPU during the recording this can
  477. // sometimes leave the PMU in an unusable state (dmesg errors of the
  478. // form "perfevents: unable to request IRQXXX for ..."). To avoid
  479. // these issues, if "mpdecision" is running the helper below will
  480. // stop the service and then online all available CPUs. The object
  481. // destructor (invoked when this routine terminates) will then
  482. // restart the service again when needed.
  483. //
  484. uint32_t duration = config.sample_duration_in_s;
  485. bool hardwire = config.hardwire_cpus;
  486. uint32_t max_duration = config.hardwire_cpus_max_duration_in_s;
  487. bool take_action = (hardwire && duration <= max_duration);
  488. HardwireCpuHelper helper(take_action);
  489. auto scope_guard = android::base::make_scope_guard(
  490. [&data_file_path]() { unlink(data_file_path.c_str()); });
  491. //
  492. // Invoke perf
  493. //
  494. const char *stack_profile_opt =
  495. (config.stack_profile ? "-g" : nullptr);
  496. const std::string& perf_path = config.perf_path;
  497. android::perfprofd::PerfResult invoke_res =
  498. android::perfprofd::InvokePerf(config,
  499. perf_path,
  500. stack_profile_opt,
  501. duration,
  502. data_file_path,
  503. perf_stderr_path);
  504. if (invoke_res != android::perfprofd::PerfResult::kOK) {
  505. return nullptr;
  506. }
  507. //
  508. // Read the resulting perf.data file, encode into protocol buffer, then write
  509. // the result to the file perf.data.encoded
  510. //
  511. std::unique_ptr<perfprofd::Symbolizer> symbolizer;
  512. if (config.use_elf_symbolizer) {
  513. symbolizer = perfprofd::CreateELFSymbolizer();
  514. }
  515. return encode_to_proto(data_file_path, config, cpu_utilization, symbolizer.get());
  516. }
  517. //
  518. // Assuming that we want to collect a profile every N seconds,
  519. // randomly partition N into two sub-intervals.
  520. //
  521. static void determine_before_after(unsigned &sleep_before_collect,
  522. unsigned &sleep_after_collect,
  523. unsigned collection_interval)
  524. {
  525. double frac = erand48(random_seed);
  526. sleep_before_collect = (unsigned) (((double)collection_interval) * frac);
  527. assert(sleep_before_collect <= collection_interval);
  528. sleep_after_collect = collection_interval - sleep_before_collect;
  529. }
  530. //
  531. // Set random number generator seed
  532. //
  533. static void set_seed(uint32_t use_fixed_seed)
  534. {
  535. unsigned seed = 0;
  536. if (use_fixed_seed) {
  537. //
  538. // Use fixed user-specified seed
  539. //
  540. seed = use_fixed_seed;
  541. } else {
  542. //
  543. // Randomized seed
  544. //
  545. #ifdef __BIONIC__
  546. seed = arc4random();
  547. #else
  548. seed = 12345678u;
  549. #endif
  550. }
  551. LOG(INFO) << "random seed set to " << seed;
  552. // Distribute the 32-bit seed into the three 16-bit array
  553. // elements. The specific values being written do not especially
  554. // matter as long as we are setting them to something based on the seed.
  555. random_seed[0] = seed & 0xffff;
  556. random_seed[1] = (seed >> 16);
  557. random_seed[2] = (random_seed[0] ^ random_seed[1]);
  558. }
  559. void CommonInit(uint32_t use_fixed_seed, const char* dest_dir) {
  560. // Children of init inherit an artificially low OOM score -- this is not
  561. // desirable for perfprofd (its OOM score should be on par with
  562. // other user processes).
  563. std::stringstream oomscore_path;
  564. oomscore_path << "/proc/" << getpid() << "/oom_score_adj";
  565. if (!android::base::WriteStringToFile("0", oomscore_path.str())) {
  566. LOG(ERROR) << "unable to write to " << oomscore_path.str();
  567. }
  568. set_seed(use_fixed_seed);
  569. if (dest_dir != nullptr) {
  570. cleanup_destination_dir(dest_dir);
  571. }
  572. #ifdef __BIONIC__
  573. running_in_emulator = android::base::GetBoolProperty("ro.kernel.qemu", false);
  574. is_debug_build = android::base::GetBoolProperty("ro.debuggable", false);
  575. #else
  576. running_in_emulator = false;
  577. is_debug_build = true;
  578. #endif
  579. common_initialized = true;
  580. }
  581. void GlobalInit(const std::string& perf_path) {
  582. if (!android::perfprofd::FindSupportedPerfCounters(perf_path)) {
  583. LOG(WARNING) << "Could not read supported perf counters.";
  584. }
  585. }
  586. bool IsDebugBuild() {
  587. CHECK(common_initialized);
  588. return is_debug_build;
  589. }
  590. template <typename ConfigFn, typename UpdateFn>
  591. static void ProfilingLoopImpl(ConfigFn config, UpdateFn update, HandlerFn handler) {
  592. unsigned iterations = 0;
  593. while(config()->main_loop_iterations == 0 ||
  594. iterations < config()->main_loop_iterations) {
  595. if (config()->ShouldStopProfiling()) {
  596. return;
  597. }
  598. // Figure out where in the collection interval we're going to actually
  599. // run perf
  600. unsigned sleep_before_collect = 0;
  601. unsigned sleep_after_collect = 0;
  602. determine_before_after(sleep_before_collect,
  603. sleep_after_collect,
  604. config()->collection_interval_in_s);
  605. if (sleep_before_collect > 0) {
  606. config()->Sleep(sleep_before_collect);
  607. }
  608. if (config()->ShouldStopProfiling()) {
  609. return;
  610. }
  611. // Run any necessary updates.
  612. update();
  613. // Check for profiling enabled...
  614. CKPROFILE_RESULT ckresult = check_profiling_enabled(*config());
  615. if (ckresult != DO_COLLECT_PROFILE) {
  616. LOG(INFO) << "profile collection skipped (" << ckprofile_result_to_string(ckresult) << ")";
  617. } else {
  618. // Kick off the profiling run...
  619. LOG(INFO) << "initiating profile collection";
  620. ProtoUniquePtr proto = collect_profile(*config());
  621. if (proto == nullptr) {
  622. LOG(WARNING) << "profile collection failed";
  623. }
  624. // Always report, even a null result.
  625. bool handle_result = handler(proto.get(), config());
  626. if (handle_result) {
  627. LOG(INFO) << "profile collection complete";
  628. } else if (proto != nullptr) {
  629. LOG(WARNING) << "profile handling failed";
  630. }
  631. }
  632. if (config()->ShouldStopProfiling()) {
  633. return;
  634. }
  635. if (sleep_after_collect > 0) {
  636. config()->Sleep(sleep_after_collect);
  637. }
  638. iterations += 1;
  639. }
  640. }
  641. void ProfilingLoop(Config& config, HandlerFn handler) {
  642. CommonInit(config.use_fixed_seed, nullptr);
  643. auto config_fn = [&config]() {
  644. return &config;;
  645. };
  646. auto do_nothing = []() {
  647. };
  648. ProfilingLoopImpl(config_fn, do_nothing, handler);
  649. }
  650. void ProfilingLoop(std::function<Config*()> config_fn,
  651. std::function<void()> update_fn,
  652. HandlerFn handler) {
  653. ProfilingLoopImpl(config_fn, update_fn, handler);
  654. }