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 18 #include <assert.h> 19 #include <dirent.h> 20 #include <errno.h> 21 #include <fcntl.h> 22 #include <signal.h> 23 #include <stdio.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <sys/stat.h> 27 #include <sys/types.h> 28 #include <sys/wait.h> 29 #include <time.h> 30 #include <unistd.h> 31 32 #include <memory> 33 #include <sstream> 34 #include <string> 35 36 #include <android-base/file.h> 37 #include <android-base/logging.h> 38 #include <android-base/macros.h> 39 #include <android-base/scopeguard.h> 40 #include <android-base/stringprintf.h> 41 42 #ifdef __BIONIC__ 43 #include <android-base/properties.h> 44 #endif 45 46 #include "perfprofd_record.pb.h" 47 48 #include "config.h" 49 #include "cpuconfig.h" 50 #include "perf_data_converter.h" 51 #include "perfprofdcore.h" 52 #include "perfprofd_io.h" 53 #include "symbolizer.h" 54 55 // 56 // Perf profiling daemon -- collects system-wide profiles using 57 // 58 // simpleperf record -a 59 // 60 // and encodes them so that they can be uploaded by a separate service. 61 // 62 63 //...................................................................... 64 65 using ProtoUniquePtr = std::unique_ptr<android::perfprofd::PerfprofdRecord>; 66 67 // 68 // Output file from 'perf record'. 69 // 70 #define PERF_OUTPUT "perf.data" 71 72 // 73 // This enum holds the results of the "should we profile" configuration check. 74 // 75 typedef enum { 76 77 // All systems go for profile collection. 78 DO_COLLECT_PROFILE, 79 80 // The selected configuration directory doesn't exist. 81 DONT_PROFILE_MISSING_CONFIG_DIR, 82 83 // Destination directory does not contain the semaphore file that 84 // the perf profile uploading service creates when it determines 85 // that the user has opted "in" for usage data collection. No 86 // semaphore -> no user approval -> no profiling. 87 DONT_PROFILE_MISSING_SEMAPHORE, 88 89 // No perf executable present 90 DONT_PROFILE_MISSING_PERF_EXECUTABLE, 91 92 // We're running in the emulator, perf won't be able to do much 93 DONT_PROFILE_RUNNING_IN_EMULATOR 94 95 } CKPROFILE_RESULT; 96 97 static bool common_initialized = false; 98 99 // 100 // Are we running in the emulator? If so, stub out profile collection 101 // Starts as uninitialized (-1), then set to 1 or 0 at init time. 102 // 103 static int running_in_emulator = -1; 104 105 // 106 // Is this a debug build ('userdebug' or 'eng')? 107 // 108 static bool is_debug_build = false; 109 110 // 111 // Random number generator seed (set at startup time). 112 // 113 static unsigned short random_seed[3]; 114 115 // 116 // Convert a CKPROFILE_RESULT to a string 117 // 118 static const char *ckprofile_result_to_string(CKPROFILE_RESULT result) 119 { 120 switch (result) { 121 case DO_COLLECT_PROFILE: 122 return "DO_COLLECT_PROFILE"; 123 case DONT_PROFILE_MISSING_CONFIG_DIR: 124 return "missing config directory"; 125 case DONT_PROFILE_MISSING_SEMAPHORE: 126 return "missing semaphore file"; 127 case DONT_PROFILE_MISSING_PERF_EXECUTABLE: 128 return "missing 'perf' executable"; 129 case DONT_PROFILE_RUNNING_IN_EMULATOR: 130 return "running in emulator"; 131 default: 132 return "unknown"; 133 } 134 } 135 136 // 137 // Check to see whether we should perform a profile collection 138 // 139 static CKPROFILE_RESULT check_profiling_enabled(const Config& config) 140 { 141 // 142 // Profile collection in the emulator doesn't make sense 143 // 144 assert(running_in_emulator != -1); 145 if (running_in_emulator) { 146 return DONT_PROFILE_RUNNING_IN_EMULATOR; 147 } 148 149 if (!config.IsProfilingEnabled()) { 150 return DONT_PROFILE_MISSING_CONFIG_DIR; 151 } 152 153 // Check for existence of simpleperf/perf executable 154 std::string pp = config.perf_path; 155 if (access(pp.c_str(), R_OK|X_OK) == -1) { 156 LOG(WARNING) << "unable to access/execute " << pp; 157 return DONT_PROFILE_MISSING_PERF_EXECUTABLE; 158 } 159 160 // 161 // We are good to go 162 // 163 return DO_COLLECT_PROFILE; 164 } 165 166 bool get_booting() 167 { 168 #ifdef __BIONIC__ 169 return android::base::GetBoolProperty("sys.boot_completed", false) != true; 170 #else 171 return false; 172 #endif 173 } 174 175 // 176 // Constructor takes a timeout (in seconds) and a child pid; If an 177 // alarm set for the specified number of seconds triggers, then a 178 // SIGKILL is sent to the child. Destructor resets alarm. Example: 179 // 180 // pid_t child_pid = ...; 181 // { AlarmHelper h(10, child_pid); 182 // ... = read_from_child(child_pid, ...); 183 // } 184 // 185 // NB: this helper is not re-entrant-- avoid nested use or 186 // use by multiple threads 187 // 188 class AlarmHelper { 189 public: 190 AlarmHelper(unsigned num_seconds, pid_t child) 191 { 192 struct sigaction sigact; 193 assert(child); 194 assert(child_ == 0); 195 memset(&sigact, 0, sizeof(sigact)); 196 sigact.sa_sigaction = handler; 197 sigaction(SIGALRM, &sigact, &oldsigact_); 198 child_ = child; 199 alarm(num_seconds); 200 } 201 ~AlarmHelper() 202 { 203 alarm(0); 204 child_ = 0; 205 sigaction(SIGALRM, &oldsigact_, NULL); 206 } 207 static void handler(int, siginfo_t *, void *); 208 209 private: 210 struct sigaction oldsigact_; 211 static pid_t child_; 212 }; 213 214 pid_t AlarmHelper::child_; 215 216 void AlarmHelper::handler(int, siginfo_t *, void *) 217 { 218 LOG(WARNING) << "SIGALRM timeout"; 219 kill(child_, SIGKILL); 220 } 221 222 // 223 // This implementation invokes "dumpsys media.camera" and inspects the 224 // output to determine if any camera clients are active. NB: this is 225 // currently disable (via config option) until the selinux issues can 226 // be sorted out. Another possible implementation (not yet attempted) 227 // would be to use the binder to call into the native camera service 228 // via "ICameraService". 229 // 230 bool get_camera_active() 231 { 232 int pipefds[2]; 233 if (pipe2(pipefds, O_CLOEXEC) != 0) { 234 PLOG(ERROR) << "pipe2() failed"; 235 return false; 236 } 237 pid_t pid = fork(); 238 if (pid == -1) { 239 PLOG(ERROR) << "fork() failed"; 240 close(pipefds[0]); 241 close(pipefds[1]); 242 return false; 243 } else if (pid == 0) { 244 // child 245 close(pipefds[0]); 246 dup2(pipefds[1], fileno(stderr)); 247 dup2(pipefds[1], fileno(stdout)); 248 const char *argv[10]; 249 unsigned slot = 0; 250 argv[slot++] = "/system/bin/dumpsys"; 251 argv[slot++] = "media.camera"; 252 argv[slot++] = nullptr; 253 execvp(argv[0], (char * const *)argv); 254 PLOG(ERROR) << "execvp() failed"; 255 return false; 256 } 257 // parent 258 AlarmHelper helper(10, pid); 259 close(pipefds[1]); 260 261 // read output 262 bool have_cam = false; 263 bool have_clients = true; 264 std::string dump_output; 265 bool result = android::base::ReadFdToString(pipefds[0], &dump_output); 266 close(pipefds[0]); 267 if (result) { 268 std::stringstream ss(dump_output); 269 std::string line; 270 while (std::getline(ss,line,'\n')) { 271 if (line.find("Camera module API version:") != 272 std::string::npos) { 273 have_cam = true; 274 } 275 if (line.find("No camera module available") != 276 std::string::npos || 277 line.find("No active camera clients yet") != 278 std::string::npos) { 279 have_clients = false; 280 } 281 } 282 } 283 284 // reap child (no zombies please) 285 int st = 0; 286 TEMP_FAILURE_RETRY(waitpid(pid, &st, 0)); 287 return have_cam && have_clients; 288 } 289 290 bool get_charging() 291 { 292 std::string psdir("/sys/class/power_supply"); 293 DIR* dir = opendir(psdir.c_str()); 294 if (dir == NULL) { 295 PLOG(ERROR) << "Failed to open dir " << psdir; 296 return false; 297 } 298 struct dirent* e; 299 bool result = false; 300 while ((e = readdir(dir)) != 0) { 301 if (e->d_name[0] != '.') { 302 std::string online_path = psdir + "/" + e->d_name + "/online"; 303 std::string contents; 304 int value = 0; 305 if (android::base::ReadFileToString(online_path.c_str(), &contents) && 306 sscanf(contents.c_str(), "%d", &value) == 1) { 307 if (value) { 308 result = true; 309 break; 310 } 311 } 312 } 313 } 314 closedir(dir); 315 return result; 316 } 317 318 static bool postprocess_proc_stat_contents(const std::string &pscontents, 319 long unsigned *idleticks, 320 long unsigned *remainingticks) 321 { 322 long unsigned usertime, nicetime, systime, idletime, iowaittime; 323 long unsigned irqtime, softirqtime; 324 325 int rc = sscanf(pscontents.c_str(), "cpu %lu %lu %lu %lu %lu %lu %lu", 326 &usertime, &nicetime, &systime, &idletime, 327 &iowaittime, &irqtime, &softirqtime); 328 if (rc != 7) { 329 return false; 330 } 331 *idleticks = idletime; 332 *remainingticks = usertime + nicetime + systime + iowaittime + irqtime + softirqtime; 333 return true; 334 } 335 336 unsigned collect_cpu_utilization() 337 { 338 std::string contents; 339 long unsigned idle[2]; 340 long unsigned busy[2]; 341 for (unsigned iter = 0; iter < 2; ++iter) { 342 if (!android::base::ReadFileToString("/proc/stat", &contents)) { 343 return 0; 344 } 345 if (!postprocess_proc_stat_contents(contents, &idle[iter], &busy[iter])) { 346 return 0; 347 } 348 if (iter == 0) { 349 sleep(1); 350 } 351 } 352 long unsigned total_delta = (idle[1] + busy[1]) - (idle[0] + busy[0]); 353 long unsigned busy_delta = busy[1] - busy[0]; 354 return busy_delta * 100 / total_delta; 355 } 356 357 static void annotate_encoded_perf_profile(android::perfprofd::PerfprofdRecord* profile, 358 const Config& config, 359 unsigned cpu_utilization) 360 { 361 // 362 // Incorporate cpu utilization (collected prior to perf run) 363 // 364 if (config.collect_cpu_utilization) { 365 profile->set_cpu_utilization(cpu_utilization); 366 } 367 368 // 369 // Load average as reported by the kernel 370 // 371 std::string load; 372 double fload = 0.0; 373 if (android::base::ReadFileToString("/proc/loadavg", &load) && 374 sscanf(load.c_str(), "%lf", &fload) == 1) { 375 int iload = static_cast<int>(fload * 100.0); 376 profile->set_sys_load_average(iload); 377 } else { 378 PLOG(ERROR) << "Failed to read or scan /proc/loadavg"; 379 } 380 381 // 382 // Device still booting? Camera in use? Plugged into charger? 383 // 384 bool is_booting = get_booting(); 385 if (config.collect_booting) { 386 profile->set_booting(is_booting); 387 } 388 if (config.collect_camera_active) { 389 profile->set_camera_active(is_booting ? false : get_camera_active()); 390 } 391 if (config.collect_charging_state) { 392 profile->set_on_charger(get_charging()); 393 } 394 395 // 396 // Examine the contents of wake_unlock to determine whether the 397 // device display is on or off. NB: is this really the only way to 398 // determine this info? 399 // 400 std::string disp; 401 if (android::base::ReadFileToString("/sys/power/wake_unlock", &disp)) { 402 bool ison = (strstr(disp.c_str(), "PowerManagerService.Display") == 0); 403 profile->set_display_on(ison); 404 } else { 405 PLOG(ERROR) << "Failed to read /sys/power/wake_unlock"; 406 } 407 } 408 409 static ProtoUniquePtr encode_to_proto(const std::string &data_file_path, 410 const Config& config, 411 unsigned cpu_utilization, 412 perfprofd::Symbolizer* symbolizer) { 413 // 414 // Open and read perf.data file 415 // 416 ProtoUniquePtr encodedProfile( 417 android::perfprofd::RawPerfDataToAndroidPerfProfile(data_file_path, symbolizer)); 418 if (encodedProfile == nullptr) { 419 return nullptr; 420 } 421 422 // All of the info in 'encodedProfile' is derived from the perf.data file; 423 // here we tack display status, cpu utilization, system load, etc. 424 annotate_encoded_perf_profile(encodedProfile.get(), config, cpu_utilization); 425 426 return encodedProfile; 427 } 428 429 PROFILE_RESULT encode_to_proto(const std::string &data_file_path, 430 const char *encoded_file_path, 431 const Config& config, 432 unsigned cpu_utilization, 433 perfprofd::Symbolizer* symbolizer) 434 { 435 ProtoUniquePtr encodedProfile = encode_to_proto(data_file_path, 436 config, 437 cpu_utilization, 438 symbolizer); 439 440 // 441 // Issue error if no samples 442 // 443 if (encodedProfile == nullptr || encodedProfile->perf_data().events_size() == 0) { 444 return ERR_PERF_ENCODE_FAILED; 445 } 446 447 return android::perfprofd::SerializeProtobuf(encodedProfile.get(), 448 encoded_file_path, 449 config.compress) 450 ? OK_PROFILE_COLLECTION 451 : ERR_WRITE_ENCODED_FILE_FAILED; 452 } 453 454 // 455 // Invoke "perf record". Return value is OK_PROFILE_COLLECTION for 456 // success, or some other error code if something went wrong. 457 // 458 static PROFILE_RESULT invoke_perf(Config& config, 459 const std::string &perf_path, 460 const char *stack_profile_opt, 461 unsigned duration, 462 const std::string &data_file_path, 463 const std::string &perf_stderr_path) 464 { 465 pid_t pid = fork(); 466 467 if (pid == -1) { 468 return ERR_FORK_FAILED; 469 } 470 471 if (pid == 0) { 472 // child 473 474 // Open file to receive stderr/stdout from perf 475 FILE *efp = fopen(perf_stderr_path.c_str(), "w"); 476 if (efp) { 477 dup2(fileno(efp), STDERR_FILENO); 478 dup2(fileno(efp), STDOUT_FILENO); 479 } else { 480 PLOG(WARNING) << "unable to open " << perf_stderr_path << " for writing"; 481 } 482 483 // marshall arguments 484 constexpr unsigned max_args = 17; 485 const char *argv[max_args]; 486 unsigned slot = 0; 487 argv[slot++] = perf_path.c_str(); 488 argv[slot++] = "record"; 489 490 // -o perf.data 491 argv[slot++] = "-o"; 492 argv[slot++] = data_file_path.c_str(); 493 494 // -c/f N 495 std::string p_str; 496 if (config.sampling_frequency > 0) { 497 argv[slot++] = "-f"; 498 p_str = android::base::StringPrintf("%u", config.sampling_frequency); 499 argv[slot++] = p_str.c_str(); 500 } else if (config.sampling_period > 0) { 501 argv[slot++] = "-c"; 502 p_str = android::base::StringPrintf("%u", config.sampling_period); 503 argv[slot++] = p_str.c_str(); 504 } 505 506 // -g if desired 507 if (stack_profile_opt) { 508 argv[slot++] = stack_profile_opt; 509 argv[slot++] = "-m"; 510 argv[slot++] = "8192"; 511 } 512 513 std::string pid_str; 514 if (config.process < 0) { 515 // system wide profiling 516 argv[slot++] = "-a"; 517 } else { 518 argv[slot++] = "-p"; 519 pid_str = std::to_string(config.process); 520 argv[slot++] = pid_str.c_str(); 521 } 522 523 // no need for kernel or other symbols 524 argv[slot++] = "--no-dump-kernel-symbols"; 525 argv[slot++] = "--no-dump-symbols"; 526 527 // sleep <duration> 528 argv[slot++] = "--duration"; 529 std::string d_str = android::base::StringPrintf("%u", duration); 530 argv[slot++] = d_str.c_str(); 531 532 // terminator 533 argv[slot++] = nullptr; 534 assert(slot < max_args); 535 536 // record the final command line in the error output file for 537 // posterity/debugging purposes 538 fprintf(stderr, "perf invocation (pid=%d):\n", getpid()); 539 for (unsigned i = 0; argv[i] != nullptr; ++i) { 540 fprintf(stderr, "%s%s", i ? " " : "", argv[i]); 541 } 542 fprintf(stderr, "\n"); 543 544 // exec 545 execvp(argv[0], (char * const *)argv); 546 fprintf(stderr, "exec failed: %s\n", strerror(errno)); 547 exit(1); 548 549 } else { 550 // parent 551 552 // Try to sleep. 553 config.Sleep(duration); 554 555 // We may have been woken up to stop profiling. 556 if (config.ShouldStopProfiling()) { 557 // Send SIGHUP to simpleperf to make it stop. 558 kill(pid, SIGHUP); 559 } 560 561 // Wait for the child, so it's reaped correctly. 562 int st = 0; 563 pid_t reaped = TEMP_FAILURE_RETRY(waitpid(pid, &st, 0)); 564 565 if (reaped == -1) { 566 PLOG(WARNING) << "waitpid failed"; 567 } else if (WIFSIGNALED(st)) { 568 if (WTERMSIG(st) == SIGHUP && config.ShouldStopProfiling()) { 569 // That was us... 570 return OK_PROFILE_COLLECTION; 571 } 572 LOG(WARNING) << "perf killed by signal " << WTERMSIG(st); 573 } else if (WEXITSTATUS(st) != 0) { 574 LOG(WARNING) << "perf bad exit status " << WEXITSTATUS(st); 575 } else { 576 return OK_PROFILE_COLLECTION; 577 } 578 } 579 580 return ERR_PERF_RECORD_FAILED; 581 } 582 583 // 584 // Remove all files in the destination directory during initialization 585 // 586 static void cleanup_destination_dir(const std::string& dest_dir) 587 { 588 DIR* dir = opendir(dest_dir.c_str()); 589 if (dir != NULL) { 590 struct dirent* e; 591 while ((e = readdir(dir)) != 0) { 592 if (e->d_name[0] != '.') { 593 std::string file_path = dest_dir + "/" + e->d_name; 594 remove(file_path.c_str()); 595 } 596 } 597 closedir(dir); 598 } else { 599 PLOG(WARNING) << "unable to open destination dir " << dest_dir << " for cleanup"; 600 } 601 } 602 603 // 604 // Collect a perf profile. Steps for this operation are: 605 // - kick off 'perf record' 606 // - read perf.data, convert to protocol buf 607 // 608 static ProtoUniquePtr collect_profile(Config& config) 609 { 610 // 611 // Collect cpu utilization if enabled 612 // 613 unsigned cpu_utilization = 0; 614 if (config.collect_cpu_utilization) { 615 cpu_utilization = collect_cpu_utilization(); 616 } 617 618 // 619 // Form perf.data file name, perf error output file name 620 // 621 const std::string& destdir = config.destination_directory; 622 std::string data_file_path(destdir); 623 data_file_path += "/"; 624 data_file_path += PERF_OUTPUT; 625 std::string perf_stderr_path(destdir); 626 perf_stderr_path += "/perferr.txt"; 627 628 // 629 // Remove any existing perf.data file -- if we don't do this, perf 630 // will rename the old file and we'll have extra cruft lying around. 631 // 632 struct stat statb; 633 if (stat(data_file_path.c_str(), &statb) == 0) { // if file exists... 634 if (unlink(data_file_path.c_str())) { // then try to remove 635 PLOG(WARNING) << "unable to unlink previous perf.data file"; 636 } 637 } 638 639 // 640 // The "mpdecision" daemon can cause problems for profile 641 // collection: if it decides to online a CPU partway through the 642 // 'perf record' run, the activity on that CPU will be invisible to 643 // perf, and if it offlines a CPU during the recording this can 644 // sometimes leave the PMU in an unusable state (dmesg errors of the 645 // form "perfevents: unable to request IRQXXX for ..."). To avoid 646 // these issues, if "mpdecision" is running the helper below will 647 // stop the service and then online all available CPUs. The object 648 // destructor (invoked when this routine terminates) will then 649 // restart the service again when needed. 650 // 651 uint32_t duration = config.sample_duration_in_s; 652 bool hardwire = config.hardwire_cpus; 653 uint32_t max_duration = config.hardwire_cpus_max_duration_in_s; 654 bool take_action = (hardwire && duration <= max_duration); 655 HardwireCpuHelper helper(take_action); 656 657 auto scope_guard = android::base::make_scope_guard( 658 [&data_file_path]() { unlink(data_file_path.c_str()); }); 659 660 // 661 // Invoke perf 662 // 663 const char *stack_profile_opt = 664 (config.stack_profile ? "-g" : nullptr); 665 const std::string& perf_path = config.perf_path; 666 667 PROFILE_RESULT ret = invoke_perf(config, 668 perf_path.c_str(), 669 stack_profile_opt, 670 duration, 671 data_file_path, 672 perf_stderr_path); 673 if (ret != OK_PROFILE_COLLECTION) { 674 return nullptr; 675 } 676 677 // 678 // Read the resulting perf.data file, encode into protocol buffer, then write 679 // the result to the file perf.data.encoded 680 // 681 std::unique_ptr<perfprofd::Symbolizer> symbolizer; 682 if (config.use_elf_symbolizer) { 683 symbolizer = perfprofd::CreateELFSymbolizer(); 684 } 685 return encode_to_proto(data_file_path, config, cpu_utilization, symbolizer.get()); 686 } 687 688 // 689 // Assuming that we want to collect a profile every N seconds, 690 // randomly partition N into two sub-intervals. 691 // 692 static void determine_before_after(unsigned &sleep_before_collect, 693 unsigned &sleep_after_collect, 694 unsigned collection_interval) 695 { 696 double frac = erand48(random_seed); 697 sleep_before_collect = (unsigned) (((double)collection_interval) * frac); 698 assert(sleep_before_collect <= collection_interval); 699 sleep_after_collect = collection_interval - sleep_before_collect; 700 } 701 702 // 703 // Set random number generator seed 704 // 705 static void set_seed(uint32_t use_fixed_seed) 706 { 707 unsigned seed = 0; 708 if (use_fixed_seed) { 709 // 710 // Use fixed user-specified seed 711 // 712 seed = use_fixed_seed; 713 } else { 714 // 715 // Randomized seed 716 // 717 #ifdef __BIONIC__ 718 seed = arc4random(); 719 #else 720 seed = 12345678u; 721 #endif 722 } 723 LOG(INFO) << "random seed set to " << seed; 724 // Distribute the 32-bit seed into the three 16-bit array 725 // elements. The specific values being written do not especially 726 // matter as long as we are setting them to something based on the seed. 727 random_seed[0] = seed & 0xffff; 728 random_seed[1] = (seed >> 16); 729 random_seed[2] = (random_seed[0] ^ random_seed[1]); 730 } 731 732 void CommonInit(uint32_t use_fixed_seed, const char* dest_dir) { 733 // Children of init inherit an artificially low OOM score -- this is not 734 // desirable for perfprofd (its OOM score should be on par with 735 // other user processes). 736 std::stringstream oomscore_path; 737 oomscore_path << "/proc/" << getpid() << "/oom_score_adj"; 738 if (!android::base::WriteStringToFile("0", oomscore_path.str())) { 739 LOG(ERROR) << "unable to write to " << oomscore_path.str(); 740 } 741 742 set_seed(use_fixed_seed); 743 if (dest_dir != nullptr) { 744 cleanup_destination_dir(dest_dir); 745 } 746 747 #ifdef __BIONIC__ 748 running_in_emulator = android::base::GetBoolProperty("ro.kernel.qemu", false); 749 is_debug_build = android::base::GetBoolProperty("ro.debuggable", false); 750 #else 751 running_in_emulator = false; 752 is_debug_build = true; 753 #endif 754 755 common_initialized = true; 756 } 757 758 bool IsDebugBuild() { 759 CHECK(common_initialized); 760 return is_debug_build; 761 } 762 763 template <typename ConfigFn, typename UpdateFn> 764 static void ProfilingLoopImpl(ConfigFn config, UpdateFn update, HandlerFn handler) { 765 unsigned iterations = 0; 766 while(config()->main_loop_iterations == 0 || 767 iterations < config()->main_loop_iterations) { 768 if (config()->ShouldStopProfiling()) { 769 return; 770 } 771 772 // Figure out where in the collection interval we're going to actually 773 // run perf 774 unsigned sleep_before_collect = 0; 775 unsigned sleep_after_collect = 0; 776 determine_before_after(sleep_before_collect, 777 sleep_after_collect, 778 config()->collection_interval_in_s); 779 if (sleep_before_collect > 0) { 780 config()->Sleep(sleep_before_collect); 781 } 782 783 if (config()->ShouldStopProfiling()) { 784 return; 785 } 786 787 // Run any necessary updates. 788 update(); 789 790 // Check for profiling enabled... 791 CKPROFILE_RESULT ckresult = check_profiling_enabled(*config()); 792 if (ckresult != DO_COLLECT_PROFILE) { 793 LOG(INFO) << "profile collection skipped (" << ckprofile_result_to_string(ckresult) << ")"; 794 } else { 795 // Kick off the profiling run... 796 LOG(INFO) << "initiating profile collection"; 797 ProtoUniquePtr proto = collect_profile(*config()); 798 if (proto == nullptr) { 799 LOG(WARNING) << "profile collection failed"; 800 } 801 802 // Always report, even a null result. 803 bool handle_result = handler(proto.get(), config()); 804 if (handle_result) { 805 LOG(INFO) << "profile collection complete"; 806 } else if (proto != nullptr) { 807 LOG(WARNING) << "profile handling failed"; 808 } 809 } 810 811 if (config()->ShouldStopProfiling()) { 812 return; 813 } 814 815 if (sleep_after_collect > 0) { 816 config()->Sleep(sleep_after_collect); 817 } 818 iterations += 1; 819 } 820 } 821 822 void ProfilingLoop(Config& config, HandlerFn handler) { 823 CommonInit(config.use_fixed_seed, nullptr); 824 825 auto config_fn = [&config]() { 826 return &config;; 827 }; 828 auto do_nothing = []() { 829 }; 830 ProfilingLoopImpl(config_fn, do_nothing, handler); 831 } 832 833 void ProfilingLoop(std::function<Config*()> config_fn, 834 std::function<void()> update_fn, 835 HandlerFn handler) { 836 ProfilingLoopImpl(config_fn, update_fn, handler); 837 } 838