event_selection_set.cpp revision 66dd09e8e2407082ce93bf0784de641298131912
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 "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 169static bool CheckIfCpusOnline(const std::vector<int>& cpus) { 170 std::vector<int> online_cpus = GetOnlineCpus(); 171 for (const auto& cpu : cpus) { 172 if (std::find(online_cpus.begin(), online_cpus.end(), cpu) == online_cpus.end()) { 173 LOG(ERROR) << "cpu " << cpu << " is not online."; 174 return false; 175 } 176 } 177 return true; 178} 179 180bool EventSelectionSet::OpenEventFilesForCpus(const std::vector<int>& cpus) { 181 return OpenEventFilesForThreadsOnCpus({-1}, cpus); 182} 183 184bool EventSelectionSet::OpenEventFilesForThreadsOnCpus(const std::vector<pid_t>& threads, 185 std::vector<int> cpus) { 186 if (!cpus.empty()) { 187 if (!CheckIfCpusOnline(cpus)) { 188 return false; 189 } 190 } else { 191 cpus = GetOnlineCpus(); 192 } 193 return OpenEventFiles(threads, cpus); 194} 195 196bool EventSelectionSet::OpenEventFiles(const std::vector<pid_t>& threads, 197 const std::vector<int>& cpus) { 198 for (auto& selection : selections_) { 199 for (auto& tid : threads) { 200 size_t open_per_thread = 0; 201 for (auto& cpu : cpus) { 202 auto event_fd = EventFd::OpenEventFile(selection.event_attr, tid, cpu); 203 if (event_fd != nullptr) { 204 selection.event_fds.push_back(std::move(event_fd)); 205 ++open_per_thread; 206 } 207 } 208 // As the online cpus can be enabled or disabled at runtime, we may not open event file for 209 // all cpus successfully. But we should open at least one cpu successfully. 210 if (open_per_thread == 0) { 211 PLOG(ERROR) << "failed to open perf event file for event_type " 212 << selection.event_type_modifier.name << " for " 213 << (tid == -1 ? "all threads" : android::base::StringPrintf(" thread %d", tid)); 214 return false; 215 } 216 } 217 } 218 return true; 219} 220 221bool EventSelectionSet::EnableEvents() { 222 for (auto& selection : selections_) { 223 for (auto& event_fd : selection.event_fds) { 224 if (!event_fd->EnableEvent()) { 225 return false; 226 } 227 } 228 } 229 return true; 230} 231 232bool EventSelectionSet::ReadCounters(std::vector<CountersInfo>* counters) { 233 counters->clear(); 234 for (auto& selection : selections_) { 235 CountersInfo counters_info; 236 counters_info.event_type = &selection.event_type_modifier; 237 for (auto& event_fd : selection.event_fds) { 238 CountersInfo::CounterInfo counter_info; 239 if (!event_fd->ReadCounter(&counter_info.counter)) { 240 return false; 241 } 242 counter_info.tid = event_fd->ThreadId(); 243 counter_info.cpu = event_fd->Cpu(); 244 counters_info.counters.push_back(counter_info); 245 } 246 counters->push_back(counters_info); 247 } 248 return true; 249} 250 251void EventSelectionSet::PreparePollForEventFiles(std::vector<pollfd>* pollfds) { 252 for (auto& selection : selections_) { 253 for (auto& event_fd : selection.event_fds) { 254 pollfd poll_fd; 255 event_fd->PreparePollForMmapData(&poll_fd); 256 pollfds->push_back(poll_fd); 257 } 258 } 259} 260 261bool EventSelectionSet::MmapEventFiles(size_t mmap_pages) { 262 for (auto& selection : selections_) { 263 for (auto& event_fd : selection.event_fds) { 264 if (!event_fd->MmapContent(mmap_pages)) { 265 return false; 266 } 267 } 268 } 269 return true; 270} 271 272static bool ReadMmapEventDataForFd(std::unique_ptr<EventFd>& event_fd, 273 std::function<bool(const char*, size_t)> callback, 274 bool* have_data) { 275 *have_data = false; 276 while (true) { 277 char* data; 278 size_t size = event_fd->GetAvailableMmapData(&data); 279 if (size == 0) { 280 break; 281 } 282 if (!callback(data, size)) { 283 return false; 284 } 285 *have_data = true; 286 } 287 return true; 288} 289 290bool EventSelectionSet::ReadMmapEventData(std::function<bool(const char*, size_t)> callback) { 291 for (auto& selection : selections_) { 292 for (auto& event_fd : selection.event_fds) { 293 while (true) { 294 bool have_data; 295 if (!ReadMmapEventDataForFd(event_fd, callback, &have_data)) { 296 return false; 297 } 298 if (!have_data) { 299 break; 300 } 301 } 302 } 303 } 304 return true; 305} 306 307EventSelectionSet::EventSelection* EventSelectionSet::FindSelectionByType( 308 const EventTypeAndModifier& event_type_modifier) { 309 for (auto& selection : selections_) { 310 if (selection.event_type_modifier.name == event_type_modifier.name) { 311 return &selection; 312 } 313 } 314 return nullptr; 315} 316 317const perf_event_attr* EventSelectionSet::FindEventAttrByType( 318 const EventTypeAndModifier& event_type_modifier) { 319 EventSelection* selection = FindSelectionByType(event_type_modifier); 320 return (selection != nullptr) ? &selection->event_attr : nullptr; 321} 322 323const std::vector<std::unique_ptr<EventFd>>* EventSelectionSet::FindEventFdsByType( 324 const EventTypeAndModifier& event_type_modifier) { 325 EventSelection* selection = FindSelectionByType(event_type_modifier); 326 return (selection != nullptr) ? &selection->event_fds : nullptr; 327} 328