summaryrefslogtreecommitdiff
path: root/simpleperf/cmd_record.cpp
diff options
context:
space:
mode:
authorYabin Cui <yabinc@google.com>2015-06-17 21:15:09 -0700
committerYabin Cui <yabinc@google.com>2015-06-18 16:47:02 -0700
commitb032de7a9e1975a838cd6df2e7c8df3c7f70a3ce (patch)
tree08c1d077015624b5488edc7483050f492364c451 /simpleperf/cmd_record.cpp
parent1ded5c77b86bf64d121251e70d84fbe7cf19b06c (diff)
downloadextras-b032de7a9e1975a838cd6df2e7c8df3c7f70a3ce.tar.gz
Simpleperf: support monitoring existing processes/threads.
Also change the default record freq from 1000 to 4000. Because 1000 seems to be too low. Bug: 19483574 Change-Id: I340fcb9d28a156862705e483ee340a1c824eea21
Diffstat (limited to 'simpleperf/cmd_record.cpp')
-rw-r--r--simpleperf/cmd_record.cpp110
1 files changed, 71 insertions, 39 deletions
diff --git a/simpleperf/cmd_record.cpp b/simpleperf/cmd_record.cpp
index 2ceeed02..e87a7ec1 100644
--- a/simpleperf/cmd_record.cpp
+++ b/simpleperf/cmd_record.cpp
@@ -17,6 +17,7 @@
#include <libgen.h>
#include <poll.h>
#include <signal.h>
+#include <set>
#include <string>
#include <unordered_map>
#include <vector>
@@ -53,33 +54,37 @@ static void signal_handler(int) {
class RecordCommand : public Command {
public:
RecordCommand()
- : Command("record", "record sampling info in perf.data",
- "Usage: simpleperf record [options] [command [command-args]]\n"
- " Gather sampling information when running [command]. If [command]\n"
- " is not specified, sleep 1 is used instead.\n"
- " -a System-wide collection.\n"
- " -b Enable take branch stack sampling. Same as '-j any'\n"
- " -c count Set event sample period.\n"
- " -e event Select the event to sample (Use `simpleperf list`)\n"
- " to find all possible event names.\n"
- " -f freq Set event sample frequency.\n"
- " -F freq Same as '-f freq'.\n"
- " -g Enables call-graph recording.\n"
- " -j branch_filter1,branch_filter2,...\n"
- " Enable taken branch stack sampling. Each sample\n"
- " captures a series of consecutive taken branches.\n"
- " The following filters are defined:\n"
- " any: any type of branch\n"
- " any_call: any function call or system call\n"
- " any_ret: any function return or system call return\n"
- " ind_call: any indirect branch\n"
- " u: only when the branch target is at the user level\n"
- " 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"
- " -o record_file_name Set record file name, default is perf.data.\n"),
+ : Command(
+ "record", "record sampling info in perf.data",
+ "Usage: simpleperf record [options] [command [command-args]]\n"
+ " Gather sampling information when running [command].\n"
+ " -a System-wide collection.\n"
+ " -b Enable take branch stack sampling. Same as '-j any'\n"
+ " -c count Set event sample period.\n"
+ " -e event Select the event to sample (Use `simpleperf list`)\n"
+ " to find all possible event names.\n"
+ " -f freq Set event sample frequency.\n"
+ " -F freq Same as '-f freq'.\n"
+ " -g Enables call-graph recording.\n"
+ " -j branch_filter1,branch_filter2,...\n"
+ " Enable taken branch stack sampling. Each sample\n"
+ " captures a series of consecutive taken branches.\n"
+ " The following filters are defined:\n"
+ " any: any type of branch\n"
+ " any_call: any function call or system call\n"
+ " any_ret: any function return or system call return\n"
+ " ind_call: any indirect branch\n"
+ " u: only when the branch target is at the user level\n"
+ " 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"
+ " -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"
+ " -t tid1,tid2,...\n"
+ " Record events on existing threads. Mutually exclusive with -a.\n"),
use_sample_freq_(true),
- sample_freq_(1000),
+ sample_freq_(4000),
system_wide_collection_(false),
branch_sampling_(0),
callchain_sampling_(false),
@@ -110,6 +115,7 @@ class RecordCommand : public Command {
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_;
bool callchain_sampling_;
const EventType* measured_event_type_;
@@ -140,13 +146,21 @@ bool RecordCommand::Run(const std::vector<std::string>& args) {
}
// 2. Create workload.
- if (workload_args.empty()) {
- // TODO: change default workload to sleep 99999, and run record until Ctrl-C.
- workload_args = std::vector<std::string>({"sleep", "1"});
+ std::unique_ptr<Workload> workload;
+ if (!workload_args.empty()) {
+ workload = Workload::CreateWorkload(workload_args);
+ if (workload == nullptr) {
+ return false;
+ }
}
- std::unique_ptr<Workload> workload = Workload::CreateWorkload(workload_args);
- if (workload == nullptr) {
- return false;
+ if (!system_wide_collection_ && monitored_threads_.empty()) {
+ if (workload != nullptr) {
+ monitored_threads_.push_back(workload->GetPid());
+ event_selection_set_.SetEnableOnExec(true);
+ } else {
+ LOG(ERROR) << "No threads to monitor. Try `simpleperf help record` for help\n";
+ return false;
+ }
}
// 3. Open perf_event_files, create memory mapped buffers for perf_event_files, add prepare poll
@@ -156,8 +170,7 @@ bool RecordCommand::Run(const std::vector<std::string>& args) {
return false;
}
} else {
- event_selection_set_.EnableOnExec();
- if (!event_selection_set_.OpenEventFilesForProcess(workload->GetPid())) {
+ if (!event_selection_set_.OpenEventFilesForThreads(monitored_threads_)) {
return false;
}
}
@@ -182,15 +195,12 @@ bool RecordCommand::Run(const std::vector<std::string>& args) {
}
// 5. Write records in mmap buffers of perf_event_files to output file while workload is running.
-
- // If monitoring only one process, we use the enable_on_exec flag, and don't need to start
- // recording manually.
- if (system_wide_collection_) {
+ if (!event_selection_set_.GetEnableOnExec()) {
if (!event_selection_set_.EnableEvents()) {
return false;
}
}
- if (!workload->Start()) {
+ if (workload != nullptr && !workload->Start()) {
return false;
}
auto callback =
@@ -217,6 +227,7 @@ bool RecordCommand::Run(const std::vector<std::string>& args) {
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].size() > 0 && args[i][0] == '-'; ++i) {
if (args[i] == "-a") {
@@ -272,12 +283,33 @@ bool RecordCommand::ParseOptions(const std::vector<std::string>& args,
return false;
}
record_filename_ = args[i];
+ } else if (args[i] == "-p") {
+ if (!NextArgumentOrError(args, &i)) {
+ return false;
+ }
+ if (!GetValidThreadsFromProcessString(args[i], &tid_set)) {
+ return false;
+ }
+ } else if (args[i] == "-t") {
+ if (!NextArgumentOrError(args, &i)) {
+ return false;
+ }
+ if (!GetValidThreadsFromThreadString(args[i], &tid_set)) {
+ return false;
+ }
} else {
ReportUnknownOption(args, i);
return false;
}
}
+ monitored_threads_.insert(monitored_threads_.end(), tid_set.begin(), tid_set.end());
+ if (system_wide_collection_ && !monitored_threads_.empty()) {
+ LOG(ERROR)
+ << "Record system wide and existing processes/threads can't be used at the same time.";
+ return false;
+ }
+
if (non_option_args != nullptr) {
non_option_args->clear();
for (; i < args.size(); ++i) {