1 /*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "event_selection_set.h"
18
19 #include <base/logging.h>
20
21 #include "environment.h"
22 #include "event_attr.h"
23 #include "event_type.h"
24
AddEventType(const EventType & event_type)25 void EventSelectionSet::AddEventType(const EventType& event_type) {
26 EventSelection selection;
27 selection.event_type = &event_type;
28 selection.event_attr = CreateDefaultPerfEventAttr(event_type);
29 selections_.push_back(std::move(selection));
30 }
31
EnableOnExec()32 void EventSelectionSet::EnableOnExec() {
33 for (auto& selection : selections_) {
34 selection.event_attr.enable_on_exec = 1;
35 }
36 }
37
SampleIdAll()38 void EventSelectionSet::SampleIdAll() {
39 for (auto& selection : selections_) {
40 selection.event_attr.sample_id_all = 1;
41 }
42 }
43
SetSampleFreq(uint64_t sample_freq)44 void EventSelectionSet::SetSampleFreq(uint64_t sample_freq) {
45 for (auto& selection : selections_) {
46 perf_event_attr& attr = selection.event_attr;
47 attr.freq = 1;
48 attr.sample_freq = sample_freq;
49 }
50 }
51
SetSamplePeriod(uint64_t sample_period)52 void EventSelectionSet::SetSamplePeriod(uint64_t sample_period) {
53 for (auto& selection : selections_) {
54 perf_event_attr& attr = selection.event_attr;
55 attr.freq = 0;
56 attr.sample_period = sample_period;
57 }
58 }
59
OpenEventFilesForAllCpus()60 bool EventSelectionSet::OpenEventFilesForAllCpus() {
61 std::vector<int> cpus = GetOnlineCpus();
62 if (cpus.empty()) {
63 return false;
64 }
65 for (auto& selection : selections_) {
66 for (auto& cpu : cpus) {
67 auto event_fd = EventFd::OpenEventFileForCpu(selection.event_attr, cpu);
68 if (event_fd != nullptr) {
69 selection.event_fds.push_back(std::move(event_fd));
70 }
71 }
72 // As the online cpus can be enabled or disabled at runtime, we may not open event file for
73 // all cpus successfully. But we should open at least one cpu successfully.
74 if (selection.event_fds.empty()) {
75 LOG(ERROR) << "failed to open perf event file for event_type " << selection.event_type->name
76 << " on all cpus";
77 return false;
78 }
79 }
80 return true;
81 }
82
OpenEventFilesForProcess(pid_t pid)83 bool EventSelectionSet::OpenEventFilesForProcess(pid_t pid) {
84 for (auto& selection : selections_) {
85 auto event_fd = EventFd::OpenEventFileForProcess(selection.event_attr, pid);
86 if (event_fd == nullptr) {
87 PLOG(ERROR) << "failed to open perf event file for event type " << selection.event_type->name
88 << " on pid " << pid;
89 return false;
90 }
91 selection.event_fds.push_back(std::move(event_fd));
92 }
93 return true;
94 }
95
EnableEvents()96 bool EventSelectionSet::EnableEvents() {
97 for (auto& selection : selections_) {
98 for (auto& event_fd : selection.event_fds) {
99 if (!event_fd->EnableEvent()) {
100 return false;
101 }
102 }
103 }
104 return true;
105 }
106
ReadCounters(std::map<const EventType *,std::vector<PerfCounter>> * counters_map)107 bool EventSelectionSet::ReadCounters(
108 std::map<const EventType*, std::vector<PerfCounter>>* counters_map) {
109 for (auto& selection : selections_) {
110 std::vector<PerfCounter> counters;
111 for (auto& event_fd : selection.event_fds) {
112 PerfCounter counter;
113 if (!event_fd->ReadCounter(&counter)) {
114 return false;
115 }
116 counters.push_back(counter);
117 }
118 counters_map->insert(std::make_pair(selection.event_type, counters));
119 }
120 return true;
121 }
122
PreparePollForEventFiles(std::vector<pollfd> * pollfds)123 void EventSelectionSet::PreparePollForEventFiles(std::vector<pollfd>* pollfds) {
124 for (auto& selection : selections_) {
125 for (auto& event_fd : selection.event_fds) {
126 pollfd poll_fd;
127 event_fd->PreparePollForMmapData(&poll_fd);
128 pollfds->push_back(poll_fd);
129 }
130 }
131 }
132
MmapEventFiles(size_t mmap_pages)133 bool EventSelectionSet::MmapEventFiles(size_t mmap_pages) {
134 for (auto& selection : selections_) {
135 for (auto& event_fd : selection.event_fds) {
136 if (!event_fd->MmapContent(mmap_pages)) {
137 return false;
138 }
139 }
140 }
141 return true;
142 }
143
ReadMmapEventDataForFd(std::unique_ptr<EventFd> & event_fd,std::function<bool (const char *,size_t)> callback,bool * have_data)144 static bool ReadMmapEventDataForFd(std::unique_ptr<EventFd>& event_fd,
145 std::function<bool(const char*, size_t)> callback,
146 bool* have_data) {
147 *have_data = false;
148 while (true) {
149 char* data;
150 size_t size = event_fd->GetAvailableMmapData(&data);
151 if (size == 0) {
152 break;
153 }
154 if (!callback(data, size)) {
155 return false;
156 }
157 *have_data = true;
158 event_fd->DiscardMmapData(size);
159 }
160 return true;
161 }
162
ReadMmapEventData(std::function<bool (const char *,size_t)> callback)163 bool EventSelectionSet::ReadMmapEventData(std::function<bool(const char*, size_t)> callback) {
164 for (auto& selection : selections_) {
165 for (auto& event_fd : selection.event_fds) {
166 while (true) {
167 bool have_data;
168 if (!ReadMmapEventDataForFd(event_fd, callback, &have_data)) {
169 return false;
170 }
171 if (!have_data) {
172 break;
173 }
174 }
175 }
176 }
177 return true;
178 }
179
FindEventFileNameById(uint64_t id)180 std::string EventSelectionSet::FindEventFileNameById(uint64_t id) {
181 for (auto& selection : selections_) {
182 for (auto& event_fd : selection.event_fds) {
183 if (event_fd->Id() == id) {
184 return event_fd->Name();
185 }
186 }
187 }
188 return "";
189 }
190
FindSelectionByType(const EventType & event_type)191 EventSelectionSet::EventSelection* EventSelectionSet::FindSelectionByType(
192 const EventType& event_type) {
193 for (auto& selection : selections_) {
194 if (strcmp(selection.event_type->name, event_type.name) == 0) {
195 return &selection;
196 }
197 }
198 return nullptr;
199 }
200
FindEventAttrByType(const EventType & event_type)201 const perf_event_attr& EventSelectionSet::FindEventAttrByType(const EventType& event_type) {
202 return FindSelectionByType(event_type)->event_attr;
203 }
204
FindEventFdsByType(const EventType & event_type)205 const std::vector<std::unique_ptr<EventFd>>& EventSelectionSet::FindEventFdsByType(
206 const EventType& event_type) {
207 return FindSelectionByType(event_type)->event_fds;
208 }
209