event_selection_set.cpp revision 76769e502d8f0ebf5d2c81b00246727fb0a59925
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
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 = event_type_modifier.event_type;
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 '" << selection.event_type.name << "' is not supported by the kernel";
63    return false;
64  }
65  selections_.push_back(std::move(selection));
66  return true;
67}
68
69void EventSelectionSet::SetEnableOnExec(bool enable) {
70  for (auto& selection : selections_) {
71    selection.event_attr.enable_on_exec = (enable ? 1 : 0);
72  }
73}
74
75bool EventSelectionSet::GetEnableOnExec() {
76  for (auto& selection : selections_) {
77    if (selection.event_attr.enable_on_exec == 0) {
78      return false;
79    }
80  }
81  return true;
82}
83
84void EventSelectionSet::SampleIdAll() {
85  for (auto& selection : selections_) {
86    selection.event_attr.sample_id_all = 1;
87  }
88}
89
90void EventSelectionSet::SetSampleFreq(uint64_t sample_freq) {
91  for (auto& selection : selections_) {
92    perf_event_attr& attr = selection.event_attr;
93    attr.freq = 1;
94    attr.sample_freq = sample_freq;
95  }
96}
97
98void EventSelectionSet::SetSamplePeriod(uint64_t sample_period) {
99  for (auto& selection : selections_) {
100    perf_event_attr& attr = selection.event_attr;
101    attr.freq = 0;
102    attr.sample_period = sample_period;
103  }
104}
105
106bool EventSelectionSet::SetBranchSampling(uint64_t branch_sample_type) {
107  if (branch_sample_type != 0 &&
108      (branch_sample_type & (PERF_SAMPLE_BRANCH_ANY | PERF_SAMPLE_BRANCH_ANY_CALL |
109                             PERF_SAMPLE_BRANCH_ANY_RETURN | PERF_SAMPLE_BRANCH_IND_CALL)) == 0) {
110    LOG(ERROR) << "Invalid branch_sample_type: 0x" << std::hex << branch_sample_type;
111    return false;
112  }
113  if (branch_sample_type != 0 && !IsBranchSamplingSupported()) {
114    LOG(ERROR) << "branch stack sampling is not supported on this device.";
115    return false;
116  }
117  for (auto& selection : selections_) {
118    perf_event_attr& attr = selection.event_attr;
119    if (branch_sample_type != 0) {
120      attr.sample_type |= PERF_SAMPLE_BRANCH_STACK;
121    } else {
122      attr.sample_type &= ~PERF_SAMPLE_BRANCH_STACK;
123    }
124    attr.branch_sample_type = branch_sample_type;
125  }
126  return true;
127}
128
129void EventSelectionSet::EnableFpCallChainSampling() {
130  for (auto& selection : selections_) {
131    selection.event_attr.sample_type |= PERF_SAMPLE_CALLCHAIN;
132  }
133}
134
135bool EventSelectionSet::EnableDwarfCallChainSampling(uint32_t dump_stack_size) {
136  if (!IsDwarfCallChainSamplingSupported()) {
137    LOG(ERROR) << "dwarf callchain sampling is not supported on this device.";
138    return false;
139  }
140  for (auto& selection : selections_) {
141    selection.event_attr.sample_type |=
142        PERF_SAMPLE_CALLCHAIN | PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER;
143    selection.event_attr.exclude_callchain_user = 1;
144    selection.event_attr.sample_regs_user = GetSupportedRegMask();
145    selection.event_attr.sample_stack_user = dump_stack_size;
146  }
147  return true;
148}
149
150void EventSelectionSet::SetInherit(bool enable) {
151  for (auto& selection : selections_) {
152    selection.event_attr.inherit = (enable ? 1 : 0);
153  }
154}
155
156bool EventSelectionSet::OpenEventFilesForAllCpus() {
157  return OpenEventFilesForThreadsOnAllCpus({-1});
158}
159
160bool EventSelectionSet::OpenEventFilesForThreads(const std::vector<pid_t>& threads) {
161  return OpenEventFiles(threads, {-1});
162}
163
164bool EventSelectionSet::OpenEventFilesForThreadsOnAllCpus(const std::vector<pid_t>& threads) {
165  std::vector<int> cpus = GetOnlineCpus();
166  if (cpus.empty()) {
167    return false;
168  }
169  return OpenEventFiles(threads, cpus);
170}
171
172bool EventSelectionSet::OpenEventFiles(const std::vector<pid_t>& threads,
173                                       const std::vector<int>& cpus) {
174  for (auto& selection : selections_) {
175    for (auto& tid : threads) {
176      size_t open_per_thread = 0;
177      for (auto& cpu : cpus) {
178        auto event_fd = EventFd::OpenEventFile(selection.event_attr, tid, cpu);
179        if (event_fd != nullptr) {
180          selection.event_fds.push_back(std::move(event_fd));
181          ++open_per_thread;
182        }
183      }
184      // As the online cpus can be enabled or disabled at runtime, we may not open event file for
185      // all cpus successfully. But we should open at least one cpu successfully.
186      if (open_per_thread == 0) {
187        PLOG(ERROR) << "failed to open perf event file for event_type " << selection.event_type.name
188                    << " for "
189                    << (tid == -1 ? "all threads" : android::base::StringPrintf(" thread %d", tid));
190        return false;
191      }
192    }
193  }
194  return true;
195}
196
197bool EventSelectionSet::EnableEvents() {
198  for (auto& selection : selections_) {
199    for (auto& event_fd : selection.event_fds) {
200      if (!event_fd->EnableEvent()) {
201        return false;
202      }
203    }
204  }
205  return true;
206}
207
208bool EventSelectionSet::ReadCounters(
209    std::map<const EventType*, std::vector<PerfCounter>>* counters_map) {
210  for (auto& selection : selections_) {
211    std::vector<PerfCounter> counters;
212    for (auto& event_fd : selection.event_fds) {
213      PerfCounter counter;
214      if (!event_fd->ReadCounter(&counter)) {
215        return false;
216      }
217      counters.push_back(counter);
218    }
219    counters_map->insert(std::make_pair(&selection.event_type, counters));
220  }
221  return true;
222}
223
224void EventSelectionSet::PreparePollForEventFiles(std::vector<pollfd>* pollfds) {
225  for (auto& selection : selections_) {
226    for (auto& event_fd : selection.event_fds) {
227      pollfd poll_fd;
228      event_fd->PreparePollForMmapData(&poll_fd);
229      pollfds->push_back(poll_fd);
230    }
231  }
232}
233
234bool EventSelectionSet::MmapEventFiles(size_t mmap_pages) {
235  for (auto& selection : selections_) {
236    for (auto& event_fd : selection.event_fds) {
237      if (!event_fd->MmapContent(mmap_pages)) {
238        return false;
239      }
240    }
241  }
242  return true;
243}
244
245static bool ReadMmapEventDataForFd(std::unique_ptr<EventFd>& event_fd,
246                                   std::function<bool(const char*, size_t)> callback,
247                                   bool* have_data) {
248  *have_data = false;
249  while (true) {
250    char* data;
251    size_t size = event_fd->GetAvailableMmapData(&data);
252    if (size == 0) {
253      break;
254    }
255    if (!callback(data, size)) {
256      return false;
257    }
258    *have_data = true;
259    event_fd->DiscardMmapData(size);
260  }
261  return true;
262}
263
264bool EventSelectionSet::ReadMmapEventData(std::function<bool(const char*, size_t)> callback) {
265  for (auto& selection : selections_) {
266    for (auto& event_fd : selection.event_fds) {
267      while (true) {
268        bool have_data;
269        if (!ReadMmapEventDataForFd(event_fd, callback, &have_data)) {
270          return false;
271        }
272        if (!have_data) {
273          break;
274        }
275      }
276    }
277  }
278  return true;
279}
280
281std::string EventSelectionSet::FindEventFileNameById(uint64_t id) {
282  for (auto& selection : selections_) {
283    for (auto& event_fd : selection.event_fds) {
284      if (event_fd->Id() == id) {
285        return event_fd->Name();
286      }
287    }
288  }
289  return "";
290}
291
292EventSelectionSet::EventSelection* EventSelectionSet::FindSelectionByType(
293    const EventType& event_type) {
294  for (auto& selection : selections_) {
295    if (selection.event_type.name == event_type.name) {
296      return &selection;
297    }
298  }
299  return nullptr;
300}
301
302const perf_event_attr& EventSelectionSet::FindEventAttrByType(const EventType& event_type) {
303  return FindSelectionByType(event_type)->event_attr;
304}
305
306const std::vector<std::unique_ptr<EventFd>>& EventSelectionSet::FindEventFdsByType(
307    const EventType& event_type) {
308  return FindSelectionByType(event_type)->event_fds;
309}
310