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