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