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