event_selection_set.cpp revision afdb9cea28340e31142fd66a90c88ed8e18ebbfa
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_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 169bool EventSelectionSet::OpenEventFilesForAllCpus() { 170 return OpenEventFilesForThreadsOnAllCpus({-1}); 171} 172 173bool EventSelectionSet::OpenEventFilesForThreads(const std::vector<pid_t>& threads) { 174 return OpenEventFiles(threads, {-1}); 175} 176 177bool EventSelectionSet::OpenEventFilesForThreadsOnAllCpus(const std::vector<pid_t>& threads) { 178 std::vector<int> cpus = GetOnlineCpus(); 179 if (cpus.empty()) { 180 return false; 181 } 182 return OpenEventFiles(threads, cpus); 183} 184 185bool 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)); 194 ++open_per_thread; 195 } 196 } 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)); 203 return false; 204 } 205 } 206 } 207 return true; 208} 209 210bool EventSelectionSet::EnableEvents() { 211 for (auto& selection : selections_) { 212 for (auto& event_fd : selection.event_fds) { 213 if (!event_fd->EnableEvent()) { 214 return false; 215 } 216 } 217 } 218 return true; 219} 220 221bool EventSelectionSet::ReadCounters(std::vector<CountersInfo>* counters) { 222 counters->clear(); 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)) { 229 return false; 230 } 231 counter_info.tid = event_fd->ThreadId(); 232 counter_info.cpu = event_fd->Cpu(); 233 counters_info.counters.push_back(counter_info); 234 } 235 counters->push_back(counters_info); 236 } 237 return true; 238} 239 240void EventSelectionSet::PreparePollForEventFiles(std::vector<pollfd>* pollfds) { 241 for (auto& selection : selections_) { 242 for (auto& event_fd : selection.event_fds) { 243 pollfd poll_fd; 244 event_fd->PreparePollForMmapData(&poll_fd); 245 pollfds->push_back(poll_fd); 246 } 247 } 248} 249 250bool 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)) { 254 return false; 255 } 256 } 257 } 258 return true; 259} 260 261static bool ReadMmapEventDataForFd(std::unique_ptr<EventFd>& event_fd, 262 std::function<bool(const char*, size_t)> callback, 263 bool* have_data) { 264 *have_data = false; 265 while (true) { 266 char* data; 267 size_t size = event_fd->GetAvailableMmapData(&data); 268 if (size == 0) { 269 break; 270 } 271 if (!callback(data, size)) { 272 return false; 273 } 274 *have_data = true; 275 event_fd->DiscardMmapData(size); 276 } 277 return true; 278} 279 280bool EventSelectionSet::ReadMmapEventData(std::function<bool(const char*, size_t)> callback) { 281 for (auto& selection : selections_) { 282 for (auto& event_fd : selection.event_fds) { 283 while (true) { 284 bool have_data; 285 if (!ReadMmapEventDataForFd(event_fd, callback, &have_data)) { 286 return false; 287 } 288 if (!have_data) { 289 break; 290 } 291 } 292 } 293 } 294 return true; 295} 296 297EventSelectionSet::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) { 301 return &selection; 302 } 303 } 304 return nullptr; 305} 306 307const 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; 311} 312 313const 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; 317} 318