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 <poll.h> 20 21 #include <android-base/logging.h> 22 #include <android-base/stringprintf.h> 23 24 #include "environment.h" 25 #include "event_attr.h" 26 #include "event_type.h" 27 #include "perf_regs.h" 28 29 bool IsBranchSamplingSupported() { 30 const EventType* type = FindEventTypeByName("cpu-cycles"); 31 if (type == nullptr) { 32 return false; 33 } 34 perf_event_attr attr = CreateDefaultPerfEventAttr(*type); 35 attr.sample_type |= PERF_SAMPLE_BRANCH_STACK; 36 attr.branch_sample_type = PERF_SAMPLE_BRANCH_ANY; 37 return IsEventAttrSupportedByKernel(attr); 38 } 39 40 bool IsDwarfCallChainSamplingSupported() { 41 const EventType* type = FindEventTypeByName("cpu-cycles"); 42 if (type == nullptr) { 43 return false; 44 } 45 perf_event_attr attr = CreateDefaultPerfEventAttr(*type); 46 attr.sample_type |= PERF_SAMPLE_CALLCHAIN | PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER; 47 attr.exclude_callchain_user = 1; 48 attr.sample_regs_user = GetSupportedRegMask(GetBuildArch()); 49 attr.sample_stack_user = 8192; 50 return IsEventAttrSupportedByKernel(attr); 51 } 52 53 bool EventSelectionSet::AddEventType(const EventTypeAndModifier& event_type_modifier) { 54 EventSelection selection; 55 selection.event_type_modifier = event_type_modifier; 56 selection.event_attr = CreateDefaultPerfEventAttr(event_type_modifier.event_type); 57 selection.event_attr.exclude_user = event_type_modifier.exclude_user; 58 selection.event_attr.exclude_kernel = event_type_modifier.exclude_kernel; 59 selection.event_attr.exclude_hv = event_type_modifier.exclude_hv; 60 selection.event_attr.exclude_host = event_type_modifier.exclude_host; 61 selection.event_attr.exclude_guest = event_type_modifier.exclude_guest; 62 selection.event_attr.precise_ip = event_type_modifier.precise_ip; 63 if (!IsEventAttrSupportedByKernel(selection.event_attr)) { 64 LOG(ERROR) << "Event type '" << event_type_modifier.name << "' is not supported by the kernel"; 65 return false; 66 } 67 selections_.push_back(std::move(selection)); 68 UnionSampleType(); 69 return true; 70 } 71 72 // Union the sample type of different event attrs can make reading sample records in perf.data 73 // easier. 74 void EventSelectionSet::UnionSampleType() { 75 uint64_t sample_type = 0; 76 for (auto& selection : selections_) { 77 sample_type |= selection.event_attr.sample_type; 78 } 79 for (auto& selection : selections_) { 80 selection.event_attr.sample_type = sample_type; 81 } 82 } 83 84 void EventSelectionSet::SetEnableOnExec(bool enable) { 85 for (auto& selection : selections_) { 86 // If sampling is enabled on exec, then it is disabled at startup, otherwise 87 // it should be enabled at startup. Don't use ioctl(PERF_EVENT_IOC_ENABLE) 88 // to enable it after perf_event_open(). Because some android kernels can't 89 // handle ioctl() well when cpu-hotplug happens. See http://b/25193162. 90 if (enable) { 91 selection.event_attr.enable_on_exec = 1; 92 selection.event_attr.disabled = 1; 93 } else { 94 selection.event_attr.enable_on_exec = 0; 95 selection.event_attr.disabled = 0; 96 } 97 } 98 } 99 100 bool EventSelectionSet::GetEnableOnExec() { 101 for (auto& selection : selections_) { 102 if (selection.event_attr.enable_on_exec == 0) { 103 return false; 104 } 105 } 106 return true; 107 } 108 109 void EventSelectionSet::SampleIdAll() { 110 for (auto& selection : selections_) { 111 selection.event_attr.sample_id_all = 1; 112 } 113 } 114 115 void EventSelectionSet::SetSampleFreq(uint64_t sample_freq) { 116 for (auto& selection : selections_) { 117 perf_event_attr& attr = selection.event_attr; 118 attr.freq = 1; 119 attr.sample_freq = sample_freq; 120 } 121 } 122 123 void EventSelectionSet::SetSamplePeriod(uint64_t sample_period) { 124 for (auto& selection : selections_) { 125 perf_event_attr& attr = selection.event_attr; 126 attr.freq = 0; 127 attr.sample_period = sample_period; 128 } 129 } 130 131 bool EventSelectionSet::SetBranchSampling(uint64_t branch_sample_type) { 132 if (branch_sample_type != 0 && 133 (branch_sample_type & (PERF_SAMPLE_BRANCH_ANY | PERF_SAMPLE_BRANCH_ANY_CALL | 134 PERF_SAMPLE_BRANCH_ANY_RETURN | PERF_SAMPLE_BRANCH_IND_CALL)) == 0) { 135 LOG(ERROR) << "Invalid branch_sample_type: 0x" << std::hex << branch_sample_type; 136 return false; 137 } 138 if (branch_sample_type != 0 && !IsBranchSamplingSupported()) { 139 LOG(ERROR) << "branch stack sampling is not supported on this device."; 140 return false; 141 } 142 for (auto& selection : selections_) { 143 perf_event_attr& attr = selection.event_attr; 144 if (branch_sample_type != 0) { 145 attr.sample_type |= PERF_SAMPLE_BRANCH_STACK; 146 } else { 147 attr.sample_type &= ~PERF_SAMPLE_BRANCH_STACK; 148 } 149 attr.branch_sample_type = branch_sample_type; 150 } 151 return true; 152 } 153 154 void EventSelectionSet::EnableFpCallChainSampling() { 155 for (auto& selection : selections_) { 156 selection.event_attr.sample_type |= PERF_SAMPLE_CALLCHAIN; 157 } 158 } 159 160 bool EventSelectionSet::EnableDwarfCallChainSampling(uint32_t dump_stack_size) { 161 if (!IsDwarfCallChainSamplingSupported()) { 162 LOG(ERROR) << "dwarf callchain sampling is not supported on this device."; 163 return false; 164 } 165 for (auto& selection : selections_) { 166 selection.event_attr.sample_type |= 167 PERF_SAMPLE_CALLCHAIN | PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER; 168 selection.event_attr.exclude_callchain_user = 1; 169 selection.event_attr.sample_regs_user = GetSupportedRegMask(GetBuildArch()); 170 selection.event_attr.sample_stack_user = dump_stack_size; 171 } 172 return true; 173 } 174 175 void EventSelectionSet::SetInherit(bool enable) { 176 for (auto& selection : selections_) { 177 selection.event_attr.inherit = (enable ? 1 : 0); 178 } 179 } 180 181 static bool CheckIfCpusOnline(const std::vector<int>& cpus) { 182 std::vector<int> online_cpus = GetOnlineCpus(); 183 for (const auto& cpu : cpus) { 184 if (std::find(online_cpus.begin(), online_cpus.end(), cpu) == online_cpus.end()) { 185 LOG(ERROR) << "cpu " << cpu << " is not online."; 186 return false; 187 } 188 } 189 return true; 190 } 191 192 bool EventSelectionSet::OpenEventFilesForCpus(const std::vector<int>& cpus) { 193 return OpenEventFilesForThreadsOnCpus({-1}, cpus); 194 } 195 196 bool EventSelectionSet::OpenEventFilesForThreadsOnCpus(const std::vector<pid_t>& threads, 197 std::vector<int> cpus) { 198 if (!cpus.empty()) { 199 if (!CheckIfCpusOnline(cpus)) { 200 return false; 201 } 202 } else { 203 cpus = GetOnlineCpus(); 204 } 205 return OpenEventFiles(threads, cpus); 206 } 207 208 bool EventSelectionSet::OpenEventFiles(const std::vector<pid_t>& threads, 209 const std::vector<int>& cpus) { 210 for (auto& selection : selections_) { 211 for (auto& tid : threads) { 212 size_t open_per_thread = 0; 213 for (auto& cpu : cpus) { 214 auto event_fd = EventFd::OpenEventFile(selection.event_attr, tid, cpu); 215 if (event_fd != nullptr) { 216 LOG(VERBOSE) << "OpenEventFile for tid " << tid << ", cpu " << cpu; 217 selection.event_fds.push_back(std::move(event_fd)); 218 ++open_per_thread; 219 } 220 } 221 // As the online cpus can be enabled or disabled at runtime, we may not open event file for 222 // all cpus successfully. But we should open at least one cpu successfully. 223 if (open_per_thread == 0) { 224 PLOG(ERROR) << "failed to open perf event file for event_type " 225 << selection.event_type_modifier.name << " for " 226 << (tid == -1 ? "all threads" : android::base::StringPrintf(" thread %d", tid)); 227 return false; 228 } 229 } 230 } 231 return true; 232 } 233 234 bool EventSelectionSet::ReadCounters(std::vector<CountersInfo>* counters) { 235 counters->clear(); 236 for (auto& selection : selections_) { 237 CountersInfo counters_info; 238 counters_info.event_type = &selection.event_type_modifier; 239 for (auto& event_fd : selection.event_fds) { 240 CountersInfo::CounterInfo counter_info; 241 if (!event_fd->ReadCounter(&counter_info.counter)) { 242 return false; 243 } 244 counter_info.tid = event_fd->ThreadId(); 245 counter_info.cpu = event_fd->Cpu(); 246 counters_info.counters.push_back(counter_info); 247 } 248 counters->push_back(counters_info); 249 } 250 return true; 251 } 252 253 void EventSelectionSet::PreparePollForEventFiles(std::vector<pollfd>* pollfds) { 254 for (auto& selection : selections_) { 255 for (auto& event_fd : selection.event_fds) { 256 pollfd poll_fd; 257 event_fd->PreparePollForMmapData(&poll_fd); 258 pollfds->push_back(poll_fd); 259 } 260 } 261 } 262 263 bool EventSelectionSet::MmapEventFiles(size_t mmap_pages) { 264 for (auto& selection : selections_) { 265 for (auto& event_fd : selection.event_fds) { 266 if (!event_fd->MmapContent(mmap_pages)) { 267 return false; 268 } 269 } 270 } 271 return true; 272 } 273 274 static bool ReadMmapEventDataForFd(std::unique_ptr<EventFd>& event_fd, 275 std::function<bool(const char*, size_t)> callback, 276 bool* have_data) { 277 *have_data = false; 278 while (true) { 279 char* data; 280 size_t size = event_fd->GetAvailableMmapData(&data); 281 if (size == 0) { 282 break; 283 } 284 if (!callback(data, size)) { 285 return false; 286 } 287 *have_data = true; 288 } 289 return true; 290 } 291 292 bool EventSelectionSet::ReadMmapEventData(std::function<bool(const char*, size_t)> callback) { 293 for (auto& selection : selections_) { 294 for (auto& event_fd : selection.event_fds) { 295 while (true) { 296 bool have_data; 297 if (!ReadMmapEventDataForFd(event_fd, callback, &have_data)) { 298 return false; 299 } 300 if (!have_data) { 301 break; 302 } 303 } 304 } 305 } 306 return true; 307 } 308 309 EventSelectionSet::EventSelection* EventSelectionSet::FindSelectionByType( 310 const EventTypeAndModifier& event_type_modifier) { 311 for (auto& selection : selections_) { 312 if (selection.event_type_modifier.name == event_type_modifier.name) { 313 return &selection; 314 } 315 } 316 return nullptr; 317 } 318 319 const perf_event_attr* EventSelectionSet::FindEventAttrByType( 320 const EventTypeAndModifier& event_type_modifier) { 321 EventSelection* selection = FindSelectionByType(event_type_modifier); 322 return (selection != nullptr) ? &selection->event_attr : nullptr; 323 } 324 325 const std::vector<std::unique_ptr<EventFd>>* EventSelectionSet::FindEventFdsByType( 326 const EventTypeAndModifier& event_type_modifier) { 327 EventSelection* selection = FindSelectionByType(event_type_modifier); 328 return (selection != nullptr) ? &selection->event_fds : nullptr; 329 } 330