Merge "simpleperf: handle monitored processes correctly when a cpu is up."
diff --git a/simpleperf/cmd_record.cpp b/simpleperf/cmd_record.cpp
index e746a9a..7671047 100644
--- a/simpleperf/cmd_record.cpp
+++ b/simpleperf/cmd_record.cpp
@@ -181,9 +181,7 @@
   bool DumpKernelSymbol();
   bool DumpTracingData();
   bool DumpKernelAndModuleMmaps(const perf_event_attr& attr, uint64_t event_id);
-  bool DumpThreadCommAndMmaps(const perf_event_attr& attr, uint64_t event_id,
-                              bool all_threads,
-                              const std::vector<pid_t>& selected_threads);
+  bool DumpThreadCommAndMmaps(const perf_event_attr& attr, uint64_t event_id);
   bool ProcessRecord(Record* record);
   bool DumpSymbolForRecord(const SampleRecord& r, bool for_callchain);
   void UpdateRecordForEmbeddedElfPath(Record* record);
@@ -209,7 +207,6 @@
   double duration_in_sec_;
   bool can_dump_kernel_symbols_;
   bool dump_symbols_;
-  std::vector<pid_t> monitored_threads_;
   std::vector<int> cpus_;
   EventSelectionSet event_selection_set_;
 
@@ -255,9 +252,11 @@
       return false;
     }
   }
