event_selection_set.cpp revision b1a885b014540a2f7798b5a35ea0f0ec150d93ee
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 // If sampling is enabled on exec, then it is disabled at startup, otherwise 85 // it should be enabled at startup. Don't use ioctl(PERF_EVENT_IOC_ENABLE) 86 // to enable it after perf_event_open(). Because some android kernels can't 87 // handle ioctl() well when cpu-hotplug happens. See http://b/25193162. 88 if (enable) { 89 selection.event_attr.enable_on_exec = 1; 90 selection.event_attr.disabled = 1; 91 } else { 92 selection.event_attr.enable_on_exec = 0; 93 selection.event_attr.disabled = 0; 94 } 95 } 96} 97 98bool EventSelectionSet::GetEnableOnExec() { 99 for (auto& selection : selections_) { 100 if (selection.event_attr.enable_on_exec == 0) { 101 return false; 102 } 103 } 104 return true; 105} 106 107void EventSelectionSet::SampleIdAll() { 108 for (auto& selection : selections_) { 109 selection.event_attr.sample_id_all = 1; 110 } 111} 112 113void EventSelectionSet::SetSampleFreq(uint64_t sample_freq) { 114 for (auto& selection : selections_) { 115 perf_event_attr& attr = selection.event_attr; 116 attr.freq = 1; 117 attr.sample_freq = sample_freq; 118 } 119} 120 121void EventSelectionSet::SetSamplePeriod(uint64_t sample_period) { 122 for (auto& selection : selections_) { 123 perf_event_attr& attr = selection.event_attr; 124 attr.freq = 0; 125 attr.sample_period = sample_period; 126 } 127} 128 129bool EventSelectionSet::SetBranchSampling(uint64_t branch_sample_type) { 130 if (branch_sample_type != 0 && 131 (branch_sample_type & (PERF_SAMPLE_BRANCH_ANY | PERF_SAMPLE_BRANCH_ANY_CALL | 132 PERF_SAMPLE_BRANCH_ANY_RETURN | PERF_SAMPLE_BRANCH_IND_CALL)) == 0) { 133 LOG(ERROR) << "Invalid branch_sample_type: 0x" << std::hex << branch_sample_type; 134 return false; 135 } 136 if (branch_sample_type != 0 && !IsBranchSamplingSupported()) { 137 LOG(ERROR) << "branch stack sampling is not supported on this device."; 138 return false; 139 } 140 for (auto& selection : selections_) { 141 perf_event_attr& attr = selection.event_attr; 142 if (branch_sample_type != 0) { 143 attr.sample_type |= PERF_SAMPLE_BRANCH_STACK; 144 } else { 145 attr.sample_type &= ~PERF_SAMPLE_BRANCH_STACK; 146 } 147 attr.branch_sample_type = branch_sample_type; 148 } 149 return true; 150} 151 152void EventSelectionSet::EnableFpCallChainSampling() { 153 for (auto& selection : selections_) { 154 selection.event_attr.sample_type |= PERF_SAMPLE_CALLCHAIN; 155 } 156} 157 158bool EventSelectionSet::EnableDwarfCallChainSampling(uint32_t dump_stack_size) { 159 if (!IsDwarfCallChainSamplingSupported()) { 160 LOG(ERROR) << "dwarf callchain sampling is not supported on this device."; 161 return false; 162 } 163 for (auto& selection : selections_) { 164 selection.event_attr.sample_type |= 165 PERF_SAMPLE_CALLCHAIN | PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER; 166 selection.event_attr.exclude_callchain_user = 1; 167 selection.event_attr.sample_regs_user = GetSupportedRegMask(); 168 selection.event_attr.sample_stack_user = dump_stack_size; 169 } 170 return true; 171} 172 173void EventSelectionSet::SetInherit(bool enable) { 174 for (auto& selection : selections_) { 175 selection.event_attr.inherit = (enable ? 1 : 0); 176 } 177} 178 179static bool CheckIfCpusOnline(const std::vector<int>& cpus) { 180 std::vector<int> online_cpus = GetOnlineCpus(); 181 for (const auto& cpu : cpus) { 182 if (std::find(online_cpus.begin(), online_cpus.end(), cpu) == online_cpus.end()) { 183 LOG(ERROR) << "cpu " << cpu << " is not online."; 184 return false; 185 } 186 } 187 return true; 188} 189 190bool EventSelectionSet::OpenEventFilesForCpus(const std::vector<int>& cpus) { 191 return OpenEventFilesForThreadsOnCpus({-1}, cpus); 192} 193 194bool EventSelectionSet::OpenEventFilesForThreadsOnCpus(const std::vector<pid_t>& threads, 195 std::vector<int> cpus) { 196 if (!cpus.empty()) { 197 if (!CheckIfCpusOnline(cpus)) { 198 return false; 199 } 200 } else { 201 cpus = GetOnlineCpus(); 202 } 203 return OpenEventFiles(threads, cpus); 204} 205 206bool EventSelectionSet::OpenEventFiles(const std::vector<pid_t>& threads, 207 const std::vector<int>& cpus) { 208 for (auto& selection : selections_) { 209 for (auto& tid : threads) { 210 size_t open_per_thread = 0; 211 for (auto& cpu : cpus) { 212 auto event_fd = EventFd::OpenEventFile(selection.event_attr, tid, cpu); 213 if (event_fd != nullptr) { 214 LOG(VERBOSE) << "OpenEventFile for tid " << tid << ", cpu " << cpu; 215 selection.event_fds.push_back(std::move(event_fd)); 216 ++open_per_thread; 217 } 218 } 219 // As the online cpus can be enabled or disabled at runtime, we may not open event file for 220 // all cpus successfully. But we should open at least one cpu successfully. 221 if (open_per_thread == 0) { 222 PLOG(ERROR) << "failed to open perf event file for event_type " 223 << selection.event_type_modifier.name << " for " 224 << (tid == -1 ? "all threads" : android::base::StringPrintf(" thread %d", tid)); 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