OSDN Git Service

Merge "Revert "Crypto performance benchmark"" into nyc-dev
[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 <android-base/logging.h>
20 #include <android-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     // If sampling is enabled on exec, then it is disabled at startup, otherwise
85     // it should be enabled at startup. Don't use ioctl(PERF_EVENT_IOC_ENABLE)
86     // to enable it after perf_event_open(). Because some android kernels can't
87     // handle ioctl() well when cpu-hotplug happens. See http://b/25193162.
88     if (enable) {
89       selection.event_attr.enable_on_exec = 1;
90       selection.event_attr.disabled = 1;
91     } else {
92       selection.event_attr.enable_on_exec = 0;
93       selection.event_attr.disabled = 0;
94     }
95   }
96 }
97
98 bool EventSelectionSet::GetEnableOnExec() {
99   for (auto& selection : selections_) {
100     if (selection.event_attr.enable_on_exec == 0) {
101       return false;
102     }
103   }
104   return true;
105 }
106
107 void EventSelectionSet::SampleIdAll() {
108   for (auto& selection : selections_) {
109     selection.event_attr.sample_id_all = 1;
110   }
111 }
112
113 void EventSelectionSet::SetSampleFreq(uint64_t sample_freq) {
114   for (auto& selection : selections_) {
115     perf_event_attr& attr = selection.event_attr;
116     attr.freq = 1;
117     attr.sample_freq = sample_freq;
118   }
119 }
120
121 void EventSelectionSet::SetSamplePeriod(uint64_t sample_period) {
122   for (auto& selection : selections_) {
123     perf_event_attr& attr = selection.event_attr;
124     attr.freq = 0;
125     attr.sample_period = sample_period;
126   }
127 }
128
129 bool EventSelectionSet::SetBranchSampling(uint64_t branch_sample_type) {
130   if (branch_sample_type != 0 &&
131       (branch_sample_type & (PERF_SAMPLE_BRANCH_ANY | PERF_SAMPLE_BRANCH_ANY_CALL |
132                              PERF_SAMPLE_BRANCH_ANY_RETURN | PERF_SAMPLE_BRANCH_IND_CALL)) == 0) {
133     LOG(ERROR) << "Invalid branch_sample_type: 0x" << std::hex << branch_sample_type;
134     return false;
135   }
136   if (branch_sample_type != 0 && !IsBranchSamplingSupported()) {
137     LOG(ERROR) << "branch stack sampling is not supported on this device.";
138     return false;
139   }
140   for (auto& selection : selections_) {
141     perf_event_attr& attr = selection.event_attr;
142     if (branch_sample_type != 0) {
143       attr.sample_type |= PERF_SAMPLE_BRANCH_STACK;
144     } else {
145       attr.sample_type &= ~PERF_SAMPLE_BRANCH_STACK;
146     }
147     attr.branch_sample_type = branch_sample_type;
148   }
149   return true;
150 }
151
152 void EventSelectionSet::EnableFpCallChainSampling() {
153   for (auto& selection : selections_) {
154     selection.event_attr.sample_type |= PERF_SAMPLE_CALLCHAIN;
155   }
156 }
157
158 bool EventSelectionSet::EnableDwarfCallChainSampling(uint32_t dump_stack_size) {
159   if (!IsDwarfCallChainSamplingSupported()) {
160     LOG(ERROR) << "dwarf callchain sampling is not supported on this device.";
161     return false;
162   }
163   for (auto& selection : selections_) {
164     selection.event_attr.sample_type |=
165         PERF_SAMPLE_CALLCHAIN | PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER;
166     selection.event_attr.exclude_callchain_user = 1;
167     selection.event_attr.sample_regs_user = GetSupportedRegMask();
168     selection.event_attr.sample_stack_user = dump_stack_size;
169   }
170   return true;
171 }
172
173 void EventSelectionSet::SetInherit(bool enable) {
174   for (auto& selection : selections_) {
175     selection.event_attr.inherit = (enable ? 1 : 0);
176   }
177 }
178
179 static bool CheckIfCpusOnline(const std::vector<int>& cpus) {
180   std::vector<int> online_cpus = GetOnlineCpus();
181   for (const auto& cpu : cpus) {
182     if (std::find(online_cpus.begin(), online_cpus.end(), cpu) == online_cpus.end()) {
183       LOG(ERROR) << "cpu " << cpu << " is not online.";
184       return false;
185     }
186   }
187   return true;
188 }
189
190 bool EventSelectionSet::OpenEventFilesForCpus(const std::vector<int>& cpus) {
191   return OpenEventFilesForThreadsOnCpus({-1}, cpus);
192 }
193
194 bool EventSelectionSet::OpenEventFilesForThreadsOnCpus(const std::vector<pid_t>& threads,
195                                                        std::vector<int> cpus) {
196   if (!cpus.empty()) {
197     if (!CheckIfCpusOnline(cpus)) {
198       return false;
199     }
200   } else {
201     cpus = GetOnlineCpus();
202   }
203   return OpenEventFiles(threads, cpus);
204 }
205
206 bool EventSelectionSet::OpenEventFiles(const std::vector<pid_t>& threads,
207                                        const std::vector<int>& cpus) {
208   for (auto& selection : selections_) {
209     for (auto& tid : threads) {
210       size_t open_per_thread = 0;
211       for (auto& cpu : cpus) {
212         auto event_fd = EventFd::OpenEventFile(selection.event_attr, tid, cpu);
213         if (event_fd != nullptr) {
214           LOG(VERBOSE) << "OpenEventFile for tid " << tid << ", cpu " << cpu;
215           selection.event_fds.push_back(std::move(event_fd));
216           ++open_per_thread;
217         }
218       }
219       // As the online cpus can be enabled or disabled at runtime, we may not open event file for
220       // all cpus successfully. But we should open at least one cpu successfully.
221       if (open_per_thread == 0) {
222         PLOG(ERROR) << "failed to open perf event file for event_type "
223                     << selection.event_type_modifier.name << " for "
224                     << (tid == -1 ? "all threads" : android::base::StringPrintf(" thread %d", tid));
225         return false;
226       }
227     }
228   }
229   return true;
230 }
231
232 bool EventSelectionSet::ReadCounters(std::vector<CountersInfo>* counters) {
233   counters->clear();
234   for (auto& selection : selections_) {
235     CountersInfo counters_info;
236     counters_info.event_type = &selection.event_type_modifier;
237     for (auto& event_fd : selection.event_fds) {
238       CountersInfo::CounterInfo counter_info;
239       if (!event_fd->ReadCounter(&counter_info.counter)) {
240         return false;
241       }
242       counter_info.tid = event_fd->ThreadId();
243       counter_info.cpu = event_fd->Cpu();
244       counters_info.counters.push_back(counter_info);
245     }
246     counters->push_back(counters_info);
247   }
248   return true;
249 }
250
251 void EventSelectionSet::PreparePollForEventFiles(std::vector<pollfd>* pollfds) {
252   for (auto& selection : selections_) {
253     for (auto& event_fd : selection.event_fds) {
254       pollfd poll_fd;
255       event_fd->PreparePollForMmapData(&poll_fd);
256       pollfds->push_back(poll_fd);
257     }
258   }
259 }
260
261 bool EventSelectionSet::MmapEventFiles(size_t mmap_pages) {
262   for (auto& selection : selections_) {
263     for (auto& event_fd : selection.event_fds) {
264       if (!event_fd->MmapContent(mmap_pages)) {
265         return false;
266       }
267     }
268   }
269   return true;
270 }
271
272 static bool ReadMmapEventDataForFd(std::unique_ptr<EventFd>& event_fd,
273                                    std::function<bool(const char*, size_t)> callback,
274                                    bool* have_data) {
275   *have_data = false;
276   while (true) {
277     char* data;
278     size_t size = event_fd->GetAvailableMmapData(&data);
279     if (size == 0) {
280       break;
281     }
282     if (!callback(data, size)) {
283       return false;
284     }
285     *have_data = true;
286   }
287   return true;
288 }
289
290 bool EventSelectionSet::ReadMmapEventData(std::function<bool(const char*, size_t)> callback) {
291   for (auto& selection : selections_) {
292     for (auto& event_fd : selection.event_fds) {
293       while (true) {
294         bool have_data;
295         if (!ReadMmapEventDataForFd(event_fd, callback, &have_data)) {
296           return false;
297         }
298         if (!have_data) {
299           break;
300         }
301       }
302     }
303   }
304   return true;
305 }
306
307 EventSelectionSet::EventSelection* EventSelectionSet::FindSelectionByType(
308     const EventTypeAndModifier& event_type_modifier) {
309   for (auto& selection : selections_) {
310     if (selection.event_type_modifier.name == event_type_modifier.name) {
311       return &selection;
312     }
313   }
314   return nullptr;
315 }
316
317 const perf_event_attr* EventSelectionSet::FindEventAttrByType(
318     const EventTypeAndModifier& event_type_modifier) {
319   EventSelection* selection = FindSelectionByType(event_type_modifier);
320   return (selection != nullptr) ? &selection->event_attr : nullptr;
321 }
322
323 const std::vector<std::unique_ptr<EventFd>>* EventSelectionSet::FindEventFdsByType(
324     const EventTypeAndModifier& event_type_modifier) {
325   EventSelection* selection = FindSelectionByType(event_type_modifier);
326   return (selection != nullptr) ? &selection->event_fds : nullptr;
327 }