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