OSDN Git Service

simpleperf: support "--app" option in record/stat command.
[android-x86/system-extras.git] / simpleperf / cmd_record.cpp
index acba6ab..e3f35c3 100644 (file)
@@ -78,6 +78,11 @@ class RecordCommand : public Command {
 "       can be used to change target of sampling information.\n"
 "       The default options are: -e cpu-cycles -f 4000 -o perf.data.\n"
 "-a     System-wide collection.\n"
+#if defined(__ANDROID__)
+"--app package_name    Profile the process of an Android application.\n"
+"                      On non-rooted devices, the app must be debuggable,\n"
+"                      because we use run-as to switch to the app's context.\n"
+#endif
 "-b     Enable take branch stack sampling. Same as '-j any'\n"
 "-c count     Set event sample period. It means recording one sample when\n"
 "             [count] events happen. Can't be used with -f/-F option.\n"
@@ -145,6 +150,10 @@ class RecordCommand : public Command {
 "                 This option is used to provide files with symbol table and\n"
 "                 debug information, which are used for unwinding and dumping symbols.\n"
 "-t tid1,tid2,... Record events on existing threads. Mutually exclusive with -a.\n"
+#if 0
+// Below options are only used internally and shouldn't be visible to the public.
+"--in-app         We are already running in the app's context.\n"
+#endif
             // clang-format on
             ),
         use_sample_freq_(false),
@@ -168,7 +177,8 @@ class RecordCommand : public Command {
         start_sampling_time_in_ns_(0),
         sample_record_count_(0),
         lost_record_count_(0),
-        start_profiling_fd_(-1) {
+        start_profiling_fd_(-1),
+        in_app_context_(false) {
     // Stop profiling if parent exits.
     prctl(PR_SET_PDEATHSIG, SIGHUP, 0, 0, 0);
   }
@@ -225,6 +235,8 @@ class RecordCommand : public Command {
   uint64_t sample_record_count_;
   uint64_t lost_record_count_;
   int start_profiling_fd_;
+  std::string app_package_name_;
+  bool in_app_context_;
 };
 
 bool RecordCommand::Run(const std::vector<std::string>& args) {
@@ -242,6 +254,15 @@ bool RecordCommand::Run(const std::vector<std::string>& args) {
   if (!ParseOptions(args, &workload_args)) {
     return false;
   }
+  if (!app_package_name_.empty() && !in_app_context_) {
+    // Some users want to profile non debuggable apps on rooted devices. If we use run-as,
+    // it will be impossible when using --app. So don't switch to app's context when we are
+    // root.
+    if (!IsRoot()) {
+      return RunInAppContext(app_package_name_, "record", args, workload_args.size(),
+                             record_filename_);
+    }
+  }
   if (event_selection_set_.empty()) {
     if (!event_selection_set_.AddEventType(default_measured_event_type)) {
       return false;
@@ -274,6 +295,11 @@ bool RecordCommand::Run(const std::vector<std::string>& args) {
           return false;
         }
       }
+    } else if (!app_package_name_.empty()) {
+      // If app process is not created, wait for it. This allows simpleperf starts before
+      // app process. In this way, we can have a better support of app start-up time profiling.
+      int pid = WaitForAppProcess(app_package_name_);
+      event_selection_set_.AddMonitoredProcesses({pid});
     } else {
       LOG(ERROR)
           << "No threads to monitor. Try `simpleperf help record` for help";
@@ -380,6 +406,11 @@ bool RecordCommand::ParseOptions(const std::vector<std::string>& args,
   for (i = 0; i < args.size() && !args[i].empty() && args[i][0] == '-'; ++i) {
     if (args[i] == "-a") {
       system_wide_collection_ = true;
+    } else if (args[i] == "--app") {
+      if (!NextArgumentOrError(args, &i)) {
+        return false;
+      }
+      app_package_name_ = args[i];
     } else if (args[i] == "-b") {
       branch_sampling_ = branch_sampling_type_map["any"];
     } else if (args[i] == "-c") {
@@ -477,6 +508,8 @@ bool RecordCommand::ParseOptions(const std::vector<std::string>& args,
       if (!event_selection_set_.AddEventGroup(event_types)) {
         return false;
       }
+    } else if (args[i] == "--in-app") {
+      in_app_context_ = true;
     } else if (args[i] == "-j") {
       if (!NextArgumentOrError(args, &i)) {
         return false;