OSDN Git Service

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