Simpleperf: support child inherit option.
In order to support child inherit option, also change the way to open event
files for threads on all cpus in record command.
Bug: 19483574
Change-Id: I0765e9ec90841c1f762490de3dd24ad37b0cc619
diff --git a/simpleperf/cmd_record.cpp b/simpleperf/cmd_record.cpp
index b59dcdc..001066c 100644
--- a/simpleperf/cmd_record.cpp
+++ b/simpleperf/cmd_record.cpp
@@ -82,6 +82,8 @@
" k: only when the branch target is in the kernel\n"
" This option requires at least one branch type among any,\n"
" any_call, any_ret, ind_call.\n"
+ " --no-inherit\n"
+ " Don't record created child threads/processes.\n"
" -o record_file_name Set record file name, default is perf.data.\n"
" -p pid1,pid2,...\n"
" Record events on existing processes. Mutually exclusive with -a.\n"
@@ -92,6 +94,7 @@
system_wide_collection_(false),
branch_sampling_(0),
callchain_sampling_(false),
+ child_inherit_(true),
perf_mmap_pages_(256),
record_filename_("perf.data") {
signaled = false;
@@ -118,10 +121,11 @@
uint64_t sample_period_; // Sample once when 'sample_period_' events occur.
bool system_wide_collection_;
- std::vector<pid_t> monitored_threads_;
uint64_t branch_sampling_;
- std::unique_ptr<EventTypeAndModifier> measured_event_type_modifier_;
bool callchain_sampling_;
+ bool child_inherit_;
+ std::vector<pid_t> monitored_threads_;
+ std::unique_ptr<EventTypeAndModifier> measured_event_type_modifier_;
EventSelectionSet event_selection_set_;
// mmap pages used by each perf event file, should be power of 2.
@@ -173,7 +177,7 @@
return false;
}
} else {
- if (!event_selection_set_.OpenEventFilesForThreads(monitored_threads_)) {
+ if (!event_selection_set_.OpenEventFilesForThreadsOnAllCpus(monitored_threads_)) {
return false;
}
}
@@ -282,6 +286,8 @@
}
branch_sampling_ |= it->second;
}
+ } else if (args[i] == "--no-inherit") {
+ child_inherit_ = false;
} else if (args[i] == "-o") {
if (!NextArgumentOrError(args, &i)) {
return false;
@@ -346,6 +352,7 @@
if (callchain_sampling_) {
event_selection_set_.EnableCallChainSampling();
}
+ event_selection_set_.SetInherit(child_inherit_);
return true;
}
diff --git a/simpleperf/cmd_stat.cpp b/simpleperf/cmd_stat.cpp
index cba2873..83a4a3f 100644
--- a/simpleperf/cmd_stat.cpp
+++ b/simpleperf/cmd_stat.cpp
@@ -57,13 +57,16 @@
" how the event should be monitored. Possible modifiers are:\n"
" u - monitor user space events only\n"
" k - monitor kernel space events only\n"
+ " --no-inherit\n"
+ " Don't stat created child threads/processes.\n"
" -p pid1,pid2,...\n"
" Stat events on existing processes. Mutually exclusive with -a.\n"
" -t tid1,tid2,...\n"
" Stat events on existing threads. Mutually exclusive with -a.\n"
" --verbose Show result in verbose mode.\n"),
verbose_mode_(false),
- system_wide_collection_(false) {
+ system_wide_collection_(false),
+ child_inherit_(true) {
signaled = false;
signal_handler_register_.reset(
new SignalHandlerRegister({SIGCHLD, SIGINT, SIGTERM}, signal_handler));
@@ -75,33 +78,34 @@
bool ParseOptions(const std::vector<std::string>& args, std::vector<std::string>* non_option_args);
bool AddMeasuredEventType(const std::string& event_type_name, bool report_unsupported_type = true);
bool AddDefaultMeasuredEventTypes();
+ void SetEventSelection();
bool ShowCounters(const std::map<const EventType*, std::vector<PerfCounter>>& counters_map,
std::chrono::steady_clock::duration counting_duration);
- std::vector<std::pair<std::string, EventType>> measured_event_types_;
- EventSelectionSet event_selection_set_;
bool verbose_mode_;
bool system_wide_collection_;
+ bool child_inherit_;
std::vector<pid_t> monitored_threads_;
+ std::vector<std::pair<std::string, EventTypeAndModifier>> measured_event_types_;
+ EventSelectionSet event_selection_set_;
std::unique_ptr<SignalHandlerRegister> signal_handler_register_;
};
bool StatCommand::Run(const std::vector<std::string>& args) {
- // 1. Parse options.
+ // 1. Parse options, and use default measured event types if not given.
std::vector<std::string> workload_args;
if (!ParseOptions(args, &workload_args)) {
return false;
}
-
- // 2. Add default measured event types.
- if (event_selection_set_.Empty()) {
+ if (measured_event_types_.empty()) {
if (!AddDefaultMeasuredEventTypes()) {
return false;
}
}
+ SetEventSelection();
- // 3. Create workload.
+ // 2. Create workload.
std::unique_ptr<Workload> workload;
if (!workload_args.empty()) {
workload = Workload::CreateWorkload(workload_args);
@@ -119,7 +123,7 @@
}
}
- // 4. Open perf_event_files.
+ // 3. Open perf_event_files.
if (system_wide_collection_) {
if (!event_selection_set_.OpenEventFilesForAllCpus()) {
return false;
@@ -130,7 +134,7 @@
}
}
- // 5. Count events while workload running.
+ // 4. Count events while workload running.
auto start_time = std::chrono::steady_clock::now();
if (!event_selection_set_.GetEnableOnExec()) {
if (!event_selection_set_.EnableEvents()) {
@@ -145,7 +149,7 @@
}
auto end_time = std::chrono::steady_clock::now();
- // 6. Read and print counters.
+ // 5. Read and print counters.
std::map<const EventType*, std::vector<PerfCounter>> counters_map;
if (!event_selection_set_.ReadCounters(&counters_map)) {
return false;
@@ -173,6 +177,8 @@
return false;
}
}
+ } else if (args[i] == "--no-inherit") {
+ child_inherit_ = false;
} else if (args[i] == "-p") {
if (!NextArgumentOrError(args, &i)) {
return false;
@@ -217,8 +223,7 @@
if (event_type_modifier == nullptr) {
return false;
}
- measured_event_types_.push_back(std::make_pair(event_type_name, event_type_modifier->event_type));
- event_selection_set_.AddEventType(*event_type_modifier);
+ measured_event_types_.push_back(std::make_pair(event_type_name, *event_type_modifier));
return true;
}
@@ -227,13 +232,20 @@
// It is not an error when some event types in the default list are not supported by the kernel.
AddMeasuredEventType(name, false);
}
- if (event_selection_set_.Empty()) {
+ if (measured_event_types_.empty()) {
LOG(ERROR) << "Failed to add any supported default measured types";
return false;
}
return true;
}
+void StatCommand::SetEventSelection() {
+ for (auto& pair : measured_event_types_) {
+ event_selection_set_.AddEventType(pair.second);
+ }
+ event_selection_set_.SetInherit(child_inherit_);
+}
+
bool StatCommand::ShowCounters(
const std::map<const EventType*, std::vector<PerfCounter>>& counters_map,
std::chrono::steady_clock::duration counting_duration) {
@@ -271,7 +283,7 @@
}
std::string event_type_name;
for (auto& pair : measured_event_types_) {
- if (pair.second.name == event_type->name) {
+ if (pair.second.event_type.name == event_type->name) {
event_type_name = pair.first;
}
}
diff --git a/simpleperf/event_selection_set.cpp b/simpleperf/event_selection_set.cpp
index e89a19f..0f23c14 100644
--- a/simpleperf/event_selection_set.cpp
+++ b/simpleperf/event_selection_set.cpp
@@ -17,6 +17,7 @@
#include "event_selection_set.h"
#include <base/logging.h>
+#include <base/stringprintf.h>
#include "environment.h"
#include "event_attr.h"
@@ -113,37 +114,48 @@
}
}
+void EventSelectionSet::SetInherit(bool enable) {
+ for (auto& selection : selections_) {
+ selection.event_attr.inherit = (enable ? 1 : 0);
+ }
+}
+
bool EventSelectionSet::OpenEventFilesForAllCpus() {
+ return OpenEventFilesForThreadsOnAllCpus({-1});
+}
+
+bool EventSelectionSet::OpenEventFilesForThreads(const std::vector<pid_t>& threads) {
+ return OpenEventFiles(threads, {-1});
+}
+
+bool EventSelectionSet::OpenEventFilesForThreadsOnAllCpus(const std::vector<pid_t>& threads) {
std::vector<int> cpus = GetOnlineCpus();
if (cpus.empty()) {
return false;
}
- for (auto& selection : selections_) {
- for (auto& cpu : cpus) {
- auto event_fd = EventFd::OpenEventFile(selection.event_attr, -1, cpu);
- if (event_fd != nullptr) {
- selection.event_fds.push_back(std::move(event_fd));
- }
- }
- // As the online cpus can be enabled or disabled at runtime, we may not open event file for
- // all cpus successfully. But we should open at least one cpu successfully.
- if (selection.event_fds.empty()) {
- PLOG(ERROR) << "failed to open perf event file for event_type " << selection.event_type.name
- << " on all cpus";
- return false;
- }
- }
- return true;
+ return OpenEventFiles(threads, cpus);
}
-bool EventSelectionSet::OpenEventFilesForThreads(const std::vector<pid_t>& threads) {
+bool EventSelectionSet::OpenEventFiles(const std::vector<pid_t>& threads,
+ const std::vector<int>& cpus) {
for (auto& selection : selections_) {
for (auto& tid : threads) {
- auto event_fd = EventFd::OpenEventFile(selection.event_attr, tid, -1);
- if (event_fd == nullptr) {
+ size_t open_per_thread = 0;
+ for (auto& cpu : cpus) {
+ auto event_fd = EventFd::OpenEventFile(selection.event_attr, tid, cpu);
+ if (event_fd != nullptr) {
+ selection.event_fds.push_back(std::move(event_fd));
+ ++open_per_thread;
+ }
+ }
+ // As the online cpus can be enabled or disabled at runtime, we may not open event file for
+ // all cpus successfully. But we should open at least one cpu successfully.
+ if (open_per_thread == 0) {
+ PLOG(ERROR) << "failed to open perf event file for event_type " << selection.event_type.name
+ << " for "
+ << (tid == -1 ? "all threads" : android::base::StringPrintf(" thread %d", tid));
return false;
}
- selection.event_fds.push_back(std::move(event_fd));
}
}
return true;
diff --git a/simpleperf/event_selection_set.h b/simpleperf/event_selection_set.h
index 6f7f8f4..adf3440 100644
--- a/simpleperf/event_selection_set.h
+++ b/simpleperf/event_selection_set.h
@@ -55,9 +55,11 @@
void SetSamplePeriod(uint64_t sample_period);
bool SetBranchSampling(uint64_t branch_sample_type);
void EnableCallChainSampling();
+ void SetInherit(bool enable);
bool OpenEventFilesForAllCpus();
bool OpenEventFilesForThreads(const std::vector<pid_t>& threads);
+ bool OpenEventFilesForThreadsOnAllCpus(const std::vector<pid_t>& threads);
bool EnableEvents();
bool ReadCounters(std::map<const EventType*, std::vector<PerfCounter>>* counters_map);
void PreparePollForEventFiles(std::vector<pollfd>* pollfds);
@@ -69,6 +71,8 @@
const std::vector<std::unique_ptr<EventFd>>& FindEventFdsByType(const EventType& event_type);
private:
+ bool OpenEventFiles(const std::vector<pid_t>& threads, const std::vector<int>& cpus);
+
struct EventSelection {
EventType event_type;
perf_event_attr event_attr;