2 * Copyright (C) 2015 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "event_selection_set.h"
19 #include <base/logging.h>
20 #include <base/stringprintf.h>
22 #include "environment.h"
23 #include "event_attr.h"
24 #include "event_type.h"
25 #include "perf_regs.h"
27 bool IsBranchSamplingSupported() {
28 const EventType* type = FindEventTypeByName("cpu-cycles");
29 if (type == nullptr) {
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);
38 bool IsDwarfCallChainSamplingSupported() {
39 const EventType* type = FindEventTypeByName("cpu-cycles");
40 if (type == nullptr) {
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);
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";
65 selections_.push_back(std::move(selection));
70 // Union the sample type of different event attrs can make reading sample records in perf.data
72 void EventSelectionSet::UnionSampleType() {
73 uint64_t sample_type = 0;
74 for (auto& selection : selections_) {
75 sample_type |= selection.event_attr.sample_type;
77 for (auto& selection : selections_) {
78 selection.event_attr.sample_type = sample_type;
82 void EventSelectionSet::SetEnableOnExec(bool enable) {
83 for (auto& selection : selections_) {
84 selection.event_attr.enable_on_exec = (enable ? 1 : 0);
88 bool EventSelectionSet::GetEnableOnExec() {
89 for (auto& selection : selections_) {
90 if (selection.event_attr.enable_on_exec == 0) {
97 void EventSelectionSet::SampleIdAll() {
98 for (auto& selection : selections_) {
99 selection.event_attr.sample_id_all = 1;
103 void EventSelectionSet::SetSampleFreq(uint64_t sample_freq) {
104 for (auto& selection : selections_) {
105 perf_event_attr& attr = selection.event_attr;
107 attr.sample_freq = sample_freq;
111 void EventSelectionSet::SetSamplePeriod(uint64_t sample_period) {
112 for (auto& selection : selections_) {
113 perf_event_attr& attr = selection.event_attr;
115 attr.sample_period = sample_period;
119 bool 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;
126 if (branch_sample_type != 0 && !IsBranchSamplingSupported()) {
127 LOG(ERROR) << "branch stack sampling is not supported on this device.";
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;
135 attr.sample_type &= ~PERF_SAMPLE_BRANCH_STACK;
137 attr.branch_sample_type = branch_sample_type;
142 void EventSelectionSet::EnableFpCallChainSampling() {
143 for (auto& selection : selections_) {
144 selection.event_attr.sample_type |= PERF_SAMPLE_CALLCHAIN;
148 bool EventSelectionSet::EnableDwarfCallChainSampling(uint32_t dump_stack_size) {
149 if (!IsDwarfCallChainSamplingSupported()) {
150 LOG(ERROR) << "dwarf callchain sampling is not supported on this device.";
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;
163 void EventSelectionSet::SetInherit(bool enable) {
164 for (auto& selection : selections_) {
165 selection.event_attr.inherit = (enable ? 1 : 0);
169 bool EventSelectionSet::OpenEventFilesForAllCpus() {
170 return OpenEventFilesForThreadsOnAllCpus({-1});
173 bool EventSelectionSet::OpenEventFilesForThreads(const std::vector<pid_t>& threads) {
174 return OpenEventFiles(threads, {-1});
177 bool EventSelectionSet::OpenEventFilesForThreadsOnAllCpus(const std::vector<pid_t>& threads) {
178 std::vector<int> cpus = GetOnlineCpus();
182 return OpenEventFiles(threads, cpus);
185 bool EventSelectionSet::OpenEventFiles(const std::vector<pid_t>& threads,
186 const std::vector<int>& cpus) {
187 for (auto& selection : selections_) {
188 for (auto& tid : threads) {
189 size_t open_per_thread = 0;
190 for (auto& cpu : cpus) {
191 auto event_fd = EventFd::OpenEventFile(selection.event_attr, tid, cpu);
192 if (event_fd != nullptr) {
193 selection.event_fds.push_back(std::move(event_fd));
197 // As the online cpus can be enabled or disabled at runtime, we may not open event file for
198 // all cpus successfully. But we should open at least one cpu successfully.
199 if (open_per_thread == 0) {
200 PLOG(ERROR) << "failed to open perf event file for event_type "
201 << selection.event_type_modifier.name << " for "
202 << (tid == -1 ? "all threads" : android::base::StringPrintf(" thread %d", tid));
210 bool EventSelectionSet::EnableEvents() {
211 for (auto& selection : selections_) {
212 for (auto& event_fd : selection.event_fds) {
213 if (!event_fd->EnableEvent()) {
221 bool EventSelectionSet::ReadCounters(std::vector<CountersInfo>* counters) {
223 for (auto& selection : selections_) {
224 CountersInfo counters_info;
225 counters_info.event_type = &selection.event_type_modifier;
226 for (auto& event_fd : selection.event_fds) {
227 CountersInfo::CounterInfo counter_info;
228 if (!event_fd->ReadCounter(&counter_info.counter)) {
231 counter_info.tid = event_fd->ThreadId();
232 counter_info.cpu = event_fd->Cpu();
233 counters_info.counters.push_back(counter_info);
235 counters->push_back(counters_info);
240 void EventSelectionSet::PreparePollForEventFiles(std::vector<pollfd>* pollfds) {
241 for (auto& selection : selections_) {
242 for (auto& event_fd : selection.event_fds) {
244 event_fd->PreparePollForMmapData(&poll_fd);
245 pollfds->push_back(poll_fd);
250 bool EventSelectionSet::MmapEventFiles(size_t mmap_pages) {
251 for (auto& selection : selections_) {
252 for (auto& event_fd : selection.event_fds) {
253 if (!event_fd->MmapContent(mmap_pages)) {
261 static bool ReadMmapEventDataForFd(std::unique_ptr<EventFd>& event_fd,
262 std::function<bool(const char*, size_t)> callback,
267 size_t size = event_fd->GetAvailableMmapData(&data);
271 if (!callback(data, size)) {
275 event_fd->DiscardMmapData(size);
280 bool EventSelectionSet::ReadMmapEventData(std::function<bool(const char*, size_t)> callback) {
281 for (auto& selection : selections_) {
282 for (auto& event_fd : selection.event_fds) {
285 if (!ReadMmapEventDataForFd(event_fd, callback, &have_data)) {
297 EventSelectionSet::EventSelection* EventSelectionSet::FindSelectionByType(
298 const EventTypeAndModifier& event_type_modifier) {
299 for (auto& selection : selections_) {
300 if (selection.event_type_modifier.name == event_type_modifier.name) {
307 const perf_event_attr* EventSelectionSet::FindEventAttrByType(
308 const EventTypeAndModifier& event_type_modifier) {
309 EventSelection* selection = FindSelectionByType(event_type_modifier);
310 return (selection != nullptr) ? &selection->event_attr : nullptr;
313 const std::vector<std::unique_ptr<EventFd>>* EventSelectionSet::FindEventFdsByType(
314 const EventTypeAndModifier& event_type_modifier) {
315 EventSelection* selection = FindSelectionByType(event_type_modifier);
316 return (selection != nullptr) ? &selection->event_fds : nullptr;