summaryrefslogtreecommitdiff
path: root/simpleperf/event_selection_set.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'simpleperf/event_selection_set.cpp')
-rw-r--r--simpleperf/event_selection_set.cpp208
1 files changed, 208 insertions, 0 deletions
diff --git a/simpleperf/event_selection_set.cpp b/simpleperf/event_selection_set.cpp
new file mode 100644
index 00000000..61f17050
--- /dev/null
+++ b/simpleperf/event_selection_set.cpp
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "event_selection_set.h"
+
+#include <base/logging.h>
+
+#include "environment.h"
+#include "event_attr.h"
+#include "event_type.h"
+
+void EventSelectionSet::AddEventType(const EventType& event_type) {
+ EventSelection selection;
+ selection.event_type = &event_type;
+ selection.event_attr = CreateDefaultPerfEventAttr(event_type);
+ selections_.push_back(std::move(selection));
+}
+
+void EventSelectionSet::EnableOnExec() {
+ for (auto& selection : selections_) {
+ selection.event_attr.enable_on_exec = 1;
+ }
+}
+
+void EventSelectionSet::SampleIdAll() {
+ for (auto& selection : selections_) {
+ selection.event_attr.sample_id_all = 1;
+ }
+}
+
+void EventSelectionSet::SetSampleFreq(uint64_t sample_freq) {
+ for (auto& selection : selections_) {
+ perf_event_attr& attr = selection.event_attr;
+ attr.freq = 1;
+ attr.sample_freq = sample_freq;
+ }
+}
+
+void EventSelectionSet::SetSamplePeriod(uint64_t sample_period) {
+ for (auto& selection : selections_) {
+ perf_event_attr& attr = selection.event_attr;
+ attr.freq = 0;
+ attr.sample_period = sample_period;
+ }
+}
+
+bool EventSelectionSet::OpenEventFilesForAllCpus() {
+ std::vector<int> cpus = GetOnlineCpus();
+ if (cpus.empty()) {
+ return false;
+ }
+ for (auto& selection : selections_) {
+ for (auto& cpu : cpus) {
+ auto event_fd = EventFd::OpenEventFileForCpu(selection.event_attr, 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()) {
+ LOG(ERROR) << "failed to open perf event file for event_type " << selection.event_type->name
+ << " on all cpus";
+ return false;
+ }
+ }
+ return true;
+}
+
+bool EventSelectionSet::OpenEventFilesForProcess(pid_t pid) {
+ for (auto& selection : selections_) {
+ auto event_fd = EventFd::OpenEventFileForProcess(selection.event_attr, pid);
+ if (event_fd == nullptr) {
+ PLOG(ERROR) << "failed to open perf event file for event type " << selection.event_type->name
+ << " on pid " << pid;
+ return false;
+ }
+ selection.event_fds.push_back(std::move(event_fd));
+ }
+ return true;
+}
+
+bool EventSelectionSet::EnableEvents() {
+ for (auto& selection : selections_) {
+ for (auto& event_fd : selection.event_fds) {
+ if (!event_fd->EnableEvent()) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool EventSelectionSet::ReadCounters(
+ std::map<const EventType*, std::vector<PerfCounter>>* counters_map) {
+ for (auto& selection : selections_) {
+ std::vector<PerfCounter> counters;
+ for (auto& event_fd : selection.event_fds) {
+ PerfCounter counter;
+ if (!event_fd->ReadCounter(&counter)) {
+ return false;
+ }
+ counters.push_back(counter);
+ }
+ counters_map->insert(std::make_pair(selection.event_type, counters));
+ }
+ return true;
+}
+
+void EventSelectionSet::PreparePollForEventFiles(std::vector<pollfd>* pollfds) {
+ for (auto& selection : selections_) {
+ for (auto& event_fd : selection.event_fds) {
+ pollfd poll_fd;
+ event_fd->PreparePollForMmapData(&poll_fd);
+ pollfds->push_back(poll_fd);
+ }
+ }
+}
+
+bool EventSelectionSet::MmapEventFiles(size_t mmap_pages) {
+ for (auto& selection : selections_) {
+ for (auto& event_fd : selection.event_fds) {
+ if (!event_fd->MmapContent(mmap_pages)) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+static bool ReadMmapEventDataForFd(std::unique_ptr<EventFd>& event_fd,
+ std::function<bool(const char*, size_t)> callback,
+ bool* have_data) {
+ *have_data = false;
+ while (true) {
+ char* data;
+ size_t size = event_fd->GetAvailableMmapData(&data);
+ if (size == 0) {
+ break;
+ }
+ if (!callback(data, size)) {
+ return false;
+ }
+ *have_data = true;
+ event_fd->DiscardMmapData(size);
+ }
+ return true;
+}
+
+bool EventSelectionSet::ReadMmapEventData(std::function<bool(const char*, size_t)> callback) {
+ for (auto& selection : selections_) {
+ for (auto& event_fd : selection.event_fds) {
+ while (true) {
+ bool have_data;
+ if (!ReadMmapEventDataForFd(event_fd, callback, &have_data)) {
+ return false;
+ }
+ if (!have_data) {
+ break;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+std::string EventSelectionSet::FindEventFileNameById(uint64_t id) {
+ for (auto& selection : selections_) {
+ for (auto& event_fd : selection.event_fds) {
+ if (event_fd->Id() == id) {
+ return event_fd->Name();
+ }
+ }
+ }
+ return "";
+}
+
+EventSelectionSet::EventSelection* EventSelectionSet::FindSelectionByType(
+ const EventType& event_type) {
+ for (auto& selection : selections_) {
+ if (strcmp(selection.event_type->name, event_type.name) == 0) {
+ return &selection;
+ }
+ }
+ return nullptr;
+}
+
+const perf_event_attr& EventSelectionSet::FindEventAttrByType(const EventType& event_type) {
+ return FindSelectionByType(event_type)->event_attr;
+}
+
+const std::vector<std::unique_ptr<EventFd>>& EventSelectionSet::FindEventFdsByType(
+ const EventType& event_type) {
+ return FindSelectionByType(event_type)->event_fds;
+}