event_selection_set.cpp revision 04d08a35c5e1cabdf6eb7397536a790b0ff44459
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 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 " 188 << selection.event_type_modifier.name << " 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(std::vector<CountersInfo>* counters) { 209 counters->clear(); 210 for (auto& selection : selections_) { 211 CountersInfo counters_info; 212 counters_info.event_type = &selection.event_type_modifier; 213 for (auto& event_fd : selection.event_fds) { 214 CountersInfo::CounterInfo counter_info; 215 if (!event_fd->ReadCounter(&counter_info.counter)) { 216 return false; 217 } 218 counter_info.tid = event_fd->ThreadId(); 219 counter_info.cpu = event_fd->Cpu(); 220 counters_info.counters.push_back(counter_info); 221 } 222 counters->push_back(counters_info); 223 } 224 return true; 225} 226 227void EventSelectionSet::PreparePollForEventFiles(std::vector<pollfd>* pollfds) { 228 for (auto& selection : selections_) { 229 for (auto& event_fd : selection.event_fds) { 230 pollfd poll_fd; 231 event_fd->PreparePollForMmapData(&poll_fd); 232 pollfds->push_back(poll_fd); 233 } 234 } 235} 236 237bool EventSelectionSet::MmapEventFiles(size_t mmap_pages) { 238 for (auto& selection : selections_) { 239 for (auto& event_fd : selection.event_fds) { 240 if (!event_fd->MmapContent(mmap_pages)) { 241 return false; 242 } 243 } 244 } 245 return true; 246} 247 248static bool ReadMmapEventDataForFd(std::unique_ptr<EventFd>& event_fd, 249 std::function<bool(const char*, size_t)> callback, 250 bool* have_data) { 251 *have_data = false; 252 while (true) { 253 char* data; 254 size_t size = event_fd->GetAvailableMmapData(&data); 255 if (size == 0) { 256 break; 257 } 258 if (!callback(data, size)) { 259 return false; 260 } 261 *have_data = true; 262 event_fd->DiscardMmapData(size); 263 } 264 return true; 265} 266 267bool EventSelectionSet::ReadMmapEventData(std::function<bool(const char*, size_t)> callback) { 268 for (auto& selection : selections_) { 269 for (auto& event_fd : selection.event_fds) { 270 while (true) { 271 bool have_data; 272 if (!ReadMmapEventDataForFd(event_fd, callback, &have_data)) { 273 return false; 274 } 275 if (!have_data) { 276 break; 277 } 278 } 279 } 280 } 281 return true; 282} 283 284EventSelectionSet::EventSelection* EventSelectionSet::FindSelectionByType( 285 const EventTypeAndModifier& event_type_modifier) { 286 for (auto& selection : selections_) { 287 if (selection.event_type_modifier.name == event_type_modifier.name) { 288 return &selection; 289 } 290 } 291 return nullptr; 292} 293 294const perf_event_attr& EventSelectionSet::FindEventAttrByType( 295 const EventTypeAndModifier& event_type_modifier) { 296 return FindSelectionByType(event_type_modifier)->event_attr; 297} 298 299const std::vector<std::unique_ptr<EventFd>>& EventSelectionSet::FindEventFdsByType( 300 const EventTypeAndModifier& event_type_modifier) { 301 return FindSelectionByType(event_type_modifier)->event_fds; 302} 303