-  if (!system_wide_collection_ && monitored_threads_.empty()) {
+  if (system_wide_collection_) {
+    event_selection_set_.AddMonitoredThreads({-1});
+  } else if (!event_selection_set_.HasMonitoredTarget()) {
     if (workload != nullptr) {
-      monitored_threads_.push_back(workload->GetPid());
+      event_selection_set_.AddMonitoredProcesses({workload->GetPid()});
       event_selection_set_.SetEnableOnExec(true);
     } else {
       LOG(ERROR)
@@ -267,15 +266,8 @@
   }
 
   // 3. Open perf_event_files, create mapped buffers for perf_event_files.
-  if (system_wide_collection_) {
-    if (!event_selection_set_.OpenEventFilesForCpus(cpus_)) {
-      return false;
-    }
-  } else {
-    if (!event_selection_set_.OpenEventFilesForThreadsOnCpus(monitored_threads_,
-                                                             cpus_)) {
-      return false;
-    }
+  if (!event_selection_set_.OpenEventFiles(cpus_)) {
+    return false;
   }
   if (!event_selection_set_.MmapEventFiles(mmap_page_range_.first,
                                            mmap_page_range_.second)) {
@@ -363,7 +355,6 @@
 
 bool RecordCommand::ParseOptions(const std::vector<std::string>& args,
                                  std::vector<std::string>* non_option_args) {
-  std::set<pid_t> tid_set;
   size_t i;
   for (i = 0; i < args.size() && !args[i].empty() && args[i][0] == '-'; ++i) {
     if (args[i] == "-a") {
@@ -509,9 +500,11 @@
       if (!NextArgumentOrError(args, &i)) {
         return false;
       }
-      if (!GetValidThreadsFromProcessString(args[i], &tid_set)) {
+      std::set<pid_t> pids;
+      if (!GetValidThreadsFromThreadString(args[i], &pids)) {
         return false;
       }
+      event_selection_set_.AddMonitoredProcesses(pids);
     } else if (args[i] == "--post-unwind") {
       post_unwind_ = true;
     } else if (args[i] == "--symfs") {
@@ -525,9 +518,11 @@
       if (!NextArgumentOrError(args, &i)) {
         return false;
       }
-      if (!GetValidThreadsFromThreadString(args[i], &tid_set)) {
+      std::set<pid_t> tids;
+      if (!GetValidThreadsFromThreadString(args[i], &tids)) {
         return false;
       }
+      event_selection_set_.AddMonitoredThreads(tids);
     } else {
       ReportUnknownOption(args, i);
       return false;
@@ -559,9 +554,7 @@
     }
   }
 
-  monitored_threads_.insert(monitored_threads_.end(), tid_set.begin(),
-                            tid_set.end());
-  if (system_wide_collection_ && !monitored_threads_.empty()) {
+  if (system_wide_collection_ && event_selection_set_.HasMonitoredTarget()) {
     LOG(ERROR) << "Record system wide and existing processes/threads can't be "
                   "used at the same time.";
     return false;
@@ -643,8 +636,7 @@
   if (!DumpKernelAndModuleMmaps(attr, event_id)) {
     return false;
   }
-  if (!DumpThreadCommAndMmaps(attr, event_id, system_wide_collection_,
-                              monitored_threads_)) {
+  if (!DumpThreadCommAndMmaps(attr, event_id)) {
     return false;
   }
   return true;
@@ -748,19 +740,20 @@
   return true;
 }
 
-bool RecordCommand::DumpThreadCommAndMmaps(
-    const perf_event_attr& attr, uint64_t event_id, bool all_threads,
-    const std::vector<pid_t>& selected_threads) {
+bool RecordCommand::DumpThreadCommAndMmaps(const perf_event_attr& attr,
+                                           uint64_t event_id) {
   std::vector<ThreadComm> thread_comms;
   if (!GetThreadComms(&thread_comms)) {
     return false;
   }
   // Decide which processes and threads to dump.
-  std::set<pid_t> dump_processes;
-  std::set<pid_t> dump_threads;
-  for (auto& tid : selected_threads) {
-    dump_threads.insert(tid);
+  bool all_threads = system_wide_collection_;
+  std::set<pid_t> dump_threads = event_selection_set_.GetMonitoredThreads();
+  for (const auto& pid : event_selection_set_.GetMonitoredProcesses()) {
+    std::vector<pid_t> tids = GetThreadsInProcess(pid);
+    dump_threads.insert(tids.begin(), tids.end());
   }
+  std::set<pid_t> dump_processes;
   for (auto& thread : thread_comms) {
     if (dump_threads.find(thread.tid) != dump_threads.end()) {
       dump_processes.insert(thread.pid);
diff --git a/simpleperf/cmd_stat.cpp b/simpleperf/cmd_stat.cpp
index 728deb2..93054d2 100644
--- a/simpleperf/cmd_stat.cpp
+++ b/simpleperf/cmd_stat.cpp
@@ -312,7 +312,6 @@
   bool system_wide_collection_;
   bool child_inherit_;
   double duration_in_sec_;
-  std::vector<pid_t> monitored_threads_;
   std::vector<int> cpus_;
   EventSelectionSet event_selection_set_;
   std::string output_filename_;
@@ -344,9 +343,11 @@
       return false;
     }
   }
-  if (!system_wide_collection_ && monitored_threads_.empty()) {
+  if (system_wide_collection_) {
+    event_selection_set_.AddMonitoredThreads({-1});
+  } else if (!event_selection_set_.HasMonitoredTarget()) {
     if (workload != nullptr) {
-      monitored_threads_.push_back(workload->GetPid());
+      event_selection_set_.AddMonitoredProcesses({workload->GetPid()});
       event_selection_set_.SetEnableOnExec(true);
     } else {
       LOG(ERROR)
@@ -356,21 +357,16 @@
   }
 
   // 3. Open perf_event_files.
-  if (system_wide_collection_) {
-    if (!event_selection_set_.OpenEventFilesForCpus(cpus_)) {
-      return false;
-    }
-  } else {
-    std::vector<int> all_cpus = {-1};
-    if (!event_selection_set_.OpenEventFilesForThreadsOnCpus(
-            monitored_threads_, cpus_.empty() ? all_cpus : cpus_)) {
-      return false;
-    }
+  if (!system_wide_collection_ && cpus_.empty()) {
+    cpus_.push_back(-1);  // Monitor on all cpus.
+  }
+  if (!event_selection_set_.OpenEventFiles(cpus_)) {
+    return false;
   }
 
   // 4. Create IOEventLoop and add signal/periodic Events.
   IOEventLoop loop;
-  if (system_wide_collection_ || !cpus_.empty()) {
+  if (system_wide_collection_ || (!cpus_.empty() && cpus_[0] != -1)) {
     if (!event_selection_set_.HandleCpuHotplugEvents(loop, cpus_)) {
       return false;
     }
@@ -465,16 +461,20 @@
       if (!NextArgumentOrError(args, &i)) {
         return false;
       }
-      if (!GetValidThreadsFromProcessString(args[i], &tid_set)) {
+      std::set<pid_t> pids;
+      if (!GetValidThreadsFromThreadString(args[i], &pids)) {
         return false;
       }
+      event_selection_set_.AddMonitoredProcesses(pids);
     } else if (args[i] == "-t") {
       if (!NextArgumentOrError(args, &i)) {
         return false;
       }
-      if (!GetValidThreadsFromThreadString(args[i], &tid_set)) {
+      std::set<pid_t> tids;
+      if (!GetValidThreadsFromThreadString(args[i], &tids)) {
         return false;
       }
+      event_selection_set_.AddMonitoredThreads(tids);
     } else if (args[i] == "--verbose") {
       verbose_mode_ = true;
     } else {
@@ -483,9 +483,7 @@
     }
   }
 
-  monitored_threads_.insert(monitored_threads_.end(), tid_set.begin(),
-                            tid_set.end());
-  if (system_wide_collection_ && !monitored_threads_.empty()) {
+  if (system_wide_collection_ && event_selection_set_.HasMonitoredTarget()) {
     LOG(ERROR) << "Stat system wide and existing processes/threads can't be "
                   "used at the same time.";
     return false;
diff --git a/simpleperf/environment.cpp b/simpleperf/environment.cpp
index 621bc9f..1de8a1e 100644
--- a/simpleperf/environment.cpp
+++ b/simpleperf/environment.cpp
@@ -246,7 +246,7 @@
   return false;
 }
 
-static std::vector<pid_t> GetThreadsInProcess(pid_t pid) {
+std::vector<pid_t> GetThreadsInProcess(pid_t pid) {
   std::vector<pid_t> result;
   std::string task_dirname = android::base::StringPrintf("/proc/%d/task", pid);
   for (const auto& name : GetSubDirs(task_dirname)) {
@@ -340,24 +340,6 @@
   return GetBuildIdFromNoteFile(notefile, build_id);
 }
 
-bool GetValidThreadsFromProcessString(const std::string& pid_str, std::set<pid_t>* tid_set) {
-  std::vector<std::string> strs = android::base::Split(pid_str, ",");
-  for (const auto& s : strs) {
-    int pid;
-    if (!android::base::ParseInt(s.c_str(), &pid, 0)) {
-      LOG(ERROR) << "Invalid pid '" << s << "'";
-      return false;
-    }
-    std::vector<pid_t> tids = GetThreadsInProcess(pid);
-    if (tids.empty()) {
-      LOG(ERROR) << "Non existing process '" << pid << "'";
-      return false;
-    }
-    tid_set->insert(tids.begin(), tids.end());
-  }
-  return true;
-}
-
 bool GetValidThreadsFromThreadString(const std::string& tid_str, std::set<pid_t>* tid_set) {
   std::vector<std::string> strs = android::base::Split(tid_str, ",");
   for (const auto& s : strs) {
diff --git a/simpleperf/environment.h b/simpleperf/environment.h
index 2f0f59c..176c9ce 100644
--- a/simpleperf/environment.h
+++ b/simpleperf/environment.h
@@ -64,7 +64,7 @@
 bool GetKernelBuildId(BuildId* build_id);
 bool GetModuleBuildId(const std::string& module_name, BuildId* build_id);
 
-bool GetValidThreadsFromProcessString(const std::string& pid_str, std::set<pid_t>* tid_set);
+std::vector<pid_t> GetThreadsInProcess(pid_t pid);
 bool GetValidThreadsFromThreadString(const std::string& tid_str, std::set<pid_t>* tid_set);
 
 bool GetExecPath(std::string* exec_path);
diff --git a/simpleperf/event_selection_set.cpp b/simpleperf/event_selection_set.cpp
index 9d65ec1..d6b1fe6 100644
--- a/simpleperf/event_selection_set.cpp
+++ b/simpleperf/event_selection_set.cpp
@@ -265,23 +265,6 @@
   return true;
 }
 
-bool EventSelectionSet::OpenEventFilesForCpus(const std::vector<int>& cpus) {
-  return OpenEventFilesForThreadsOnCpus({-1}, cpus);
-}
-
-bool EventSelectionSet::OpenEventFilesForThreadsOnCpus(
-    const std::vector<pid_t>& threads, std::vector<int> cpus) {
-  if (!cpus.empty()) {
-    // cpus = {-1} means open an event file for all cpus.
-    if (!(cpus.size() == 1 && cpus[0] == -1) && !CheckIfCpusOnline(cpus)) {
-      return false;
-    }
-  } else {
-    cpus = GetOnlineCpus();
-  }
-  return OpenEventFiles(threads, cpus);
-}
-
 static bool OpenEventFile(EventSelectionGroup& group, pid_t tid, int cpu,
                           std::string* failed_event_type) {
   std::vector<std::unique_ptr<EventFd>> event_fds;
@@ -310,8 +293,27 @@
   return true;
 }
 
-bool EventSelectionSet::OpenEventFiles(const std::vector<pid_t>& threads,
-                                       const std::vector<int>& cpus) {
+static std::set<pid_t> PrepareThreads(const std::set<pid_t>& processes,
+                                      const std::set<pid_t>& threads) {
+  std::set<pid_t> result = threads;
+  for (const auto& pid : processes) {
+    std::vector<pid_t> tids = GetThreadsInProcess(pid);
+    result.insert(tids.begin(), tids.end());
+  }
+  return result;
+}
+
+bool EventSelectionSet::OpenEventFiles(const std::vector<int>& on_cpus) {
+  std::vector<int> cpus = on_cpus;
+  if (!cpus.empty()) {
+    // cpus = {-1} means open an event file for all cpus.
+    if (!(cpus.size() == 1 && cpus[0] == -1) && !CheckIfCpusOnline(cpus)) {
+      return false;
+    }
+  } else {
+    cpus = GetOnlineCpus();
+  }
+  std::set<pid_t> threads = PrepareThreads(processes_, threads_);
   for (auto& group : groups_) {
     for (const auto& tid : threads) {
       size_t success_cpu_count = 0;
@@ -334,7 +336,6 @@
       }
     }
   }
-  threads_.insert(threads_.end(), threads.begin(), threads.end());
   return true;
 }
 
@@ -545,8 +546,9 @@
 bool EventSelectionSet::HandleCpuOnlineEvent(int cpu) {
   // We need to start profiling when opening new event files.
   SetEnableOnExec(false);
+  std::set<pid_t> threads = PrepareThreads(processes_, threads_);
   for (auto& group : groups_) {
-    for (const auto& tid : threads_) {
+    for (const auto& tid : threads) {
       std::string failed_event_type;
       if (!OpenEventFile(group, tid, cpu, &failed_event_type)) {
         // If failed to open event files, maybe the cpu has been offlined.
diff --git a/simpleperf/event_selection_set.h b/simpleperf/event_selection_set.h
index 5a2dea4..53c8edd 100644
--- a/simpleperf/event_selection_set.h
+++ b/simpleperf/event_selection_set.h
@@ -97,9 +97,27 @@
   void SetInherit(bool enable);
   void SetLowWatermark();
 
-  bool OpenEventFilesForCpus(const std::vector<int>& cpus);
-  bool OpenEventFilesForThreadsOnCpus(const std::vector<pid_t>& threads,
-                                      std::vector<int> cpus);
+  void AddMonitoredProcesses(const std::set<pid_t>& processes) {
+    processes_.insert(processes.begin(), processes.end());
+  }
+
+  void AddMonitoredThreads(const std::set<pid_t>& threads) {
+    threads_.insert(threads.begin(), threads.end());
+  }
+
+  const std::set<pid_t>& GetMonitoredProcesses() const {
+    return processes_;
+  }
+
+  const std::set<pid_t>& GetMonitoredThreads() const {
+    return threads_;
+  }
+
+  bool HasMonitoredTarget() const {
+    return !processes_.empty() || !threads_.empty();
+  }
+
+  bool OpenEventFiles(const std::vector<int>& on_cpus);
   bool ReadCounters(std::vector<CountersInfo>* counters);
   bool MmapEventFiles(size_t min_mmap_pages, size_t max_mmap_pages);
   bool PrepareToReadMmapEventData(IOEventLoop& loop,
@@ -116,8 +134,6 @@
   bool BuildAndCheckEventSelection(const std::string& event_name,
                                    EventSelection* selection);
   void UnionSampleType();
-  bool OpenEventFiles(const std::vector<pid_t>& threads,
-                      const std::vector<int>& cpus);
   bool MmapEventFiles(size_t mmap_pages, bool report_error);
   bool ReadMmapEventDataForFd(EventFd* event_fd);
 
@@ -129,7 +145,8 @@
   const bool for_stat_cmd_;
 
   std::vector<EventSelectionGroup> groups_;
-  std::vector<pid_t> threads_;
+  std::set<pid_t> processes_;
+  std::set<pid_t> threads_;
   size_t mmap_pages_;
 
   IOEventLoop* loop_;