event_selection_set.cpp revision 003b245939bae5e86ed53b3c6b333637dbc571b4
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 21#include "environment.h" 22#include "event_attr.h" 23#include "event_type.h" 24#include "IOEventLoop.h" 25#include "perf_regs.h" 26#include "utils.h" 27 28constexpr uint64_t DEFAULT_SAMPLE_FREQ_FOR_NONTRACEPOINT_EVENT = 4000; 29constexpr uint64_t DEFAULT_SAMPLE_PERIOD_FOR_TRACEPOINT_EVENT = 1; 30 31bool IsBranchSamplingSupported() { 32 const EventType* type = FindEventTypeByName("cpu-cycles"); 33 if (type == nullptr) { 34 return false; 35 } 36 perf_event_attr attr = CreateDefaultPerfEventAttr(*type); 37 attr.sample_type |= PERF_SAMPLE_BRANCH_STACK; 38 attr.branch_sample_type = PERF_SAMPLE_BRANCH_ANY; 39 return IsEventAttrSupportedByKernel(attr); 40} 41 42bool IsDwarfCallChainSamplingSupported() { 43 const EventType* type = FindEventTypeByName("cpu-cycles"); 44 if (type == nullptr) { 45 return false; 46 } 47 perf_event_attr attr = CreateDefaultPerfEventAttr(*type); 48 attr.sample_type |= 49 PERF_SAMPLE_CALLCHAIN | PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER; 50 attr.exclude_callchain_user = 1; 51 attr.sample_regs_user = GetSupportedRegMask(GetBuildArch()); 52 attr.sample_stack_user = 8192; 53 return IsEventAttrSupportedByKernel(attr); 54} 55 56bool EventSelectionSet::BuildAndCheckEventSelection( 57 const std::string& event_name, EventSelection* selection) { 58 std::unique_ptr<EventTypeAndModifier> event_type = ParseEventType(event_name); 59 if (event_type == nullptr) { 60 return false; 61 } 62 if (for_stat_cmd_) { 63 if (event_type->event_type.name == "cpu-clock" || 64 event_type->event_type.name == "task-clock") { 65 if (event_type->exclude_user || event_type->exclude_kernel) { 66 LOG(ERROR) << "Modifier u and modifier k used in event type " 67 << event_type->event_type.name 68 << " are not supported by the kernel."; 69 return false; 70 } 71 } 72 } 73 selection->event_type_modifier = *event_type; 74 selection->event_attr = CreateDefaultPerfEventAttr(event_type->event_type); 75 selection->event_attr.exclude_user = event_type->exclude_user; 76 selection->event_attr.exclude_kernel = event_type->exclude_kernel; 77 selection->event_attr.exclude_hv = event_type->exclude_hv; 78 selection->event_attr.exclude_host = event_type->exclude_host; 79 selection->event_attr.exclude_guest = event_type->exclude_guest; 80 selection->event_attr.precise_ip = event_type->precise_ip; 81 if (!IsEventAttrSupportedByKernel(selection->event_attr)) { 82 LOG(ERROR) << "Event type '" << event_type->name 83 << "' is not supported by the kernel"; 84 return false; 85 } 86 selection->event_fds.clear(); 87 88 for (const auto& group : groups_) { 89 for (const auto& sel : group) { 90 if (sel.event_type_modifier.name == selection->event_type_modifier.name) { 91 LOG(ERROR) << "Event type '" << sel.event_type_modifier.name 92 << "' appears more than once"; 93 return false; 94 } 95 } 96 } 97 return true; 98} 99 100bool EventSelectionSet::AddEventType(const std::string& event_name) { 101 return AddEventGroup(std::vector<std::string>(1, event_name)); 102} 103 104bool EventSelectionSet::AddEventGroup( 105 const std::vector<std::string>& event_names) { 106 EventSelectionGroup group; 107 for (const auto& event_name : event_names) { 108 EventSelection selection; 109 if (!BuildAndCheckEventSelection(event_name, &selection)) { 110 return false; 111 } 112 group.push_back(std::move(selection)); 113 } 114 groups_.push_back(std::move(group)); 115 UnionSampleType(); 116 return true; 117} 118 119std::vector<const EventType*> EventSelectionSet::GetTracepointEvents() const { 120 std::vector<const EventType*> result; 121 for (const auto& group : groups_) { 122 for (const auto& selection : group) { 123 if (selection.event_type_modifier.event_type.type == 124 PERF_TYPE_TRACEPOINT) { 125 result.push_back(&selection.event_type_modifier.event_type); 126 } 127 } 128 } 129 return result; 130} 131 132std::vector<EventAttrWithId> EventSelectionSet::GetEventAttrWithId() const { 133 std::vector<EventAttrWithId> result; 134 for (const auto& group : groups_) { 135 for (const auto& selection : group) { 136 EventAttrWithId attr_id; 137 attr_id.attr = &selection.event_attr; 138 for (const auto& fd : selection.event_fds) { 139 attr_id.ids.push_back(fd->Id()); 140 } 141 result.push_back(attr_id); 142 } 143 } 144 return result; 145} 146 147// Union the sample type of different event attrs can make reading sample 148// records in perf.data easier. 149void EventSelectionSet::UnionSampleType() { 150 uint64_t sample_type = 0; 151 for (const auto& group : groups_) { 152 for (const auto& selection : group) { 153 sample_type |= selection.event_attr.sample_type; 154 } 155 } 156 for (auto& group : groups_) { 157 for (auto& selection : group) { 158 selection.event_attr.sample_type = sample_type; 159 } 160 } 161} 162 163void EventSelectionSet::SetEnableOnExec(bool enable) { 164 for (auto& group : groups_) { 165 for (auto& selection : group) { 166 // If sampling is enabled on exec, then it is disabled at startup, 167 // otherwise it should be enabled at startup. Don't use 168 // ioctl(PERF_EVENT_IOC_ENABLE) to enable it after perf_event_open(). 169 // Because some android kernels can't handle ioctl() well when cpu-hotplug 170 // happens. See http://b/25193162. 171 if (enable) { 172 selection.event_attr.enable_on_exec = 1; 173 selection.event_attr.disabled = 1; 174 } else { 175 selection.event_attr.enable_on_exec = 0; 176 selection.event_attr.disabled = 0; 177 } 178 } 179 } 180} 181 182bool EventSelectionSet::GetEnableOnExec() { 183 for (const auto& group : groups_) { 184 for (const auto& selection : group) { 185 if (selection.event_attr.enable_on_exec == 0) { 186 return false; 187 } 188 } 189 } 190 return true; 191} 192 193void EventSelectionSet::SampleIdAll() { 194 for (auto& group : groups_) { 195 for (auto& selection : group) { 196 selection.event_attr.sample_id_all = 1; 197 } 198 } 199} 200 201void EventSelectionSet::SetSampleFreq(uint64_t sample_freq) { 202 for (auto& group : groups_) { 203 for (auto& selection : group) { 204 selection.event_attr.freq = 1; 205 selection.event_attr.sample_freq = sample_freq; 206 } 207 } 208} 209 210void EventSelectionSet::SetSamplePeriod(uint64_t sample_period) { 211 for (auto& group : groups_) { 212 for (auto& selection : group) { 213 selection.event_attr.freq = 0; 214 selection.event_attr.sample_period = sample_period; 215 } 216 } 217} 218 219void EventSelectionSet::UseDefaultSampleFreq() { 220 for (auto& group : groups_) { 221 for (auto& selection : group) { 222 if (selection.event_type_modifier.event_type.type == 223 PERF_TYPE_TRACEPOINT) { 224 selection.event_attr.freq = 0; 225 selection.event_attr.sample_period = 226 DEFAULT_SAMPLE_PERIOD_FOR_TRACEPOINT_EVENT; 227 } else { 228 selection.event_attr.freq = 1; 229 selection.event_attr.sample_freq = 230 DEFAULT_SAMPLE_FREQ_FOR_NONTRACEPOINT_EVENT; 231 } 232 } 233 } 234} 235 236bool EventSelectionSet::SetBranchSampling(uint64_t branch_sample_type) { 237 if (branch_sample_type != 0 && 238 (branch_sample_type & 239 (PERF_SAMPLE_BRANCH_ANY | PERF_SAMPLE_BRANCH_ANY_CALL | 240 PERF_SAMPLE_BRANCH_ANY_RETURN | PERF_SAMPLE_BRANCH_IND_CALL)) == 0) { 241 LOG(ERROR) << "Invalid branch_sample_type: 0x" << std::hex 242 << branch_sample_type; 243 return false; 244 } 245 if (branch_sample_type != 0 && !IsBranchSamplingSupported()) { 246 LOG(ERROR) << "branch stack sampling is not supported on this device."; 247 return false; 248 } 249 for (auto& group : groups_) { 250 for (auto& selection : group) { 251 perf_event_attr& attr = selection.event_attr; 252 if (branch_sample_type != 0) { 253 attr.sample_type |= PERF_SAMPLE_BRANCH_STACK; 254 } else { 255 attr.sample_type &= ~PERF_SAMPLE_BRANCH_STACK; 256 } 257 attr.branch_sample_type = branch_sample_type; 258 } 259 } 260 return true; 261} 262 263void EventSelectionSet::EnableFpCallChainSampling() { 264 for (auto& group : groups_) { 265 for (auto& selection : group) { 266 selection.event_attr.sample_type |= PERF_SAMPLE_CALLCHAIN; 267 } 268 } 269} 270 271bool EventSelectionSet::EnableDwarfCallChainSampling(uint32_t dump_stack_size) { 272 if (!IsDwarfCallChainSamplingSupported()) { 273 LOG(ERROR) << "dwarf callchain sampling is not supported on this device."; 274 return false; 275 } 276 for (auto& group : groups_) { 277 for (auto& selection : group) { 278 selection.event_attr.sample_type |= PERF_SAMPLE_CALLCHAIN | 279 PERF_SAMPLE_REGS_USER | 280 PERF_SAMPLE_STACK_USER; 281 selection.event_attr.exclude_callchain_user = 1; 282 selection.event_attr.sample_regs_user = 283 GetSupportedRegMask(GetBuildArch()); 284 selection.event_attr.sample_stack_user = dump_stack_size; 285 } 286 } 287 return true; 288} 289 290void EventSelectionSet::SetInherit(bool enable) { 291 for (auto& group : groups_) { 292 for (auto& selection : group) { 293 selection.event_attr.inherit = (enable ? 1 : 0); 294 } 295 } 296} 297 298void EventSelectionSet::SetLowWatermark() { 299 for (auto& group : groups_) { 300 for (auto& selection : group) { 301 selection.event_attr.wakeup_events = 1; 302 } 303 } 304} 305 306bool EventSelectionSet::NeedKernelSymbol() const { 307 for (const auto& group : groups_) { 308 for (const auto& selection : group) { 309 if (!selection.event_type_modifier.exclude_kernel) { 310 return true; 311 } 312 } 313 } 314 return false; 315} 316 317static bool CheckIfCpusOnline(const std::vector<int>& cpus) { 318 std::vector<int> online_cpus = GetOnlineCpus(); 319 for (const auto& cpu : cpus) { 320 if (std::find(online_cpus.begin(), online_cpus.end(), cpu) == 321 online_cpus.end()) { 322 LOG(ERROR) << "cpu " << cpu << " is not online."; 323 return false; 324 } 325 } 326 return true; 327} 328 329bool EventSelectionSet::OpenEventFilesOnGroup(EventSelectionGroup& group, 330 pid_t tid, int cpu, 331 std::string* failed_event_type) { 332 std::vector<std::unique_ptr<EventFd>> event_fds; 333 // Given a tid and cpu, events on the same group should be all opened 334 // successfully or all failed to open. 335 EventFd* group_fd = nullptr; 336 for (auto& selection : group) { 337 std::unique_ptr<EventFd> event_fd = 338 EventFd::OpenEventFile(selection.event_attr, tid, cpu, group_fd); 339 if (event_fd != nullptr) { 340 LOG(VERBOSE) << "OpenEventFile for " << event_fd->Name(); 341 event_fds.push_back(std::move(event_fd)); 342 } else { 343 if (failed_event_type != nullptr) { 344 *failed_event_type = selection.event_type_modifier.name; 345 return false; 346 } 347 } 348 if (group_fd == nullptr) { 349 group_fd = event_fd.get(); 350 } 351 } 352 for (size_t i = 0; i < group.size(); ++i) { 353 group[i].event_fds.push_back(std::move(event_fds[i])); 354 } 355 return true; 356} 357 358static std::set<pid_t> PrepareThreads(const std::set<pid_t>& processes, 359 const std::set<pid_t>& threads) { 360 std::set<pid_t> result = threads; 361 for (const auto& pid : processes) { 362 std::vector<pid_t> tids = GetThreadsInProcess(pid); 363 result.insert(tids.begin(), tids.end()); 364 } 365 return result; 366} 367 368bool EventSelectionSet::OpenEventFiles(const std::vector<int>& on_cpus) { 369 std::vector<int> cpus = on_cpus; 370 if (!cpus.empty()) { 371 // cpus = {-1} means open an event file for all cpus. 372 if (!(cpus.size() == 1 && cpus[0] == -1) && !CheckIfCpusOnline(cpus)) { 373 return false; 374 } 375 } else { 376 cpus = GetOnlineCpus(); 377 } 378 std::set<pid_t> threads = PrepareThreads(processes_, threads_); 379 for (auto& group : groups_) { 380 for (const auto& tid : threads) { 381 size_t success_cpu_count = 0; 382 std::string failed_event_type; 383 for (const auto& cpu : cpus) { 384 if (OpenEventFilesOnGroup(group, tid, cpu, &failed_event_type)) { 385 success_cpu_count++; 386 } 387 } 388 // As the online cpus can be enabled or disabled at runtime, we may not 389 // open event file for all cpus successfully. But we should open at 390 // least one cpu successfully. 391 if (success_cpu_count == 0) { 392 PLOG(ERROR) << "failed to open perf event file for event_type " 393 << failed_event_type << " for " 394 << (tid == -1 ? "all threads" 395 : "thread " + std::to_string(tid)) 396 << " on all cpus"; 397 return false; 398 } 399 } 400 } 401 return true; 402} 403 404static bool ReadCounter(const EventFd* event_fd, CounterInfo* counter) { 405 if (!event_fd->ReadCounter(&counter->counter)) { 406 return false; 407 } 408 counter->tid = event_fd->ThreadId(); 409 counter->cpu = event_fd->Cpu(); 410 return true; 411} 412 413bool EventSelectionSet::ReadCounters(std::vector<CountersInfo>* counters) { 414 counters->clear(); 415 for (size_t i = 0; i < groups_.size(); ++i) { 416 for (auto& selection : groups_[i]) { 417 CountersInfo counters_info; 418 counters_info.group_id = i; 419 counters_info.event_name = selection.event_type_modifier.event_type.name; 420 counters_info.event_modifier = selection.event_type_modifier.modifier; 421 counters_info.counters = selection.hotplugged_counters; 422 for (auto& event_fd : selection.event_fds) { 423 CounterInfo counter; 424 if (!ReadCounter(event_fd.get(), &counter)) { 425 return false; 426 } 427 counters_info.counters.push_back(counter); 428 } 429 counters->push_back(counters_info); 430 } 431 } 432 return true; 433} 434 435bool EventSelectionSet::MmapEventFiles(size_t min_mmap_pages, 436 size_t max_mmap_pages) { 437 for (size_t i = max_mmap_pages; i >= min_mmap_pages; i >>= 1) { 438 if (MmapEventFiles(i, i == min_mmap_pages)) { 439 LOG(VERBOSE) << "Mapped buffer size is " << i << " pages."; 440 mmap_pages_ = i; 441 return true; 442 } 443 for (auto& group : groups_) { 444 for (auto& selection : group) { 445 for (auto& event_fd : selection.event_fds) { 446 event_fd->DestroyMappedBuffer(); 447 } 448 } 449 } 450 } 451 return false; 452} 453 454bool EventSelectionSet::MmapEventFiles(size_t mmap_pages, bool report_error) { 455 // Allocate a mapped buffer for each cpu. 456 std::map<int, EventFd*> cpu_map; 457 for (auto& group : groups_) { 458 for (auto& selection : group) { 459 for (auto& event_fd : selection.event_fds) { 460 auto it = cpu_map.find(event_fd->Cpu()); 461 if (it != cpu_map.end()) { 462 if (!event_fd->ShareMappedBuffer(*(it->second), report_error)) { 463 return false; 464 } 465 } else { 466 if (!event_fd->CreateMappedBuffer(mmap_pages, report_error)) { 467 return false; 468 } 469 cpu_map[event_fd->Cpu()] = event_fd.get(); 470 } 471 } 472 } 473 } 474 return true; 475} 476 477bool EventSelectionSet::PrepareToReadMmapEventData( 478 IOEventLoop& loop, const std::function<bool(Record*)>& callback) { 479 // Add read Events for perf event files having mapped buffer. 480 for (auto& group : groups_) { 481 for (auto& selection : group) { 482 for (auto& event_fd : selection.event_fds) { 483 if (event_fd->HasMappedBuffer()) { 484 if (!event_fd->StartPolling(loop, [&]() { 485 return ReadMmapEventDataForFd(event_fd.get()); 486 })) { 487 return false; 488 } 489 } 490 } 491 } 492 } 493 loop_ = &loop; 494 495 // Prepare record callback function. 496 record_callback_ = callback; 497 return true; 498} 499 500bool EventSelectionSet::ReadMmapEventDataForFd(EventFd* event_fd) { 501 const char* data; 502 // Call GetAvailableMmapData() only once instead of calling in a loop, because 503 // 1) A mapped buffer caches data before needing to be read again. By default 504 // it raises read Event when half full. 505 // 2) Spinning on one mapped buffer can make other mapped buffers overflow. 506 size_t size = event_fd->GetAvailableMmapData(&data); 507 if (size == 0) { 508 return true; 509 } 510 std::vector<std::unique_ptr<Record>> records = 511 ReadRecordsFromBuffer(event_fd->attr(), data, size); 512 for (auto& r : records) { 513 if (!record_callback_(r.get())) { 514 return false; 515 } 516 } 517 return true; 518} 519 520bool EventSelectionSet::FinishReadMmapEventData() { 521 // Read each mapped buffer once, because some data may exist in the buffers 522 // but is not much enough to raise read Events. 523 for (auto& group : groups_) { 524 for (auto& selection : group) { 525 for (auto& event_fd : selection.event_fds) { 526 if (event_fd->HasMappedBuffer()) { 527 if (!ReadMmapEventDataForFd(event_fd.get())) { 528 return false; 529 } 530 } 531 } 532 } 533 } 534 return true; 535} 536 537bool EventSelectionSet::HandleCpuHotplugEvents( 538 IOEventLoop& loop, const std::vector<int>& monitored_cpus, 539 double check_interval_in_sec) { 540 monitored_cpus_.insert(monitored_cpus.begin(), monitored_cpus.end()); 541 online_cpus_ = GetOnlineCpus(); 542 if (!loop.AddPeriodicEvent(SecondToTimeval(check_interval_in_sec), 543 [&]() { return DetectCpuHotplugEvents(); })) { 544 return false; 545 } 546 return true; 547} 548 549bool EventSelectionSet::DetectCpuHotplugEvents() { 550 std::vector<int> new_cpus = GetOnlineCpus(); 551 for (const auto& cpu : online_cpus_) { 552 if (std::find(new_cpus.begin(), new_cpus.end(), cpu) == new_cpus.end()) { 553 if (monitored_cpus_.empty() || 554 monitored_cpus_.find(cpu) != monitored_cpus_.end()) { 555 LOG(INFO) << "Cpu " << cpu << " is offlined"; 556 if (!HandleCpuOfflineEvent(cpu)) { 557 return false; 558 } 559 } 560 } 561 } 562 for (const auto& cpu : new_cpus) { 563 if (std::find(online_cpus_.begin(), online_cpus_.end(), cpu) == 564 online_cpus_.end()) { 565 if (monitored_cpus_.empty() || 566 monitored_cpus_.find(cpu) != monitored_cpus_.end()) { 567 LOG(INFO) << "Cpu " << cpu << " is onlined"; 568 if (!HandleCpuOnlineEvent(cpu)) { 569 return false; 570 } 571 } 572 } 573 } 574 online_cpus_ = new_cpus; 575 return true; 576} 577 578bool EventSelectionSet::HandleCpuOfflineEvent(int cpu) { 579 for (auto& group : groups_) { 580 for (auto& selection : group) { 581 for (auto it = selection.event_fds.begin(); 582 it != selection.event_fds.end();) { 583 if ((*it)->Cpu() == cpu) { 584 if (for_stat_cmd_) { 585 CounterInfo counter; 586 if (!ReadCounter(it->get(), &counter)) { 587 return false; 588 } 589 selection.hotplugged_counters.push_back(counter); 590 } else { 591 if ((*it)->HasMappedBuffer()) { 592 if (!ReadMmapEventDataForFd(it->get())) { 593 return false; 594 } 595 if (!(*it)->StopPolling()) { 596 return false; 597 } 598 } 599 } 600 it = selection.event_fds.erase(it); 601 } else { 602 ++it; 603 } 604 } 605 } 606 } 607 return true; 608} 609 610bool EventSelectionSet::HandleCpuOnlineEvent(int cpu) { 611 // We need to start profiling when opening new event files. 612 SetEnableOnExec(false); 613 std::set<pid_t> threads = PrepareThreads(processes_, threads_); 614 for (auto& group : groups_) { 615 for (const auto& tid : threads) { 616 std::string failed_event_type; 617 if (!OpenEventFilesOnGroup(group, tid, cpu, &failed_event_type)) { 618 // If failed to open event files, maybe the cpu has been offlined. 619 PLOG(WARNING) << "failed to open perf event file for event_type " 620 << failed_event_type << " for " 621 << (tid == -1 ? "all threads" 622 : "thread " + std::to_string(tid)) 623 << " on cpu " << cpu; 624 } 625 } 626 } 627 if (!for_stat_cmd_) { 628 // Prepare mapped buffer. 629 if (!CreateMappedBufferForCpu(cpu)) { 630 return false; 631 } 632 // Send a EventIdRecord. 633 std::vector<uint64_t> event_id_data; 634 uint64_t attr_id = 0; 635 for (const auto& group : groups_) { 636 for (const auto& selection : group) { 637 for (const auto& event_fd : selection.event_fds) { 638 if (event_fd->Cpu() == cpu) { 639 event_id_data.push_back(attr_id); 640 event_id_data.push_back(event_fd->Id()); 641 } 642 } 643 ++attr_id; 644 } 645 } 646 EventIdRecord r(event_id_data); 647 if (!record_callback_(&r)) { 648 return false; 649 } 650 } 651 return true; 652} 653 654bool EventSelectionSet::CreateMappedBufferForCpu(int cpu) { 655 EventFd* fd_with_buffer = nullptr; 656 for (auto& group : groups_) { 657 for (auto& selection : group) { 658 for (auto& event_fd : selection.event_fds) { 659 if (event_fd->Cpu() != cpu) { 660 continue; 661 } 662 if (fd_with_buffer == nullptr) { 663 if (!event_fd->CreateMappedBuffer(mmap_pages_, true)) { 664 return false; 665 } 666 fd_with_buffer = event_fd.get(); 667 } else { 668 if (!event_fd->ShareMappedBuffer(*fd_with_buffer, true)) { 669 fd_with_buffer->DestroyMappedBuffer(); 670 return false; 671 } 672 } 673 } 674 } 675 } 676 if (fd_with_buffer != nullptr && 677 !fd_with_buffer->StartPolling(*loop_, [this, fd_with_buffer]() { 678 return ReadMmapEventDataForFd(fd_with_buffer); 679 })) { 680 return false; 681 } 682 return true; 683} 684