OSDN Git Service

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