event_selection_set.cpp revision 4cf37d1583a605785b7677c1935ce316c2097fa2
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 "IOEventLoop.h"
26#include "perf_regs.h"
27#include "utils.h"
28
29bool IsBranchSamplingSupported() {
30  const EventType* type = FindEventTypeByName("cpu-cycles");
31  if (type == nullptr) {
32    return false;
33  }
34  perf_event_attr attr = CreateDefaultPerfEventAttr(*type);
35  attr.sample_type |= PERF_SAMPLE_BRANCH_STACK;
36  attr.branch_sample_type = PERF_SAMPLE_BRANCH_ANY;
37  return IsEventAttrSupportedByKernel(attr);
38}
39
40bool IsDwarfCallChainSamplingSupported() {
41  const EventType* type = FindEventTypeByName("cpu-cycles");
42  if (type == nullptr) {
43    return false;
44  }
45  perf_event_attr attr = CreateDefaultPerfEventAttr(*type);
46  attr.sample_type |=
47      PERF_SAMPLE_CALLCHAIN | PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER;
48  attr.exclude_callchain_user = 1;
49  attr.sample_regs_user = GetSupportedRegMask(GetBuildArch());
50  attr.sample_stack_user = 8192;
51  return IsEventAttrSupportedByKernel(attr);
52}
53
54bool EventSelectionSet::BuildAndCheckEventSelection(
55    const std::string& event_name, EventSelection* selection) {
56  std::unique_ptr<EventTypeAndModifier> event_type = ParseEventType(event_name);
57  if (event_type == nullptr) {
58    return false;
59  }
60  if (for_stat_cmd_) {
61    if (event_type->event_type.name == "cpu-clock" ||
62        event_type->event_type.name == "task-clock") {
63      if (event_type->exclude_user || event_type->exclude_kernel) {
64        LOG(ERROR) << "Modifier u and modifier k used in event type "
65                   << event_type->event_type.name
66                   << " are not supported by the kernel.";
67        return false;
68      }
69    }
70  }
71  selection->event_type_modifier = *event_type;
72  selection->event_attr = CreateDefaultPerfEventAttr(event_type->event_type);
73  selection->event_attr.exclude_user = event_type->exclude_user;
74  selection->event_attr.exclude_kernel = event_type->exclude_kernel;
75  selection->event_attr.exclude_hv = event_type->exclude_hv;
76  selection->event_attr.exclude_host = event_type->exclude_host;
77  selection->event_attr.exclude_guest = event_type->exclude_guest;
78  selection->event_attr.precise_ip = event_type->precise_ip;
79  if (!IsEventAttrSupportedByKernel(selection->event_attr)) {
80    LOG(ERROR) << "Event type '" << event_type->name
81               << "' is not supported by the kernel";
82    return false;
83  }
84  selection->event_fds.clear();
85
86  for (const auto& group : groups_) {
87    for (const auto& sel : group) {
88      if (sel.event_type_modifier.name == selection->event_type_modifier.name) {
89        LOG(ERROR) << "Event type '" << sel.event_type_modifier.name
90                   << "' appears more than once";
91        return false;
92      }
93    }
94  }
95  return true;
96}
97
98bool EventSelectionSet::AddEventType(const std::string& event_name) {
99  return AddEventGroup(std::vector<std::string>(1, event_name));
100}
101
102bool EventSelectionSet::AddEventGroup(
103    const std::vector<std::string>& event_names) {
104  EventSelectionGroup group;
105  for (const auto& event_name : event_names) {
106    EventSelection selection;
107    if (!BuildAndCheckEventSelection(event_name, &selection)) {
108      return false;
109    }
110    selection.selection_id = group.size();
111    selection.group_id = groups_.size();
112    group.push_back(std::move(selection));
113  }
114  groups_.push_back(std::move(group));
115  UnionSampleType();
116  return true;
117}
118
119// Union the sample type of different event attrs can make reading sample
120// records in perf.data easier.
121void EventSelectionSet::UnionSampleType() {
122  uint64_t sample_type = 0;
123  for (const auto& group : groups_) {
124    for (const auto& selection : group) {
125      sample_type |= selection.event_attr.sample_type;
126    }
127  }
128  for (auto& group : groups_) {
129    for (auto& selection : group) {
130      selection.event_attr.sample_type = sample_type;
131    }
132  }
133}
134
135void EventSelectionSet::SetEnableOnExec(bool enable) {
136  for (auto& group : groups_) {
137    for (auto& selection : group) {
138      // If sampling is enabled on exec, then it is disabled at startup,
139      // otherwise it should be enabled at startup. Don't use
140      // ioctl(PERF_EVENT_IOC_ENABLE) to enable it after perf_event_open().
141      // Because some android kernels can't handle ioctl() well when cpu-hotplug
142      // happens. See http://b/25193162.
143      if (enable) {
144        selection.event_attr.enable_on_exec = 1;
145        selection.event_attr.disabled = 1;
146      } else {
147        selection.event_attr.enable_on_exec = 0;
148        selection.event_attr.disabled = 0;
149      }
150    }
151  }
152}
153
154bool EventSelectionSet::GetEnableOnExec() {
155  for (const auto& group : groups_) {
156    for (const auto& selection : group) {
157      if (selection.event_attr.enable_on_exec == 0) {
158        return false;
159      }
160    }
161  }
162  return true;
163}
164
165void EventSelectionSet::SampleIdAll() {
166  for (auto& group : groups_) {
167    for (auto& selection : group) {
168      selection.event_attr.sample_id_all = 1;
169    }
170  }
171}
172
173void EventSelectionSet::SetSampleFreq(const EventSelection& selection,
174                                      uint64_t sample_freq) {
175  EventSelection& sel = groups_[selection.group_id][selection.selection_id];
176  sel.event_attr.freq = 1;
177  sel.event_attr.sample_freq = sample_freq;
178}
179
180void EventSelectionSet::SetSamplePeriod(const EventSelection& selection,
181                                        uint64_t sample_period) {
182  EventSelection& sel = groups_[selection.group_id][selection.selection_id];
183  sel.event_attr.freq = 0;
184  sel.event_attr.sample_period = sample_period;
185}
186
187bool EventSelectionSet::SetBranchSampling(uint64_t branch_sample_type) {
188  if (branch_sample_type != 0 &&
189      (branch_sample_type &
190       (PERF_SAMPLE_BRANCH_ANY | PERF_SAMPLE_BRANCH_ANY_CALL |
191        PERF_SAMPLE_BRANCH_ANY_RETURN | PERF_SAMPLE_BRANCH_IND_CALL)) == 0) {
192    LOG(ERROR) << "Invalid branch_sample_type: 0x" << std::hex
193               << branch_sample_type;
194    return false;
195  }
196  if (branch_sample_type != 0 && !IsBranchSamplingSupported()) {
197    LOG(ERROR) << "branch stack sampling is not supported on this device.";
198    return false;
199  }
200  for (auto& group : groups_) {
201    for (auto& selection : group) {
202      perf_event_attr& attr = selection.event_attr;
203      if (branch_sample_type != 0) {
204        attr.sample_type |= PERF_SAMPLE_BRANCH_STACK;
205      } else {
206        attr.sample_type &= ~PERF_SAMPLE_BRANCH_STACK;
207      }
208      attr.branch_sample_type = branch_sample_type;
209    }
210  }
211  return true;
212}
213
214void EventSelectionSet::EnableFpCallChainSampling() {
215  for (auto& group : groups_) {
216    for (auto& selection : group) {
217      selection.event_attr.sample_type |= PERF_SAMPLE_CALLCHAIN;
218    }
219  }
220}
221
222bool EventSelectionSet::EnableDwarfCallChainSampling(uint32_t dump_stack_size) {
223  if (!IsDwarfCallChainSamplingSupported()) {
224    LOG(ERROR) << "dwarf callchain sampling is not supported on this device.";
225    return false;
226  }
227  for (auto& group : groups_) {
228    for (auto& selection : group) {
229      selection.event_attr.sample_type |= PERF_SAMPLE_CALLCHAIN |
230                                          PERF_SAMPLE_REGS_USER |
231                                          PERF_SAMPLE_STACK_USER;
232      selection.event_attr.exclude_callchain_user = 1;
233      selection.event_attr.sample_regs_user =
234          GetSupportedRegMask(GetBuildArch());
235      selection.event_attr.sample_stack_user = dump_stack_size;
236    }
237  }
238  return true;
239}
240
241void EventSelectionSet::SetInherit(bool enable) {
242  for (auto& group : groups_) {
243    for (auto& selection : group) {
244      selection.event_attr.inherit = (enable ? 1 : 0);
245    }
246  }
247}
248
249void EventSelectionSet::SetLowWatermark() {
250  for (auto& group : groups_) {
251    for (auto& selection : group) {
252      selection.event_attr.wakeup_events = 1;
253    }
254  }
255}
256
257static bool CheckIfCpusOnline(const std::vector<int>& cpus) {
258  std::vector<int> online_cpus = GetOnlineCpus();
259  for (const auto& cpu : cpus) {
260    if (std::find(online_cpus.begin(), online_cpus.end(), cpu) ==
261        online_cpus.end()) {
262      LOG(ERROR) << "cpu " << cpu << " is not online.";
263      return false;
264    }
265  }
266  return true;
267}
268
269bool EventSelectionSet::OpenEventFilesForCpus(const std::vector<int>& cpus) {
270  return OpenEventFilesForThreadsOnCpus({-1}, cpus);
271}
272
273bool EventSelectionSet::OpenEventFilesForThreadsOnCpus(
274    const std::vector<pid_t>& threads, std::vector<int> cpus) {
275  if (!cpus.empty()) {
276    // cpus = {-1} means open an event file for all cpus.
277    if (!(cpus.size() == 1 && cpus[0] == -1) && !CheckIfCpusOnline(cpus)) {
278      return false;
279    }
280  } else {
281    cpus = GetOnlineCpus();
282  }
283  return OpenEventFiles(threads, cpus);
284}
285
286bool EventSelectionSet::OpenEventFiles(const std::vector<pid_t>& threads,
287                                       const std::vector<int>& cpus) {
288  for (auto& group : groups_) {
289    for (const auto& tid : threads) {
290      size_t open_per_thread = 0;
291      std::string failed_event_type;
292      for (const auto& cpu : cpus) {
293        std::vector<std::unique_ptr<EventFd>> event_fds;
294        // Given a tid and cpu, events on the same group should be all opened
295        // successfully or all failed to open.
296        for (auto& selection : group) {
297          EventFd* group_fd = nullptr;
298          if (selection.selection_id != 0) {
299            group_fd = event_fds[0].get();
300          }
301          std::unique_ptr<EventFd> event_fd =
302              EventFd::OpenEventFile(selection.event_attr, tid, cpu, group_fd);
303          if (event_fd != nullptr) {
304            LOG(VERBOSE) << "OpenEventFile for " << event_fd->Name();
305            event_fds.push_back(std::move(event_fd));
306          } else {
307            failed_event_type = selection.event_type_modifier.name;
308            break;
309          }
310        }
311        if (event_fds.size() == group.size()) {
312          for (size_t i = 0; i < group.size(); ++i) {
313            group[i].event_fds.push_back(std::move(event_fds[i]));
314          }
315          ++open_per_thread;
316        }
317      }
318      // As the online cpus can be enabled or disabled at runtime, we may not
319      // open event file for all cpus successfully. But we should open at least
320      // one cpu successfully.
321      if (open_per_thread == 0) {
322        PLOG(ERROR) << "failed to open perf event file for event_type "
323                    << failed_event_type << " for "
324                    << (tid == -1 ? "all threads" : android::base::StringPrintf(
325                                                        " thread %d", tid));
326        return false;
327      }
328    }
329  }
330  return true;
331}
332
333bool EventSelectionSet::ReadCounters(std::vector<CountersInfo>* counters) {
334  counters->clear();
335  for (auto& group : groups_) {
336    for (auto& selection : group) {
337      CountersInfo counters_info;
338      counters_info.selection = &selection;
339      for (auto& event_fd : selection.event_fds) {
340        CountersInfo::CounterInfo counter_info;
341        if (!event_fd->ReadCounter(&counter_info.counter)) {
342          return false;
343        }
344        counter_info.tid = event_fd->ThreadId();
345        counter_info.cpu = event_fd->Cpu();
346        counters_info.counters.push_back(counter_info);
347      }
348      counters->push_back(counters_info);
349    }
350  }
351  return true;
352}
353
354bool EventSelectionSet::MmapEventFiles(size_t min_mmap_pages,
355                                       size_t max_mmap_pages) {
356  for (size_t i = max_mmap_pages; i >= min_mmap_pages; i >>= 1) {
357    if (MmapEventFiles(i, i == min_mmap_pages)) {
358      LOG(VERBOSE) << "Mapped buffer size is " << i << " pages.";
359      return true;
360    }
361    for (auto& group : groups_) {
362      for (auto& selection : group) {
363        for (auto& event_fd : selection.event_fds) {
364          event_fd->DestroyMappedBuffer();
365        }
366      }
367    }
368  }
369  return false;
370}
371
372bool EventSelectionSet::MmapEventFiles(size_t mmap_pages, bool report_error) {
373  for (auto& group : groups_) {
374    for (auto& selection : group) {
375      // For each event, allocate a mapped buffer for each cpu.
376      std::map<int, EventFd*> cpu_map;
377      for (auto& event_fd : selection.event_fds) {
378        auto it = cpu_map.find(event_fd->Cpu());
379        if (it != cpu_map.end()) {
380          if (!event_fd->ShareMappedBuffer(*(it->second), report_error)) {
381            return false;
382          }
383        } else {
384          if (!event_fd->CreateMappedBuffer(mmap_pages, report_error)) {
385            return false;
386          }
387          cpu_map.insert(std::make_pair(event_fd->Cpu(), event_fd.get()));
388        }
389      }
390    }
391  }
392  return true;
393}
394
395bool EventSelectionSet::PrepareToReadMmapEventData(
396    IOEventLoop& loop, const std::function<bool(Record*)>& callback) {
397  // Add read Events for perf event files having mapped buffer.
398  for (auto& group : groups_) {
399    for (auto& selection : group) {
400      for (auto& event_fd : selection.event_fds) {
401        if (event_fd->HasMappedBuffer()) {
402          if (!loop.AddReadEvent(event_fd->fd(), [&]() {
403                return ReadMmapEventDataForFd(event_fd);
404              })) {
405            return false;
406          }
407        }
408      }
409    }
410  }
411
412  // Prepare record callback function.
413  record_callback_ = callback;
414  return true;
415}
416
417bool EventSelectionSet::ReadMmapEventDataForFd(
418    std::unique_ptr<EventFd>& event_fd) {
419  const char* data;
420  // Call GetAvailableMmapData() only once instead of calling in a loop, because
421  // 1) A mapped buffer caches data before needing to be read again. By default
422  //    it raises read Event when half full.
423  // 2) Spinning on one mapped buffer can make other mapped buffers overflow.
424  size_t size = event_fd->GetAvailableMmapData(&data);
425  if (size == 0) {
426    return true;
427  }
428  std::vector<std::unique_ptr<Record>> records =
429      ReadRecordsFromBuffer(event_fd->attr(), data, size);
430  for (auto& r : records) {
431    if (!record_callback_(r.get())) {
432      return false;
433    }
434  }
435  return true;
436}
437
438bool EventSelectionSet::FinishReadMmapEventData() {
439  // Read each mapped buffer once, because some data may exist in the buffers
440  // but is not much enough to raise read Events.
441  for (auto& group : groups_) {
442    for (auto& selection : group) {
443      for (auto& event_fd : selection.event_fds) {
444        if (event_fd->HasMappedBuffer()) {
445          if (!ReadMmapEventDataForFd(event_fd)) {
446            return false;
447          }
448        }
449      }
450    }
451  }
452  return true;
453}
454
455bool EventSelectionSet::HandleCpuHotplugEvents(
456    IOEventLoop& loop, const std::vector<int>& monitored_cpus,
457    double check_interval_in_sec) {
458  monitored_cpus_.insert(monitored_cpus.begin(), monitored_cpus.end());
459  online_cpus_ = GetOnlineCpus();
460  if (!loop.AddPeriodicEvent(SecondToTimeval(check_interval_in_sec),
461                             [&]() { return DetectCpuHotplugEvents(); })) {
462    return false;
463  }
464  return true;
465}
466
467bool EventSelectionSet::DetectCpuHotplugEvents() {
468  std::vector<int> new_cpus = GetOnlineCpus();
469  for (const auto& cpu : online_cpus_) {
470    if (std::find(new_cpus.begin(), new_cpus.end(), cpu) == new_cpus.end()) {
471      if (monitored_cpus_.empty() ||
472          monitored_cpus_.find(cpu) != monitored_cpus_.end()) {
473        LOG(INFO) << "Cpu " << cpu << " is offlined";
474      }
475    }
476  }
477  for (const auto& cpu : new_cpus) {
478    if (std::find(online_cpus_.begin(), online_cpus_.end(), cpu) ==
479        online_cpus_.end()) {
480      if (monitored_cpus_.empty() ||
481          monitored_cpus_.find(cpu) != monitored_cpus_.end()) {
482        LOG(INFO) << "Cpu " << cpu << " is onlined";
483      }
484    }
485  }
486  online_cpus_ = new_cpus;
487  return true;
488}
489