event_selection_set.cpp revision 66dd09e8e2407082ce93bf0784de641298131912
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
27bool 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
38bool 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
51bool 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.
72void 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
82void EventSelectionSet::SetEnableOnExec(bool enable) {
83  for (auto& selection : selections_) {
84    selection.event_attr.enable_on_exec = (enable ? 1 : 0);
85  }
86}
87
88bool 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
97void EventSelectionSet::SampleIdAll() {
98  for (auto& selection : selections_) {
99    selection.event_attr.sample_id_all = 1;
100  }
101}
102
103void 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
111void 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
119bool 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
142void EventSelectionSet::EnableFpCallChainSampling() {
143  for (auto& selection : selections_) {
144    selection.event_attr.sample_type |= PERF_SAMPLE_CALLCHAIN;
145  }
146}
147
148bool 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
163void EventSelectionSet::SetInherit(bool enable) {
164  for (auto& selection : selections_) {
165    selection.event_attr.inherit = (enable ? 1 : 0);
166  }
167}
168
169static bool CheckIfCpusOnline(const std::vector<int>& cpus) {
170  std::vector<int> online_cpus = GetOnlineCpus();
171  for (const auto& cpu : cpus) {
172    if (std::find(online_cpus.begin(), online_cpus.end(), cpu) == online_cpus.end()) {
173      LOG(ERROR) << "cpu " << cpu << " is not online.";
174      return false;
175    }
176  }
177  return true;
178}
179
180bool EventSelectionSet::OpenEventFilesForCpus(const std::vector<int>& cpus) {
181  return OpenEventFilesForThreadsOnCpus({-1}, cpus);
182}
183
184bool EventSelectionSet::OpenEventFilesForThreadsOnCpus(const std::vector<pid_t>& threads,
185                                                       std::vector<int> cpus) {
186  if (!cpus.empty()) {
187    if (!CheckIfCpusOnline(cpus)) {
188      return false;
189    }
190  } else {
191    cpus = GetOnlineCpus();
192  }
193  return OpenEventFiles(threads, cpus);
194}
195
196bool EventSelectionSet::OpenEventFiles(const std::vector<pid_t>& threads,
197                                       const std::vector<int>& cpus) {
198  for (auto& selection : selections_) {
199    for (auto& tid : threads) {
200      size_t open_per_thread = 0;
201      for (auto& cpu : cpus) {
202        auto event_fd = EventFd::OpenEventFile(selection.event_attr, tid, cpu);
203        if (event_fd != nullptr) {
204          selection.event_fds.push_back(std::move(event_fd));
205          ++open_per_thread;
206        }
207      }
208      // As the online cpus can be enabled or disabled at runtime, we may not open event file for
209      // all cpus successfully. But we should open at least one cpu successfully.
210      if (open_per_thread == 0) {
211        PLOG(ERROR) << "failed to open perf event file for event_type "
212                    << selection.event_type_modifier.name << " for "
213                    << (tid == -1 ? "all threads" : android::base::StringPrintf(" thread %d", tid));
214        return false;
215      }
216    }
217  }
218  return true;
219}
220
221bool EventSelectionSet::EnableEvents() {
222  for (auto& selection : selections_) {
223    for (auto& event_fd : selection.event_fds) {
224      if (!event_fd->EnableEvent()) {
225        return false;
226      }
227    }
228  }
229  return true;
230}
231
232bool 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
251void 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
261bool 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
272static 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
290bool 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
307EventSelectionSet::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
317const 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
323const 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}
328