Home | History | Annotate | Download | only in perfprofd
      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