• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <poll.h>
20 
21 #include <android-base/logging.h>
22 #include <android-base/stringprintf.h>
23 
24 #include "environment.h"
25 #include "event_attr.h"
26 #include "event_type.h"
27 #include "perf_regs.h"
28 
IsBranchSamplingSupported()29 bool IsBranchSamplingSupported() {
30   const EventType* type = FindEventTypeByName("cpu-cycles");
31   if (type == nullptr) {
32     return false;
33   }
34   perf_event_attr attr = CreateDefaultPerfEventAttr(*type);
35   attr.sample_type |= PERF_SAMPLE_BRANCH_STACK;
36   attr.branch_sample_type = PERF_SAMPLE_BRANCH_ANY;
37   return IsEventAttrSupportedByKernel(attr);
38 }
39 
IsDwarfCallChainSamplingSupported()40 bool IsDwarfCallChainSamplingSupported() {
41   const EventType* type = FindEventTypeByName("cpu-cycles");
42   if (type == nullptr) {
43     return false;
44   }
45   perf_event_attr attr = CreateDefaultPerfEventAttr(*type);
46   attr.sample_type |= PERF_SAMPLE_CALLCHAIN | PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER;
47   attr.exclude_callchain_user = 1;
48   attr.sample_regs_user = GetSupportedRegMask(GetBuildArch());
49   attr.sample_stack_user = 8192;
50   return IsEventAttrSupportedByKernel(attr);
51 }
52 
AddEventType(const EventTypeAndModifier & event_type_modifier)53 bool EventSelectionSet::AddEventType(const EventTypeAndModifier& event_type_modifier) {
54   EventSelection selection;
55   selection.event_type_modifier = event_type_modifier;
56   selection.event_attr = CreateDefaultPerfEventAttr(event_type_modifier.event_type);
57   selection.event_attr.exclude_user = event_type_modifier.exclude_user;
58   selection.event_attr.exclude_kernel = event_type_modifier.exclude_kernel;
59   selection.event_attr.exclude_hv = event_type_modifier.exclude_hv;
60   selection.event_attr.exclude_host = event_type_modifier.exclude_host;
61   selection.event_attr.exclude_guest = event_type_modifier.exclude_guest;
62   selection.event_attr.precise_ip = event_type_modifier.precise_ip;
63   if (!IsEventAttrSupportedByKernel(selection.event_attr)) {
64     LOG(ERROR) << "Event type '" << event_type_modifier.name << "' is not supported by the kernel";
65     return false;
66   }
67   selections_.push_back(std::move(selection));
68   UnionSampleType();
69   return true;
70 }
71 
72 // Union the sample type of different event attrs can make reading sample records in perf.data
73 // easier.
UnionSampleType()74 void EventSelectionSet::UnionSampleType() {
75   uint64_t sample_type = 0;
76   for (auto& selection : selections_) {
77     sample_type |= selection.event_attr.sample_type;
78   }
79   for (auto& selection : selections_) {
80     selection.event_attr.sample_type = sample_type;
81   }
82 }
83 
SetEnableOnExec(bool enable)84 void EventSelectionSet::SetEnableOnExec(bool enable) {
85   for (auto& selection : selections_) {
86     // If sampling is enabled on exec, then it is disabled at startup, otherwise
87     // it should be enabled at startup. Don't use ioctl(PERF_EVENT_IOC_ENABLE)
88     // to enable it after perf_event_open(). Because some android kernels can't
89     // handle ioctl() well when cpu-hotplug happens. See http://b/25193162.
90     if (enable) {
91       selection.event_attr.enable_on_exec = 1;
92       selection.event_attr.disabled = 1;
93     } else {
94       selection.event_attr.enable_on_exec = 0;
95       selection.event_attr.disabled = 0;
96     }
97   }
98 }
99 
GetEnableOnExec()100 bool EventSelectionSet::GetEnableOnExec() {
101   for (auto& selection : selections_) {
102     if (selection.event_attr.enable_on_exec == 0) {
103       return false;
104     }
105   }
106   return true;
107 }
108 
SampleIdAll()109 void EventSelectionSet::SampleIdAll() {
110   for (auto& selection : selections_) {
111     selection.event_attr.sample_id_all = 1;
112   }
113 }
114 
SetSampleFreq(uint64_t sample_freq)115 void EventSelectionSet::SetSampleFreq(uint64_t sample_freq) {
116   for (auto& selection : selections_) {
117     perf_event_attr& attr = selection.event_attr;
118     attr.freq = 1;
119     attr.sample_freq = sample_freq;
120   }
121 }
122 
SetSamplePeriod(uint64_t sample_period)123 void EventSelectionSet::SetSamplePeriod(uint64_t sample_period) {
124   for (auto& selection : selections_) {
125     perf_event_attr& attr = selection.event_attr;
126     attr.freq = 0;
127     attr.sample_period = sample_period;
128   }
129 }
130 
SetBranchSampling(uint64_t branch_sample_type)131 bool EventSelectionSet::SetBranchSampling(uint64_t branch_sample_type) {
132   if (branch_sample_type != 0 &&
133       (branch_sample_type & (PERF_SAMPLE_BRANCH_ANY | PERF_SAMPLE_BRANCH_ANY_CALL |
134                              PERF_SAMPLE_BRANCH_ANY_RETURN | PERF_SAMPLE_BRANCH_IND_CALL)) == 0) {
135     LOG(ERROR) << "Invalid branch_sample_type: 0x" << std::hex << branch_sample_type;
136     return false;
137   }
138   if (branch_sample_type != 0 && !IsBranchSamplingSupported()) {
139     LOG(ERROR) << "branch stack sampling is not supported on this device.";
140     return false;
141   }
142   for (auto& selection : selections_) {
143     perf_event_attr& attr = selection.event_attr;
144     if (branch_sample_type != 0) {
145       attr.sample_type |= PERF_SAMPLE_BRANCH_STACK;
146     } else {
147       attr.sample_type &= ~PERF_SAMPLE_BRANCH_STACK;
148     }
149     attr.branch_sample_type = branch_sample_type;
150   }
151   return true;
152 }
153 
EnableFpCallChainSampling()154 void EventSelectionSet::EnableFpCallChainSampling() {
155   for (auto& selection : selections_) {
156     selection.event_attr.sample_type |= PERF_SAMPLE_CALLCHAIN;
157   }
158 }
159 
EnableDwarfCallChainSampling(uint32_t dump_stack_size)160 bool EventSelectionSet::EnableDwarfCallChainSampling(uint32_t dump_stack_size) {
161   if (!IsDwarfCallChainSamplingSupported()) {
162     LOG(ERROR) << "dwarf callchain sampling is not supported on this device.";
163     return false;
164   }
165   for (auto& selection : selections_) {
166     selection.event_attr.sample_type |=
167         PERF_SAMPLE_CALLCHAIN | PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER;
168     selection.event_attr.exclude_callchain_user = 1;
169     selection.event_attr.sample_regs_user = GetSupportedRegMask(GetBuildArch());
170     selection.event_attr.sample_stack_user = dump_stack_size;
171   }
172   return true;
173 }
174 
SetInherit(bool enable)175 void EventSelectionSet::SetInherit(bool enable) {
176   for (auto& selection : selections_) {
177     selection.event_attr.inherit = (enable ? 1 : 0);
178   }
179 }
180 
CheckIfCpusOnline(const std::vector<int> & cpus)181 static bool CheckIfCpusOnline(const std::vector<int>& cpus) {
182   std::vector<int> online_cpus = GetOnlineCpus();
183   for (const auto& cpu : cpus) {
184     if (std::find(online_cpus.begin(), online_cpus.end(), cpu) == online_cpus.end()) {
185       LOG(ERROR) << "cpu " << cpu << " is not online.";
186       return false;
187     }
188   }
189   return true;
190 }
191 
OpenEventFilesForCpus(const std::vector<int> & cpus)192 bool EventSelectionSet::OpenEventFilesForCpus(const std::vector<int>& cpus) {
193   return OpenEventFilesForThreadsOnCpus({-1}, cpus);
194 }
195 
OpenEventFilesForThreadsOnCpus(const std::vector<pid_t> & threads,std::vector<int> cpus)196 bool EventSelectionSet::OpenEventFilesForThreadsOnCpus(const std::vector<pid_t>& threads,
197                                                        std::vector<int> cpus) {
198   if (!cpus.empty()) {
199     if (!CheckIfCpusOnline(cpus)) {
200       return false;
201     }
202   } else {
203     cpus = GetOnlineCpus();
204   }
205   return OpenEventFiles(threads, cpus);
206 }
207 
OpenEventFiles(const std::vector<pid_t> & threads,const std::vector<int> & cpus)208 bool EventSelectionSet::OpenEventFiles(const std::vector<pid_t>& threads,
209                                        const std::vector<int>& cpus) {
210   for (auto& selection : selections_) {
211     for (auto& tid : threads) {
212       size_t open_per_thread = 0;
213       for (auto& cpu : cpus) {
214         auto event_fd = EventFd::OpenEventFile(selection.event_attr, tid, cpu);
215         if (event_fd != nullptr) {
216           LOG(VERBOSE) << "OpenEventFile for tid " << tid << ", cpu " << cpu;
217           selection.event_fds.push_back(std::move(event_fd));
218           ++open_per_thread;
219         }
220       }
221       // As the online cpus can be enabled or disabled at runtime, we may not open event file for
222       // all cpus successfully. But we should open at least one cpu successfully.
223       if (open_per_thread == 0) {
224         PLOG(ERROR) << "failed to open perf event file for event_type "
225                     << selection.event_type_modifier.name << " for "
226                     << (tid == -1 ? "all threads" : android::base::StringPrintf(" thread %d", tid));
227         return false;
228       }
229     }
230   }
231   return true;
232 }
233 
ReadCounters(std::vector<CountersInfo> * counters)234 bool EventSelectionSet::ReadCounters(std::vector<CountersInfo>* counters) {
235   counters->clear();
236   for (auto& selection : selections_) {
237     CountersInfo counters_info;
238     counters_info.event_type = &selection.event_type_modifier;
239     for (auto& event_fd : selection.event_fds) {
240       CountersInfo::CounterInfo counter_info;
241       if (!event_fd->ReadCounter(&counter_info.counter)) {
242         return false;
243       }
244       counter_info.tid = event_fd->ThreadId();
245       counter_info.cpu = event_fd->Cpu();
246       counters_info.counters.push_back(counter_info);
247     }
248     counters->push_back(counters_info);
249   }
250   return true;
251 }
252 
PreparePollForEventFiles(std::vector<pollfd> * pollfds)253 void EventSelectionSet::PreparePollForEventFiles(std::vector<pollfd>* pollfds) {
254   for (auto& selection : selections_) {
255     for (auto& event_fd : selection.event_fds) {
256       pollfd poll_fd;
257       event_fd->PreparePollForMmapData(&poll_fd);
258       pollfds->push_back(poll_fd);
259     }
260   }
261 }
262 
MmapEventFiles(size_t mmap_pages)263 bool EventSelectionSet::MmapEventFiles(size_t mmap_pages) {
264   for (auto& selection : selections_) {
265     for (auto& event_fd : selection.event_fds) {
266       if (!event_fd->MmapContent(mmap_pages)) {
267         return false;
268       }
269     }
270   }
271   return true;
272 }
273 
ReadMmapEventDataForFd(std::unique_ptr<EventFd> & event_fd,std::function<bool (const char *,size_t)> callback,bool * have_data)274 static bool ReadMmapEventDataForFd(std::unique_ptr<EventFd>& event_fd,
275                                    std::function<bool(const char*, size_t)> callback,
276                                    bool* have_data) {
277   *have_data = false;
278   while (true) {
279     char* data;
280     size_t size = event_fd->GetAvailableMmapData(&data);
281     if (size == 0) {
282       break;
283     }
284     if (!callback(data, size)) {
285       return false;
286     }
287     *have_data = true;
288   }
289   return true;
290 }
291 
ReadMmapEventData(std::function<bool (const char *,size_t)> callback)292 bool EventSelectionSet::ReadMmapEventData(std::function<bool(const char*, size_t)> callback) {
293   for (auto& selection : selections_) {
294     for (auto& event_fd : selection.event_fds) {
295       while (true) {
296         bool have_data;
297         if (!ReadMmapEventDataForFd(event_fd, callback, &have_data)) {
298           return false;
299         }
300         if (!have_data) {
301           break;
302         }
303       }
304     }
305   }
306   return true;
307 }
308 
FindSelectionByType(const EventTypeAndModifier & event_type_modifier)309 EventSelectionSet::EventSelection* EventSelectionSet::FindSelectionByType(
310     const EventTypeAndModifier& event_type_modifier) {
311   for (auto& selection : selections_) {
312     if (selection.event_type_modifier.name == event_type_modifier.name) {
313       return &selection;
314     }
315   }
316   return nullptr;
317 }
318 
FindEventAttrByType(const EventTypeAndModifier & event_type_modifier)319 const perf_event_attr* EventSelectionSet::FindEventAttrByType(
320     const EventTypeAndModifier& event_type_modifier) {
321   EventSelection* selection = FindSelectionByType(event_type_modifier);
322   return (selection != nullptr) ? &selection->event_attr : nullptr;
323 }
324 
FindEventFdsByType(const EventTypeAndModifier & event_type_modifier)325 const std::vector<std::unique_ptr<EventFd>>* EventSelectionSet::FindEventFdsByType(
326     const EventTypeAndModifier& event_type_modifier) {
327   EventSelection* selection = FindSelectionByType(event_type_modifier);
328   return (selection != nullptr) ? &selection->event_fds : nullptr;
329 }
330