summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--simpleperf/cmd_stat.cpp10
-rw-r--r--simpleperf/event_selection_set.cpp130
-rw-r--r--simpleperf/event_selection_set.h29
3 files changed, 119 insertions, 50 deletions
diff --git a/simpleperf/cmd_stat.cpp b/simpleperf/cmd_stat.cpp
index 76df147f..728deb2e 100644
--- a/simpleperf/cmd_stat.cpp
+++ b/simpleperf/cmd_stat.cpp
@@ -572,13 +572,9 @@ bool StatCommand::ShowCounters(const std::vector<CountersInfo>& counters,
uint64_t time_enabled_sum = 0;
uint64_t time_running_sum = 0;
for (auto& counter_info : counters_info.counters) {
- // If time_running is 0, the program has never run on this event and we
- // shouldn't summarize it.
- if (counter_info.counter.time_running != 0) {
- value_sum += counter_info.counter.value;
- time_enabled_sum += counter_info.counter.time_enabled;
- time_running_sum += counter_info.counter.time_running;
- }
+ value_sum += counter_info.counter.value;
+ time_enabled_sum += counter_info.counter.time_enabled;
+ time_running_sum += counter_info.counter.time_running;
}
double scale = 1.0;
if (time_running_sum < time_enabled_sum && time_running_sum != 0) {
diff --git a/simpleperf/event_selection_set.cpp b/simpleperf/event_selection_set.cpp
index d6961e5a..49ccb10d 100644
--- a/simpleperf/event_selection_set.cpp
+++ b/simpleperf/event_selection_set.cpp
@@ -17,7 +17,6 @@
#include "event_selection_set.h"
#include <android-base/logging.h>
-#include <android-base/stringprintf.h>
#include "environment.h"
#include "event_attr.h"
@@ -283,50 +282,68 @@ bool EventSelectionSet::OpenEventFilesForThreadsOnCpus(
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;
+ // Given a tid and cpu, events on the same group should be all opened
+ // successfully or all failed to open.
+ for (auto& selection : group) {
+ EventFd* group_fd = nullptr;
+ if (selection.selection_id != 0) {
+ group_fd = event_fds[0].get();
+ }
+ std::unique_ptr<EventFd> event_fd =
+ EventFd::OpenEventFile(selection.event_attr, tid, cpu, group_fd);
+ if (event_fd != nullptr) {
+ LOG(VERBOSE) << "OpenEventFile for " << event_fd->Name();
+ event_fds.push_back(std::move(event_fd));
+ } else {
+ if (failed_event_type != nullptr) {
+ *failed_event_type = selection.event_type_modifier.name;
+ return false;
+ }
+ }
+ }
+ for (size_t i = 0; i < group.size(); ++i) {
+ group[i].event_fds.push_back(std::move(event_fds[i]));
+ }
+ return true;
+}
+
bool EventSelectionSet::OpenEventFiles(const std::vector<pid_t>& threads,
const std::vector<int>& cpus) {
for (auto& group : groups_) {
for (const auto& tid : threads) {
- size_t open_per_thread = 0;
+ size_t success_cpu_count = 0;
std::string failed_event_type;
for (const auto& cpu : cpus) {
- std::vector<std::unique_ptr<EventFd>> event_fds;
- // Given a tid and cpu, events on the same group should be all opened
- // successfully or all failed to open.
- for (auto& selection : group) {
- EventFd* group_fd = nullptr;
- if (selection.selection_id != 0) {
- group_fd = event_fds[0].get();
- }
- std::unique_ptr<EventFd> event_fd =
- EventFd::OpenEventFile(selection.event_attr, tid, cpu, group_fd);
- if (event_fd != nullptr) {
- LOG(VERBOSE) << "OpenEventFile for " << event_fd->Name();
- event_fds.push_back(std::move(event_fd));
- } else {
- failed_event_type = selection.event_type_modifier.name;
- break;
- }
- }
- if (event_fds.size() == group.size()) {
- for (size_t i = 0; i < group.size(); ++i) {
- group[i].event_fds.push_back(std::move(event_fds[i]));
- }
- ++open_per_thread;
+ if (OpenEventFile(group, tid, cpu, &failed_event_type)) {
+ success_cpu_count++;
}
}
// 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) {
+ if (success_cpu_count == 0) {
PLOG(ERROR) << "failed to open perf event file for event_type "
<< failed_event_type << " for "
- << (tid == -1 ? "all threads" : android::base::StringPrintf(
- " thread %d", tid));
+ << (tid == -1 ? "all threads"
+ : "thread " + std::to_string(tid))
+ << " on all cpus";
return false;
}
}
}
+ threads_.insert(threads_.end(), threads.begin(), threads.end());
+ return true;
+}
+
+static bool ReadCounter(const EventFd* event_fd, CounterInfo* counter) {
+ if (!event_fd->ReadCounter(&counter->counter)) {
+ return false;
+ }
+ counter->tid = event_fd->ThreadId();
+ counter->cpu = event_fd->Cpu();
return true;
}
@@ -336,14 +353,13 @@ bool EventSelectionSet::ReadCounters(std::vector<CountersInfo>* counters) {
for (auto& selection : group) {
CountersInfo counters_info;
counters_info.selection = &selection;
+ counters_info.counters = selection.hotplugged_counters;
for (auto& event_fd : selection.event_fds) {
- CountersInfo::CounterInfo counter_info;
- if (!event_fd->ReadCounter(&counter_info.counter)) {
+ CounterInfo counter;
+ if (!ReadCounter(event_fd.get(), &counter)) {
return false;
}
- counter_info.tid = event_fd->ThreadId();
- counter_info.cpu = event_fd->Cpu();
- counters_info.counters.push_back(counter_info);
+ counters_info.counters.push_back(counter);
}
counters->push_back(counters_info);
}
@@ -471,6 +487,9 @@ bool EventSelectionSet::DetectCpuHotplugEvents() {
if (monitored_cpus_.empty() ||
monitored_cpus_.find(cpu) != monitored_cpus_.end()) {
LOG(INFO) << "Cpu " << cpu << " is offlined";
+ if (!HandleCpuOfflineEvent(cpu)) {
+ return false;
+ }
}
}
}
@@ -480,9 +499,54 @@ bool EventSelectionSet::DetectCpuHotplugEvents() {
if (monitored_cpus_.empty() ||
monitored_cpus_.find(cpu) != monitored_cpus_.end()) {
LOG(INFO) << "Cpu " << cpu << " is onlined";
+ if (!HandleCpuOnlineEvent(cpu)) {
+ return false;
+ }
}
}
}
online_cpus_ = new_cpus;
return true;
}
+
+bool EventSelectionSet::HandleCpuOfflineEvent(int cpu) {
+ if (for_stat_cmd_) {
+ for (auto& group : groups_) {
+ for (auto& selection : group) {
+ for (auto it = selection.event_fds.begin();
+ it != selection.event_fds.end();) {
+ if ((*it)->Cpu() == cpu) {
+ CounterInfo counter;
+ if (!ReadCounter(it->get(), &counter)) {
+ return false;
+ }
+ selection.hotplugged_counters.push_back(counter);
+ it = selection.event_fds.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ }
+ }
+ }
+ return true;
+}
+
+bool EventSelectionSet::HandleCpuOnlineEvent(int cpu) {
+ if (for_stat_cmd_) {
+ for (auto& group : groups_) {
+ 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.
+ PLOG(WARNING) << "failed to open perf event file for event_type "
+ << failed_event_type << " for "
+ << (tid == -1 ? "all threads"
+ : "thread " + std::to_string(tid))
+ << " on cpu " << cpu;
+ }
+ }
+ }
+ }
+ return true;
+}
diff --git a/simpleperf/event_selection_set.h b/simpleperf/event_selection_set.h
index 6fb02b81..12ed510a 100644
--- a/simpleperf/event_selection_set.h
+++ b/simpleperf/event_selection_set.h
@@ -32,24 +32,30 @@
constexpr double DEFAULT_PERIOD_TO_DETECT_CPU_HOTPLUG_EVENTS_IN_SEC = 0.5;
+struct CounterInfo {
+ pid_t tid;
+ int cpu;
+ PerfCounter counter;
+};
+
+struct EventSelection;
+
+struct CountersInfo {
+ const EventSelection* selection;
+ std::vector<CounterInfo> counters;
+};
+
struct EventSelection {
uint32_t group_id;
uint32_t selection_id;
EventTypeAndModifier event_type_modifier;
perf_event_attr event_attr;
std::vector<std::unique_ptr<EventFd>> event_fds;
+ // counters for event files closed for cpu hotplug events
+ std::vector<CounterInfo> hotplugged_counters;
};
-typedef std::vector<EventSelection> EventSelectionGroup;
-struct CountersInfo {
- const EventSelection* selection;
- struct CounterInfo {
- pid_t tid;
- int cpu;
- PerfCounter counter;
- };
- std::vector<CounterInfo> counters;
-};
+typedef std::vector<EventSelection> EventSelectionGroup;
class IOEventLoop;
@@ -115,10 +121,13 @@ class EventSelectionSet {
bool ReadMmapEventDataForFd(std::unique_ptr<EventFd>& event_fd);
bool DetectCpuHotplugEvents();
+ bool HandleCpuOnlineEvent(int cpu);
+ bool HandleCpuOfflineEvent(int cpu);
const bool for_stat_cmd_;
std::vector<EventSelectionGroup> groups_;
+ std::vector<pid_t> threads_;
std::function<bool(Record*)> record_callback_;