event_selection_set.cpp revision 4cf37d1583a605785b7677c1935ce316c2097fa2
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 "IOEventLoop.h" 26#include "perf_regs.h" 27#include "utils.h" 28 29bool 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 40bool 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 |= 47 PERF_SAMPLE_CALLCHAIN | PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER; 48 attr.exclude_callchain_user = 1; 49 attr.sample_regs_user = GetSupportedRegMask(GetBuildArch()); 50 attr.sample_stack_user = 8192; 51 return IsEventAttrSupportedByKernel(attr); 52} 53 54bool EventSelectionSet::BuildAndCheckEventSelection( 55 const std::string& event_name, EventSelection* selection) { 56 std::unique_ptr<EventTypeAndModifier> event_type = ParseEventType(event_name); 57 if (event_type == nullptr) { 58 return false; 59 } 60 if (for_stat_cmd_) { 61 if (event_type->event_type.name == "cpu-clock" || 62 event_type->event_type.name == "task-clock") { 63 if (event_type->exclude_user || event_type->exclude_kernel) { 64 LOG(ERROR) << "Modifier u and modifier k used in event type " 65 << event_type->event_type.name 66 << " are not supported by the kernel."; 67 return false; 68 } 69 } 70 } 71 selection->event_type_modifier = *event_type; 72 selection->event_attr = CreateDefaultPerfEventAttr(event_type->event_type); 73 selection->event_attr.exclude_user = event_type->exclude_user; 74 selection->event_attr.exclude_kernel = event_type->exclude_kernel; 75 selection->event_attr.exclude_hv = event_type->exclude_hv; 76 selection->event_attr.exclude_host = event_type->exclude_host; 77 selection->event_attr.exclude_guest = event_type->exclude_guest; 78 selection->event_attr.precise_ip = event_type->precise_ip; 79 if (!IsEventAttrSupportedByKernel(selection->event_attr)) { 80 LOG(ERROR) << "Event type '" << event_type->name 81 << "' is not supported by the kernel"; 82 return false; 83 } 84 selection->event_fds.clear(); 85 86 for (const auto& group : groups_) { 87 for (const auto& sel : group) { 88 if (sel.event_type_modifier.name == selection->event_type_modifier.name) { 89 LOG(ERROR) << "Event type '" << sel.event_type_modifier.name 90 << "' appears more than once"; 91 return false; 92 } 93 } 94 } 95 return true; 96} 97 98bool EventSelectionSet::AddEventType(const std::string& event_name) { 99 return AddEventGroup(std::vector<std::string>(1, event_name)); 100} 101 102bool EventSelectionSet::AddEventGroup( 103 const std::vector<std::string>& event_names) { 104 EventSelectionGroup group; 105 for (const auto& event_name : event_names) { 106 EventSelection selection; 107 if (!BuildAndCheckEventSelection(event_name, &selection)) { 108 return false; 109 } 110 selection.selection_id = group.size(); 111 selection.group_id = groups_.size(); 112 group.push_back(std::move(selection)); 113 } 114 groups_.push_back(std::move(group)); 115 UnionSampleType(); 116 return true; 117} 118 119// Union the sample type of different event attrs can make reading sample 120// records in perf.data easier. 121void EventSelectionSet::UnionSampleType() { 122 uint64_t sample_type = 0; 123 for (const auto& group : groups_) { 124 for (const auto& selection : group) { 125 sample_type |= selection.event_attr.sample_type; 126 } 127 } 128 for (auto& group : groups_) { 129 for (auto& selection : group) { 130 selection.event_attr.sample_type = sample_type; 131 } 132 } 133} 134 135void EventSelectionSet::SetEnableOnExec(bool enable) { 136 for (auto& group : groups_) { 137 for (auto& selection : group) { 138 // If sampling is enabled on exec, then it is disabled at startup, 139 // otherwise it should be enabled at startup. Don't use 140 // ioctl(PERF_EVENT_IOC_ENABLE) to enable it after perf_event_open(). 141 // Because some android kernels can't handle ioctl() well when cpu-hotplug 142 // happens. See http://b/25193162. 143 if (enable) { 144 selection.event_attr.enable_on_exec = 1; 145 selection.event_attr.disabled = 1; 146 } else { 147 selection.event_attr.enable_on_exec = 0; 148 selection.event_attr.disabled = 0; 149 } 150 } 151 } 152} 153 154bool EventSelectionSet::GetEnableOnExec() { 155 for (const auto& group : groups_) { 156 for (const auto& selection : group) { 157 if (selection.event_attr.enable_on_exec == 0) { 158 return false; 159 } 160 } 161 } 162 return true; 163} 164 165void EventSelectionSet::SampleIdAll() { 166 for (auto& group : groups_) { 167 for (auto& selection : group) { 168 selection.event_attr.sample_id_all = 1; 169 } 170 } 171} 172 173void EventSelectionSet::SetSampleFreq(const EventSelection& selection, 174 uint64_t sample_freq) { 175 EventSelection& sel = groups_[selection.group_id][selection.selection_id]; 176 sel.event_attr.freq = 1; 177 sel.event_attr.sample_freq = sample_freq; 178} 179 180void EventSelectionSet::SetSamplePeriod(const EventSelection& selection, 181 uint64_t sample_period) { 182 EventSelection& sel = groups_[selection.group_id][selection.selection_id]; 183 sel.event_attr.freq = 0; 184 sel.event_attr.sample_period = sample_period; 185} 186 187bool EventSelectionSet::SetBranchSampling(uint64_t branch_sample_type) { 188 if (branch_sample_type != 0 && 189 (branch_sample_type & 190 (PERF_SAMPLE_BRANCH_ANY | PERF_SAMPLE_BRANCH_ANY_CALL | 191 PERF_SAMPLE_BRANCH_ANY_RETURN | PERF_SAMPLE_BRANCH_IND_CALL)) == 0) { 192 LOG(ERROR) << "Invalid branch_sample_type: 0x" << std::hex 193 << branch_sample_type; 194 return false; 195 } 196 if (branch_sample_type != 0 && !IsBranchSamplingSupported()) { 197 LOG(ERROR) << "branch stack sampling is not supported on this device."; 198 return false; 199 } 200 for (auto& group : groups_) { 201 for (auto& selection : group) { 202 perf_event_attr& attr = selection.event_attr; 203 if (branch_sample_type != 0) { 204 attr.sample_type |= PERF_SAMPLE_BRANCH_STACK; 205 } else { 206 attr.sample_type &= ~PERF_SAMPLE_BRANCH_STACK; 207 } 208 attr.branch_sample_type = branch_sample_type; 209 } 210 } 211 return true; 212} 213 214void EventSelectionSet::EnableFpCallChainSampling() { 215 for (auto& group : groups_) { 216 for (auto& selection : group) { 217 selection.event_attr.sample_type |= PERF_SAMPLE_CALLCHAIN; 218 } 219 } 220} 221 222bool EventSelectionSet::EnableDwarfCallChainSampling(uint32_t dump_stack_size) { 223 if (!IsDwarfCallChainSamplingSupported()) { 224 LOG(ERROR) << "dwarf callchain sampling is not supported on this device."; 225 return false; 226 } 227 for (auto& group : groups_) { 228 for (auto& selection : group) { 229 selection.event_attr.sample_type |= PERF_SAMPLE_CALLCHAIN | 230 PERF_SAMPLE_REGS_USER | 231 PERF_SAMPLE_STACK_USER; 232 selection.event_attr.exclude_callchain_user = 1; 233 selection.event_attr.sample_regs_user = 234 GetSupportedRegMask(GetBuildArch()); 235 selection.event_attr.sample_stack_user = dump_stack_size; 236 } 237 } 238 return true; 239} 240 241void EventSelectionSet::SetInherit(bool enable) { 242 for (auto& group : groups_) { 243 for (auto& selection : group) { 244 selection.event_attr.inherit = (enable ? 1 : 0); 245 } 246 } 247} 248 249void EventSelectionSet::SetLowWatermark() { 250 for (auto& group : groups_) { 251 for (auto& selection : group) { 252 selection.event_attr.wakeup_events = 1; 253 } 254 } 255} 256 257static bool CheckIfCpusOnline(const std::vector<int>& cpus) { 258 std::vector<int> online_cpus = GetOnlineCpus(); 259 for (const auto& cpu : cpus) { 260 if (std::find(online_cpus.begin(), online_cpus.end(), cpu) == 261 online_cpus.end()) { 262 LOG(ERROR) << "cpu " << cpu << " is not online."; 263 return false; 264 } 265 } 266 return true; 267} 268 269bool EventSelectionSet::OpenEventFilesForCpus(const std::vector<int>& cpus) { 270 return OpenEventFilesForThreadsOnCpus({-1}, cpus); 271} 272 273bool EventSelectionSet::OpenEventFilesForThreadsOnCpus( 274 const std::vector<pid_t>& threads, std::vector<int> cpus) { 275 if (!cpus.empty()) { 276 // cpus = {-1} means open an event file for all cpus. 277 if (!(cpus.size() == 1 && cpus[0] == -1) && !CheckIfCpusOnline(cpus)) { 278 return false; 279 } 280 } else { 281 cpus = GetOnlineCpus(); 282 } 283 return OpenEventFiles(threads, cpus); 284} 285 286bool EventSelectionSet::OpenEventFiles(const std::vector<pid_t>& threads, 287 const std::vector<int>& cpus) { 288 for (auto& group : groups_) { 289 for (const auto& tid : threads) { 290 size_t open_per_thread = 0; 291 std::string failed_event_type; 292 for (const auto& cpu : cpus) { 293 std::vector<std::unique_ptr<EventFd>> event_fds; 294 // Given a tid and cpu, events on the same group should be all opened 295 // successfully or all failed to open. 296 for (auto& selection : group) { 297 EventFd* group_fd = nullptr; 298 if (selection.selection_id != 0) { 299 group_fd = event_fds[0].get(); 300 } 301 std::unique_ptr<EventFd> event_fd = 302 EventFd::OpenEventFile(selection.event_attr, tid, cpu, group_fd); 303 if (event_fd != nullptr) { 304 LOG(VERBOSE) << "OpenEventFile for " << event_fd->Name(); 305 event_fds.push_back(std::move(event_fd)); 306 } else { 307 failed_event_type = selection.event_type_modifier.name; 308 break; 309 } 310 } 311 if (event_fds.size() == group.size()) { 312 for (size_t i = 0; i < group.size(); ++i) { 313 group[i].event_fds.push_back(std::move(event_fds[i])); 314 } 315 ++open_per_thread; 316 } 317 } 318 // As the online cpus can be enabled or disabled at runtime, we may not 319 // open event file for all cpus successfully. But we should open at least 320 // one cpu successfully. 321 if (open_per_thread == 0) { 322 PLOG(ERROR) << "failed to open perf event file for event_type " 323 << failed_event_type << " for " 324 << (tid == -1 ? "all threads" : android::base::StringPrintf( 325 " thread %d", tid)); 326 return false; 327 } 328 } 329 } 330 return true; 331} 332 333bool EventSelectionSet::ReadCounters(std::vector<CountersInfo>* counters) { 334 counters->clear(); 335 for (auto& group : groups_) { 336 for (auto& selection : group) { 337 CountersInfo counters_info; 338 counters_info.selection = &selection; 339 for (auto& event_fd : selection.event_fds) { 340 CountersInfo::CounterInfo counter_info; 341 if (!event_fd->ReadCounter(&counter_info.counter)) { 342 return false; 343 } 344 counter_info.tid = event_fd->ThreadId(); 345 counter_info.cpu = event_fd->Cpu(); 346 counters_info.counters.push_back(counter_info); 347 } 348 counters->push_back(counters_info); 349 } 350 } 351 return true; 352} 353 354bool EventSelectionSet::MmapEventFiles(size_t min_mmap_pages, 355 size_t max_mmap_pages) { 356 for (size_t i = max_mmap_pages; i >= min_mmap_pages; i >>= 1) { 357 if (MmapEventFiles(i, i == min_mmap_pages)) { 358 LOG(VERBOSE) << "Mapped buffer size is " << i << " pages."; 359 return true; 360 } 361 for (auto& group : groups_) { 362 for (auto& selection : group) { 363 for (auto& event_fd : selection.event_fds) { 364 event_fd->DestroyMappedBuffer(); 365 } 366 } 367 } 368 } 369 return false; 370} 371 372bool EventSelectionSet::MmapEventFiles(size_t mmap_pages, bool report_error) { 373 for (auto& group : groups_) { 374 for (auto& selection : group) { 375 // For each event, allocate a mapped buffer for each cpu. 376 std::map<int, EventFd*> cpu_map; 377 for (auto& event_fd : selection.event_fds) { 378 auto it = cpu_map.find(event_fd->Cpu()); 379 if (it != cpu_map.end()) { 380 if (!event_fd->ShareMappedBuffer(*(it->second), report_error)) { 381 return false; 382 } 383 } else { 384 if (!event_fd->CreateMappedBuffer(mmap_pages, report_error)) { 385 return false; 386 } 387 cpu_map.insert(std::make_pair(event_fd->Cpu(), event_fd.get())); 388 } 389 } 390 } 391 } 392 return true; 393} 394 395bool EventSelectionSet::PrepareToReadMmapEventData( 396 IOEventLoop& loop, const std::function<bool(Record*)>& callback) { 397 // Add read Events for perf event files having mapped buffer. 398 for (auto& group : groups_) { 399 for (auto& selection : group) { 400 for (auto& event_fd : selection.event_fds) { 401 if (event_fd->HasMappedBuffer()) { 402 if (!loop.AddReadEvent(event_fd->fd(), [&]() { 403 return ReadMmapEventDataForFd(event_fd); 404 })) { 405 return false; 406 } 407 } 408 } 409 } 410 } 411 412 // Prepare record callback function. 413 record_callback_ = callback; 414 return true; 415} 416 417bool EventSelectionSet::ReadMmapEventDataForFd( 418 std::unique_ptr<EventFd>& event_fd) { 419 const char* data; 420 // Call GetAvailableMmapData() only once instead of calling in a loop, because 421 // 1) A mapped buffer caches data before needing to be read again. By default 422 // it raises read Event when half full. 423 // 2) Spinning on one mapped buffer can make other mapped buffers overflow. 424 size_t size = event_fd->GetAvailableMmapData(&data); 425 if (size == 0) { 426 return true; 427 } 428 std::vector<std::unique_ptr<Record>> records = 429 ReadRecordsFromBuffer(event_fd->attr(), data, size); 430 for (auto& r : records) { 431 if (!record_callback_(r.get())) { 432 return false; 433 } 434 } 435 return true; 436} 437 438bool EventSelectionSet::FinishReadMmapEventData() { 439 // Read each mapped buffer once, because some data may exist in the buffers 440 // but is not much enough to raise read Events. 441 for (auto& group : groups_) { 442 for (auto& selection : group) { 443 for (auto& event_fd : selection.event_fds) { 444 if (event_fd->HasMappedBuffer()) { 445 if (!ReadMmapEventDataForFd(event_fd)) { 446 return false; 447 } 448 } 449 } 450 } 451 } 452 return true; 453} 454 455bool EventSelectionSet::HandleCpuHotplugEvents( 456 IOEventLoop& loop, const std::vector<int>& monitored_cpus, 457 double check_interval_in_sec) { 458 monitored_cpus_.insert(monitored_cpus.begin(), monitored_cpus.end()); 459 online_cpus_ = GetOnlineCpus(); 460 if (!loop.AddPeriodicEvent(SecondToTimeval(check_interval_in_sec), 461 [&]() { return DetectCpuHotplugEvents(); })) { 462 return false; 463 } 464 return true; 465} 466 467bool EventSelectionSet::DetectCpuHotplugEvents() { 468 std::vector<int> new_cpus = GetOnlineCpus(); 469 for (const auto& cpu : online_cpus_) { 470 if (std::find(new_cpus.begin(), new_cpus.end(), cpu) == new_cpus.end()) { 471 if (monitored_cpus_.empty() || 472 monitored_cpus_.find(cpu) != monitored_cpus_.end()) { 473 LOG(INFO) << "Cpu " << cpu << " is offlined"; 474 } 475 } 476 } 477 for (const auto& cpu : new_cpus) { 478 if (std::find(online_cpus_.begin(), online_cpus_.end(), cpu) == 479 online_cpus_.end()) { 480 if (monitored_cpus_.empty() || 481 monitored_cpus_.find(cpu) != monitored_cpus_.end()) { 482 LOG(INFO) << "Cpu " << cpu << " is onlined"; 483 } 484 } 485 } 486 online_cpus_ = new_cpus; 487 return true; 488} 489