summaryrefslogtreecommitdiff
path: root/simpleperf/cmd_stat.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'simpleperf/cmd_stat.cpp')
-rw-r--r--simpleperf/cmd_stat.cpp211
1 files changed, 54 insertions, 157 deletions
diff --git a/simpleperf/cmd_stat.cpp b/simpleperf/cmd_stat.cpp
index 9ba4a561..c8e59d97 100644
--- a/simpleperf/cmd_stat.cpp
+++ b/simpleperf/cmd_stat.cpp
@@ -25,8 +25,7 @@
#include "command.h"
#include "environment.h"
-#include "event_attr.h"
-#include "event_fd.h"
+#include "event_selection_set.h"
#include "event_type.h"
#include "perf_event.h"
#include "utils.h"
@@ -46,27 +45,12 @@ class StatCommandImpl {
private:
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_types = true);
+ bool AddMeasuredEventType(const std::string& event_type_name, bool report_unsupported_type = true);
bool AddDefaultMeasuredEventTypes();
- bool OpenEventFilesForCpus(const std::vector<int>& cpus);
- bool OpenEventFilesForProcess(pid_t pid);
- bool StartCounting();
- bool StopCounting();
- bool ReadCounters();
- bool ShowCounters(std::chrono::steady_clock::duration counting_duration);
+ bool ShowCounters(const std::map<const EventType*, std::vector<PerfCounter>>& counters_map,
+ std::chrono::steady_clock::duration counting_duration);
- struct EventElem {
- const EventType* const event_type;
- std::vector<std::unique_ptr<EventFd>> event_fds;
- std::vector<PerfCounter> event_counters;
- PerfCounter sum_counter;
-
- EventElem(const EventType* event_type) : event_type(event_type) {
- }
- };
-
- std::vector<EventElem> measured_events_;
+ EventSelectionSet event_selection_set_;
bool verbose_mode_;
bool system_wide_collection_;
};
@@ -79,7 +63,7 @@ bool StatCommandImpl::Run(const std::vector<std::string>& args) {
}
// 2. Add default measured event types.
- if (measured_events_.empty()) {
+ if (event_selection_set_.Empty()) {
if (!AddDefaultMeasuredEventTypes()) {
return false;
}
@@ -87,6 +71,7 @@ bool StatCommandImpl::Run(const std::vector<std::string>& args) {
// 3. Create workload.
if (workload_args.empty()) {
+ // TODO: change default workload to sleep 99999, and run stat until Ctrl-C.
workload_args = std::vector<std::string>({"sleep", "1"});
}
std::unique_ptr<Workload> workload = Workload::CreateWorkload(workload_args);
@@ -96,53 +81,52 @@ bool StatCommandImpl::Run(const std::vector<std::string>& args) {
// 4. Open perf_event_files.
if (system_wide_collection_) {
- std::vector<int> cpus = GetOnlineCpus();
- if (cpus.empty() || !OpenEventFilesForCpus(cpus)) {
+ if (!event_selection_set_.OpenEventFilesForAllCpus()) {
return false;
}
} else {
- if (!OpenEventFilesForProcess(workload->GetWorkPid())) {
+ event_selection_set_.EnableOnExec();
+ if (!event_selection_set_.OpenEventFilesForProcess(workload->GetPid())) {
return false;
}
}
// 5. Count events while workload running.
auto start_time = std::chrono::steady_clock::now();
- if (!StartCounting()) {
- return false;
+ // If monitoring only one process, we use the enable_on_exec flag, and don't need to start
+ // counting manually.
+ if (system_wide_collection_) {
+ if (!event_selection_set_.EnableEvents()) {
+ return false;
+ }
}
if (!workload->Start()) {
return false;
}
workload->WaitFinish();
- if (!StopCounting()) {
- return false;
- }
auto end_time = std::chrono::steady_clock::now();
// 6. Read and print counters.
- if (!ReadCounters()) {
+ std::map<const EventType*, std::vector<PerfCounter>> counters_map;
+ if (!event_selection_set_.ReadCounters(&counters_map)) {
return false;
}
- if (!ShowCounters(end_time - start_time)) {
+ if (!ShowCounters(counters_map, end_time - start_time)) {
return false;
}
-
return true;
}
bool StatCommandImpl::ParseOptions(const std::vector<std::string>& args,
std::vector<std::string>* non_option_args) {
size_t i;
- for (i = 0; i < args.size() && args[i].size() > 0 && args[i][0] == '-'; ++i) {
+ for (i = 1; i < args.size() && args[i].size() > 0 && args[i][0] == '-'; ++i) {
if (args[i] == "-a") {
system_wide_collection_ = true;
} else if (args[i] == "-e") {
- if (i + 1 == args.size()) {
- LOG(ERROR) << "No event list following -e option. Try `simpleperf help stat`";
+ if (!NextArgumentOrError(args, &i)) {
return false;
}
- ++i;
std::vector<std::string> event_types = android::base::Split(args[i], ",");
for (auto& event_type : event_types) {
if (!AddMeasuredEventType(event_type)) {
@@ -168,19 +152,13 @@ bool StatCommandImpl::ParseOptions(const std::vector<std::string>& args,
}
bool StatCommandImpl::AddMeasuredEventType(const std::string& event_type_name,
- bool report_unsupported_types) {
- const EventType* event_type = EventTypeFactory::FindEventTypeByName(event_type_name);
+ bool report_unsupported_type) {
+ const EventType* event_type =
+ EventTypeFactory::FindEventTypeByName(event_type_name, report_unsupported_type);
if (event_type == nullptr) {
- LOG(ERROR) << "Unknown event_type: " << event_type_name;
- LOG(ERROR) << "Try `simpleperf help list` to list all possible event type names";
return false;
}
- if (!event_type->IsSupportedByKernel()) {
- (report_unsupported_types ? LOG(ERROR) : LOG(DEBUG)) << "Event type " << event_type->name
- << " is not supported by the kernel";
- return false;
- }
- measured_events_.push_back(EventElem(event_type));
+ event_selection_set_.AddEventType(*event_type);
return true;
}
@@ -189,129 +167,52 @@ bool StatCommandImpl::AddDefaultMeasuredEventTypes() {
// It is not an error when some event types in the default list are not supported by the kernel.
AddMeasuredEventType(name, false);
}
- if (measured_events_.empty()) {
+ if (event_selection_set_.Empty()) {
LOG(ERROR) << "Failed to add any supported default measured types";
return false;
}
return true;
}
-bool StatCommandImpl::OpenEventFilesForCpus(const std::vector<int>& cpus) {
- for (auto& elem : measured_events_) {
- EventAttr attr = EventAttr::CreateDefaultAttrToMonitorEvent(*elem.event_type);
- std::vector<std::unique_ptr<EventFd>> event_fds;
- for (auto& cpu : cpus) {
- auto event_fd = EventFd::OpenEventFileForCpu(attr, cpu);
- if (event_fd != nullptr) {
- event_fds.push_back(std::move(event_fd));
- }
- }
- // As the online cpus can be enabled or disabled at runtime, we may not open perf_event_file
- // for all cpus successfully. But we should open at least one cpu successfully for each event
- // type.
- if (event_fds.empty()) {
- LOG(ERROR) << "failed to open perf_event_files for event_type " << elem.event_type->name
- << " on all cpus";
- return false;
- }
- elem.event_fds = std::move(event_fds);
- }
- return true;
-}
-
-bool StatCommandImpl::OpenEventFilesForProcess(pid_t pid) {
- for (auto& elem : measured_events_) {
- EventAttr attr = EventAttr::CreateDefaultAttrToMonitorEvent(*elem.event_type);
- std::vector<std::unique_ptr<EventFd>> event_fds;
- auto event_fd = EventFd::OpenEventFileForProcess(attr, pid);
- if (event_fd == nullptr) {
- PLOG(ERROR) << "failed to open perf_event_file for event_type " << elem.event_type->name
- << " on pid " << pid;
- return false;
- }
- event_fds.push_back(std::move(event_fd));
- elem.event_fds = std::move(event_fds);
- }
- return true;
-}
-
-bool StatCommandImpl::StartCounting() {
- for (auto& elem : measured_events_) {
- for (auto& event_fd : elem.event_fds) {
- if (!event_fd->EnableEvent()) {
- return false;
- }
- }
- }
- return true;
-}
-
-bool StatCommandImpl::StopCounting() {
- for (auto& elem : measured_events_) {
- for (auto& event_fd : elem.event_fds) {
- if (!event_fd->DisableEvent()) {
- return false;
- }
- }
- }
- return true;
-}
-
-bool StatCommandImpl::ReadCounters() {
- for (auto& elem : measured_events_) {
- std::vector<PerfCounter> event_counters;
- for (auto& event_fd : elem.event_fds) {
- PerfCounter counter;
- if (!event_fd->ReadCounter(&counter)) {
- return false;
- }
- event_counters.push_back(counter);
- }
- PerfCounter sum_counter = event_counters.front();
- for (size_t i = 1; i < event_counters.size(); ++i) {
- sum_counter.value += event_counters[i].value;
- sum_counter.time_enabled += event_counters[i].time_enabled;
- sum_counter.time_running += event_counters[i].time_running;
- }
- elem.event_counters = event_counters;
- elem.sum_counter = sum_counter;
- }
- return true;
-}
-
-bool StatCommandImpl::ShowCounters(std::chrono::steady_clock::duration counting_duration) {
+bool StatCommandImpl::ShowCounters(
+ const std::map<const EventType*, std::vector<PerfCounter>>& counters_map,
+ std::chrono::steady_clock::duration counting_duration) {
printf("Performance counter statistics:\n\n");
- for (auto& elem : measured_events_) {
- std::string event_type_name = elem.event_type->name;
+ for (auto& pair : counters_map) {
+ auto& event_type = pair.first;
+ auto& counters = pair.second;
if (verbose_mode_) {
- auto& event_fds = elem.event_fds;
- auto& counters = elem.event_counters;
- for (size_t i = 0; i < elem.event_fds.size(); ++i) {
- printf("%s: value %'" PRId64 ", time_enabled %" PRId64 ", time_disabled %" PRId64
+ for (auto& counter : counters) {
+ printf("%s: value %'" PRId64 ", time_enabled %" PRId64 ", time_running %" PRId64
", id %" PRId64 "\n",
- event_fds[i]->Name().c_str(), counters[i].value, counters[i].time_enabled,
- counters[i].time_running, counters[i].id);
+ event_selection_set_.FindEventFileNameById(counter.id).c_str(), counter.value,
+ counter.time_enabled, counter.time_running, counter.id);
}
}
- auto& counter = elem.sum_counter;
+ PerfCounter sum_counter;
+ memset(&sum_counter, 0, sizeof(sum_counter));
+ for (auto& counter : counters) {
+ sum_counter.value += counter.value;
+ sum_counter.time_enabled += counter.time_enabled;
+ sum_counter.time_running += counter.time_running;
+ }
bool scaled = false;
- int64_t scaled_count = counter.value;
- if (counter.time_running < counter.time_enabled) {
- if (counter.time_running == 0) {
+ int64_t scaled_count = sum_counter.value;
+ if (sum_counter.time_running < sum_counter.time_enabled) {
+ if (sum_counter.time_running == 0) {
scaled_count = 0;
} else {
scaled = true;
- scaled_count = static_cast<int64_t>(static_cast<double>(counter.value) *
- counter.time_enabled / counter.time_running);
+ scaled_count = static_cast<int64_t>(static_cast<double>(sum_counter.value) *
+ sum_counter.time_enabled / sum_counter.time_running);
}
}
printf("%'30" PRId64 "%s %s\n", scaled_count, scaled ? "(scaled)" : " ",
- event_type_name.c_str());
+ event_type->name);
}
- printf("\n");
- printf("Total test time: %lf seconds.\n",
+ printf("\nTotal test time: %lf seconds.\n",
std::chrono::duration_cast<std::chrono::duration<double>>(counting_duration).count());
return true;
}
@@ -326,17 +227,13 @@ class StatCommand : public Command {
" -a Collect system-wide information.\n"
" -e event1,event2,... Select the event list to count. Use `simpleperf list`\n"
" to find all possible event names.\n"
- " --verbose Show result in verbose mode.\n"
- " --help Print this help information.\n") {
+ " --verbose Show result in verbose mode.\n") {
}
bool Run(const std::vector<std::string>& args) override {
- for (auto& arg : args) {
- if (arg == "--help") {
- printf("%s\n", LongHelpString().c_str());
- return true;
- }
- }
+ // Keep the implementation in StatCommandImpl, so the resources used are cleaned up when the
+ // command finishes. This is useful when we need to call some commands multiple times, like
+ // in unit tests.
StatCommandImpl impl;
return impl.Run(args);
}