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 <algorithm> 20 #include <atomic> 21 #include <thread> 22 23 #include <android-base/logging.h> 24 25 #include "environment.h" 26 #include "event_attr.h" 27 #include "event_type.h" 28 #include "IOEventLoop.h" 29 #include "perf_regs.h" 30 #include "utils.h" 31 32 constexpr uint64_t DEFAULT_SAMPLE_FREQ_FOR_NONTRACEPOINT_EVENT = 4000; 33 constexpr uint64_t DEFAULT_SAMPLE_PERIOD_FOR_TRACEPOINT_EVENT = 1; 34 35 bool IsBranchSamplingSupported() { 36 const EventType* type = FindEventTypeByName("cpu-cycles"); 37 if (type == nullptr) { 38 return false; 39 } 40 perf_event_attr attr = CreateDefaultPerfEventAttr(*type); 41 attr.sample_type |= PERF_SAMPLE_BRANCH_STACK; 42 attr.branch_sample_type = PERF_SAMPLE_BRANCH_ANY; 43 return IsEventAttrSupported(attr); 44 } 45 46 bool IsDwarfCallChainSamplingSupported() { 47 const EventType* type = FindEventTypeByName("cpu-cycles"); 48 if (type == nullptr) { 49 return false; 50 } 51 perf_event_attr attr = CreateDefaultPerfEventAttr(*type); 52 attr.sample_type |= 53 PERF_SAMPLE_CALLCHAIN | PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER; 54 attr.exclude_callchain_user = 1; 55 attr.sample_regs_user = GetSupportedRegMask(GetBuildArch()); 56 attr.sample_stack_user = 8192; 57 return IsEventAttrSupported(attr); 58 } 59 60 bool IsDumpingRegsForTracepointEventsSupported() { 61 const EventType* event_type = FindEventTypeByName("sched:sched_switch", false); 62 if (event_type == nullptr) { 63 return false; 64 } 65 std::atomic<bool> done(false); 66 std::atomic<pid_t> thread_id(0); 67 std::thread thread([&]() { 68 thread_id = gettid(); 69 while (!done) { 70 usleep(1); 71 } 72 usleep(1); // Make a sched out to generate one sample. 73 }); 74 while (thread_id == 0) { 75 usleep(1); 76 } 77 perf_event_attr attr = CreateDefaultPerfEventAttr(*event_type); 78 attr.freq = 0; 79 attr.sample_period = 1; 80 std::unique_ptr<EventFd> event_fd = 81 EventFd::OpenEventFile(attr, thread_id, -1, nullptr); 82 if (event_fd == nullptr) { 83 return false; 84 } 85 if (!event_fd->CreateMappedBuffer(4, true)) { 86 return false; 87 } 88 done = true; 89 thread.join(); 90 91 std::vector<char> buffer; 92 size_t buffer_pos = 0; 93 size_t size = event_fd->GetAvailableMmapData(buffer, buffer_pos); 94 std::vector<std::unique_ptr<Record>> records = 95 ReadRecordsFromBuffer(attr, buffer.data(), size); 96 for (auto& r : records) { 97 if (r->type() == PERF_RECORD_SAMPLE) { 98 auto& record = *static_cast<SampleRecord*>(r.get()); 99 if (record.ip_data.ip != 0) { 100 return true; 101 } 102 } 103 } 104 return false; 105 } 106 107 bool IsSettingClockIdSupported() { 108 const EventType* type = FindEventTypeByName("cpu-cycles"); 109 if (type == nullptr) { 110 return false; 111 } 112 // Check if the kernel supports setting clockid, which was added in kernel 4.0. Just check with 113 // one clockid is enough. Because all needed clockids were supported before kernel 4.0. 114 perf_event_attr attr = CreateDefaultPerfEventAttr(*type); 115 attr.use_clockid = 1; 116 attr.clockid = CLOCK_MONOTONIC; 117 return IsEventAttrSupported(attr); 118 } 119 120 bool EventSelectionSet::BuildAndCheckEventSelection( 121 const std::string& event_name, EventSelection* selection) { 122 std::unique_ptr<EventTypeAndModifier> event_type = ParseEventType(event_name); 123 if (event_type == nullptr) { 124 return false; 125 } 126 if (for_stat_cmd_) { 127 if (event_type->event_type.name == "cpu-clock" || 128 event_type->event_type.name == "task-clock") { 129 if (event_type->exclude_user || event_type->exclude_kernel) { 130 LOG(ERROR) << "Modifier u and modifier k used in event type " 131 << event_type->event_type.name 132 << " are not supported by the kernel."; 133 return false; 134 } 135 } 136 } 137 selection->event_type_modifier = *event_type; 138 selection->event_attr = CreateDefaultPerfEventAttr(event_type->event_type); 139 selection->event_attr.exclude_user = event_type->exclude_user; 140 selection->event_attr.exclude_kernel = event_type->exclude_kernel; 141 selection->event_attr.exclude_hv = event_type->exclude_hv; 142 selection->event_attr.exclude_host = event_type->exclude_host; 143 selection->event_attr.exclude_guest = event_type->exclude_guest; 144 selection->event_attr.precise_ip = event_type->precise_ip; 145 if (!for_stat_cmd_) { 146 if (event_type->event_type.type == PERF_TYPE_TRACEPOINT) { 147 selection->event_attr.freq = 0; 148 selection->event_attr.sample_period = DEFAULT_SAMPLE_PERIOD_FOR_TRACEPOINT_EVENT; 149 } else { 150 selection->event_attr.freq = 1; 151 uint64_t freq = DEFAULT_SAMPLE_FREQ_FOR_NONTRACEPOINT_EVENT; 152 uint64_t max_freq; 153 if (GetMaxSampleFrequency(&max_freq)) { 154 freq = std::min(freq, max_freq); 155 } 156 selection->event_attr.sample_freq = freq; 157 } 158 } 159 if (!IsEventAttrSupported(selection->event_attr)) { 160 LOG(ERROR) << "Event type '" << event_type->name 161 << "' is not supported on the device"; 162 return false; 163 } 164 selection->event_fds.clear(); 165 166 for (const auto& group : groups_) { 167 for (const auto& sel : group) { 168 if (sel.event_type_modifier.name == selection->event_type_modifier.name) { 169 LOG(ERROR) << "Event type '" << sel.event_type_modifier.name 170 << "' appears more than once"; 171 return false; 172 } 173 } 174 } 175 return true; 176 } 177 178 bool EventSelectionSet::AddEventType(const std::string& event_name, size_t* group_id) { 179 return AddEventGroup(std::vector<std::string>(1, event_name), group_id); 180 } 181 182 bool EventSelectionSet::AddEventGroup( 183 const std::vector<std::string>& event_names, size_t* group_id) { 184 EventSelectionGroup group; 185 for (const auto& event_name : event_names) { 186 EventSelection selection; 187 if (!BuildAndCheckEventSelection(event_name, &selection)) { 188 return false; 189 } 190 group.push_back(std::move(selection)); 191 } 192 groups_.push_back(std::move(group)); 193 UnionSampleType(); 194 if (group_id != nullptr) { 195 *group_id = groups_.size() - 1; 196 } 197 return true; 198 } 199 200 std::vector<const EventType*> EventSelectionSet::GetEvents() const { 201 std::vector<const EventType*> result; 202 for (const auto& group : groups_) { 203 for (const auto& selection : group) { 204 result.push_back(&selection.event_type_modifier.event_type); 205 } 206 } 207 return result; 208 } 209 210 std::vector<const EventType*> EventSelectionSet::GetTracepointEvents() const { 211 std::vector<const EventType*> result; 212 for (const auto& group : groups_) { 213 for (const auto& selection : group) { 214 if (selection.event_type_modifier.event_type.type == 215 PERF_TYPE_TRACEPOINT) { 216 result.push_back(&selection.event_type_modifier.event_type); 217 } 218 } 219 } 220 return result; 221 } 222 223 bool EventSelectionSet::ExcludeKernel() const { 224 for (const auto& group : groups_) { 225 for (const auto& selection : group) { 226 if (!selection.event_type_modifier.exclude_kernel) { 227 return false; 228 } 229 } 230 } 231 return true; 232 } 233 234 bool EventSelectionSet::HasInplaceSampler() const { 235 for (const auto& group : groups_) { 236 for (const auto& sel : group) { 237 if (sel.event_attr.type == SIMPLEPERF_TYPE_USER_SPACE_SAMPLERS && 238 sel.event_attr.config == SIMPLEPERF_CONFIG_INPLACE_SAMPLER) { 239 return true; 240 } 241 } 242 } 243 return false; 244 } 245 246 std::vector<EventAttrWithId> EventSelectionSet::GetEventAttrWithId() const { 247 std::vector<EventAttrWithId> result; 248 for (const auto& group : groups_) { 249 for (const auto& selection : group) { 250 EventAttrWithId attr_id; 251 attr_id.attr = &selection.event_attr; 252 for (const auto& fd : selection.event_fds) { 253 attr_id.ids.push_back(fd->Id()); 254 } 255 if (!selection.inplace_samplers.empty()) { 256 attr_id.ids.push_back(selection.inplace_samplers[0]->Id()); 257 } 258 result.push_back(attr_id); 259 } 260 } 261 return result; 262 } 263 264 // Union the sample type of different event attrs can make reading sample 265 // records in perf.data easier. 266 void EventSelectionSet::UnionSampleType() { 267 uint64_t sample_type = 0; 268 for (const auto& group : groups_) { 269 for (const auto& selection : group) { 270 sample_type |= selection.event_attr.sample_type; 271 } 272 } 273 for (auto& group : groups_) { 274 for (auto& selection : group) { 275 selection.event_attr.sample_type = sample_type; 276 } 277 } 278 } 279 280 void EventSelectionSet::SetEnableOnExec(bool enable) { 281 for (auto& group : groups_) { 282 for (auto& selection : group) { 283 // If sampling is enabled on exec, then it is disabled at startup, 284 // otherwise it should be enabled at startup. Don't use 285 // ioctl(PERF_EVENT_IOC_ENABLE) to enable it after perf_event_open(). 286 // Because some android kernels can't handle ioctl() well when cpu-hotplug 287 // happens. See http://b/25193162. 288 if (enable) { 289 selection.event_attr.enable_on_exec = 1; 290 selection.event_attr.disabled = 1; 291 } else { 292 selection.event_attr.enable_on_exec = 0; 293 selection.event_attr.disabled = 0; 294 } 295 } 296 } 297 } 298 299 bool EventSelectionSet::GetEnableOnExec() { 300 for (const auto& group : groups_) { 301 for (const auto& selection : group) { 302 if (selection.event_attr.enable_on_exec == 0) { 303 return false; 304 } 305 } 306 } 307 return true; 308 } 309 310 void EventSelectionSet::SampleIdAll() { 311 for (auto& group : groups_) { 312 for (auto& selection : group) { 313 selection.event_attr.sample_id_all = 1; 314 } 315 } 316 } 317 318 void EventSelectionSet::SetSampleSpeed(size_t group_id, const SampleSpeed& speed) { 319 CHECK_LT(group_id, groups_.size()); 320 for (auto& selection : groups_[group_id]) { 321 if (speed.UseFreq()) { 322 selection.event_attr.freq = 1; 323 selection.event_attr.sample_freq = speed.sample_freq; 324 } else { 325 selection.event_attr.freq = 0; 326 selection.event_attr.sample_period = speed.sample_period; 327 } 328 } 329 } 330 331 bool EventSelectionSet::SetBranchSampling(uint64_t branch_sample_type) { 332 if (branch_sample_type != 0 && 333 (branch_sample_type & 334 (PERF_SAMPLE_BRANCH_ANY | PERF_SAMPLE_BRANCH_ANY_CALL | 335 PERF_SAMPLE_BRANCH_ANY_RETURN | PERF_SAMPLE_BRANCH_IND_CALL)) == 0) { 336 LOG(ERROR) << "Invalid branch_sample_type: 0x" << std::hex 337 << branch_sample_type; 338 return false; 339 } 340 if (branch_sample_type != 0 && !IsBranchSamplingSupported()) { 341 LOG(ERROR) << "branch stack sampling is not supported on this device."; 342 return false; 343 } 344 for (auto& group : groups_) { 345 for (auto& selection : group) { 346 perf_event_attr& attr = selection.event_attr; 347 if (branch_sample_type != 0) { 348 attr.sample_type |= PERF_SAMPLE_BRANCH_STACK; 349 } else { 350 attr.sample_type &= ~PERF_SAMPLE_BRANCH_STACK; 351 } 352 attr.branch_sample_type = branch_sample_type; 353 } 354 } 355 return true; 356 } 357 358 void EventSelectionSet::EnableFpCallChainSampling() { 359 for (auto& group : groups_) { 360 for (auto& selection : group) { 361 selection.event_attr.sample_type |= PERF_SAMPLE_CALLCHAIN; 362 } 363 } 364 } 365 366 bool EventSelectionSet::EnableDwarfCallChainSampling(uint32_t dump_stack_size) { 367 if (!IsDwarfCallChainSamplingSupported()) { 368 LOG(ERROR) << "dwarf callchain sampling is not supported on this device."; 369 return false; 370 } 371 for (auto& group : groups_) { 372 for (auto& selection : group) { 373 selection.event_attr.sample_type |= PERF_SAMPLE_CALLCHAIN | 374 PERF_SAMPLE_REGS_USER | 375 PERF_SAMPLE_STACK_USER; 376 selection.event_attr.exclude_callchain_user = 1; 377 selection.event_attr.sample_regs_user = 378 GetSupportedRegMask(GetMachineArch()); 379 selection.event_attr.sample_stack_user = dump_stack_size; 380 } 381 } 382 return true; 383 } 384 385 void EventSelectionSet::SetInherit(bool enable) { 386 for (auto& group : groups_) { 387 for (auto& selection : group) { 388 selection.event_attr.inherit = (enable ? 1 : 0); 389 } 390 } 391 } 392 393 void EventSelectionSet::SetClockId(int clock_id) { 394 for (auto& group : groups_) { 395 for (auto& selection : group) { 396 selection.event_attr.use_clockid = 1; 397 selection.event_attr.clockid = clock_id; 398 } 399 } 400 } 401 402 bool EventSelectionSet::NeedKernelSymbol() const { 403 for (const auto& group : groups_) { 404 for (const auto& selection : group) { 405 if (!selection.event_type_modifier.exclude_kernel) { 406 return true; 407 } 408 } 409 } 410 return false; 411 } 412 413 static bool CheckIfCpusOnline(const std::vector<int>& cpus) { 414 std::vector<int> online_cpus = GetOnlineCpus(); 415 for (const auto& cpu : cpus) { 416 if (std::find(online_cpus.begin(), online_cpus.end(), cpu) == 417 online_cpus.end()) { 418 LOG(ERROR) << "cpu " << cpu << " is not online."; 419 return false; 420 } 421 } 422 return true; 423 } 424 425 bool EventSelectionSet::OpenEventFilesOnGroup(EventSelectionGroup& group, 426 pid_t tid, int cpu, 427 std::string* failed_event_type) { 428 std::vector<std::unique_ptr<EventFd>> event_fds; 429 // Given a tid and cpu, events on the same group should be all opened 430 // successfully or all failed to open. 431 EventFd* group_fd = nullptr; 432 for (auto& selection : group) { 433 std::unique_ptr<EventFd> event_fd = 434 EventFd::OpenEventFile(selection.event_attr, tid, cpu, group_fd, false); 435 if (!event_fd) { 436 *failed_event_type = selection.event_type_modifier.name; 437 return false; 438 } 439 LOG(VERBOSE) << "OpenEventFile for " << event_fd->Name(); 440 event_fds.push_back(std::move(event_fd)); 441 if (group_fd == nullptr) { 442 group_fd = event_fds.back().get(); 443 } 444 } 445 for (size_t i = 0; i < group.size(); ++i) { 446 group[i].event_fds.push_back(std::move(event_fds[i])); 447 } 448 return true; 449 } 450 451 static std::map<pid_t, std::set<pid_t>> PrepareThreads(const std::set<pid_t>& processes, 452 const std::set<pid_t>& threads) { 453 std::map<pid_t, std::set<pid_t>> result; 454 for (auto& pid : processes) { 455 std::vector<pid_t> tids = GetThreadsInProcess(pid); 456 std::set<pid_t>& threads_in_process = result[pid]; 457 threads_in_process.insert(tids.begin(), tids.end()); 458 } 459 for (auto& tid : threads) { 460 // tid = -1 means monitoring all threads. 461 if (tid == -1) { 462 result[-1].insert(-1); 463 } else { 464 pid_t pid; 465 if (GetProcessForThread(tid, &pid)) { 466 result[pid].insert(tid); 467 } 468 } 469 } 470 return result; 471 } 472 473 bool EventSelectionSet::OpenEventFiles(const std::vector<int>& on_cpus) { 474 std::vector<int> cpus = on_cpus; 475 if (!cpus.empty()) { 476 // cpus = {-1} means open an event file for all cpus. 477 if (!(cpus.size() == 1 && cpus[0] == -1) && !CheckIfCpusOnline(cpus)) { 478 return false; 479 } 480 } else { 481 cpus = GetOnlineCpus(); 482 } 483 std::map<pid_t, std::set<pid_t>> process_map = PrepareThreads(processes_, threads_); 484 for (auto& group : groups_) { 485 if (IsUserSpaceSamplerGroup(group)) { 486 if (!OpenUserSpaceSamplersOnGroup(group, process_map)) { 487 return false; 488 } 489 } else { 490 for (const auto& pair : process_map) { 491 size_t success_count = 0; 492 std::string failed_event_type; 493 for (const auto& tid : pair.second) { 494 for (const auto& cpu : cpus) { 495 if (OpenEventFilesOnGroup(group, tid, cpu, &failed_event_type)) { 496 success_count++; 497 } 498 } 499 } 500 // We can't guarantee to open perf event file successfully for each thread on each cpu. 501 // Because threads may exit between PrepareThreads() and OpenEventFilesOnGroup(), and 502 // cpus may be offlined between GetOnlineCpus() and OpenEventFilesOnGroup(). 503 // So we only check that we can at least monitor one thread for each process. 504 if (success_count == 0) { 505 PLOG(ERROR) << "failed to open perf event file for event_type " 506 << failed_event_type << " for " 507 << (pair.first == -1 ? "all threads" 508 : "threads in process " + std::to_string(pair.first)); 509 return false; 510 } 511 } 512 } 513 } 514 return true; 515 } 516 517 bool EventSelectionSet::IsUserSpaceSamplerGroup(EventSelectionGroup& group) { 518 return group.size() == 1 && group[0].event_attr.type == SIMPLEPERF_TYPE_USER_SPACE_SAMPLERS; 519 } 520 521 bool EventSelectionSet::OpenUserSpaceSamplersOnGroup(EventSelectionGroup& group, 522 const std::map<pid_t, std::set<pid_t>>& process_map) { 523 CHECK_EQ(group.size(), 1u); 524 for (auto& selection : group) { 525 if (selection.event_attr.type == SIMPLEPERF_TYPE_USER_SPACE_SAMPLERS && 526 selection.event_attr.config == SIMPLEPERF_CONFIG_INPLACE_SAMPLER) { 527 for (auto& pair : process_map) { 528 std::unique_ptr<InplaceSamplerClient> sampler = InplaceSamplerClient::Create( 529 selection.event_attr, pair.first, pair.second); 530 if (sampler == nullptr) { 531 return false; 532 } 533 selection.inplace_samplers.push_back(std::move(sampler)); 534 } 535 } 536 } 537 return true; 538 } 539 540 static bool ReadCounter(EventFd* event_fd, CounterInfo* counter) { 541 if (!event_fd->ReadCounter(&counter->counter)) { 542 return false; 543 } 544 counter->tid = event_fd->ThreadId(); 545 counter->cpu = event_fd->Cpu(); 546 return true; 547 } 548 549 bool EventSelectionSet::ReadCounters(std::vector<CountersInfo>* counters) { 550 counters->clear(); 551 for (size_t i = 0; i < groups_.size(); ++i) { 552 for (auto& selection : groups_[i]) { 553 CountersInfo counters_info; 554 counters_info.group_id = i; 555 counters_info.event_name = selection.event_type_modifier.event_type.name; 556 counters_info.event_modifier = selection.event_type_modifier.modifier; 557 counters_info.counters = selection.hotplugged_counters; 558 for (auto& event_fd : selection.event_fds) { 559 CounterInfo counter; 560 if (!ReadCounter(event_fd.get(), &counter)) { 561 return false; 562 } 563 counters_info.counters.push_back(counter); 564 } 565 counters->push_back(counters_info); 566 } 567 } 568 return true; 569 } 570 571 bool EventSelectionSet::MmapEventFiles(size_t min_mmap_pages, 572 size_t max_mmap_pages) { 573 for (size_t i = max_mmap_pages; i >= min_mmap_pages; i >>= 1) { 574 if (MmapEventFiles(i, i == min_mmap_pages)) { 575 LOG(VERBOSE) << "Mapped buffer size is " << i << " pages."; 576 mmap_pages_ = i; 577 return true; 578 } 579 for (auto& group : groups_) { 580 for (auto& selection : group) { 581 for (auto& event_fd : selection.event_fds) { 582 event_fd->DestroyMappedBuffer(); 583 } 584 } 585 } 586 } 587 return false; 588 } 589 590 bool EventSelectionSet::MmapEventFiles(size_t mmap_pages, bool report_error) { 591 // Allocate a mapped buffer for each cpu. 592 std::map<int, EventFd*> cpu_map; 593 for (auto& group : groups_) { 594 for (auto& selection : group) { 595 for (auto& event_fd : selection.event_fds) { 596 auto it = cpu_map.find(event_fd->Cpu()); 597 if (it != cpu_map.end()) { 598 if (!event_fd->ShareMappedBuffer(*(it->second), report_error)) { 599 return false; 600 } 601 } else { 602 if (!event_fd->CreateMappedBuffer(mmap_pages, report_error)) { 603 return false; 604 } 605 cpu_map[event_fd->Cpu()] = event_fd.get(); 606 } 607 } 608 } 609 } 610 return true; 611 } 612 613 bool EventSelectionSet::PrepareToReadMmapEventData(const std::function<bool(Record*)>& callback) { 614 // Add read Events for perf event files having mapped buffer. 615 for (auto& group : groups_) { 616 for (auto& selection : group) { 617 for (auto& event_fd : selection.event_fds) { 618 if (event_fd->HasMappedBuffer()) { 619 if (!event_fd->StartPolling(*loop_, [this]() { 620 return ReadMmapEventData(); 621 })) { 622 return false; 623 } 624 } 625 } 626 for (auto& sampler : selection.inplace_samplers) { 627 if (!sampler->StartPolling(*loop_, callback, 628 [&] { return CheckMonitoredTargets(); })) { 629 return false; 630 } 631 } 632 } 633 } 634 635 // Prepare record callback function. 636 record_callback_ = callback; 637 return true; 638 } 639 640 // When reading from mmap buffers, we prefer reading from all buffers at once 641 // rather than reading one buffer at a time. Because by reading all buffers 642 // at once, we can merge records from different buffers easily in memory. 643 // Otherwise, we have to sort records with greater effort. 644 bool EventSelectionSet::ReadMmapEventData() { 645 size_t head_size = 0; 646 std::vector<RecordBufferHead>& heads = record_buffer_heads_; 647 if (heads.empty()) { 648 heads.resize(1); 649 } 650 heads[0].current_pos = 0; 651 size_t buffer_pos = 0; 652 653 for (auto& group : groups_) { 654 for (auto& selection : group) { 655 for (auto& event_fd : selection.event_fds) { 656 if (event_fd->HasMappedBuffer()) { 657 if (event_fd->GetAvailableMmapData(record_buffer_, buffer_pos) != 0) { 658 heads[head_size].end_pos = buffer_pos; 659 heads[head_size].attr = &selection.event_attr; 660 head_size++; 661 if (heads.size() == head_size) { 662 heads.resize(head_size + 1); 663 } 664 heads[head_size].current_pos = buffer_pos; 665 } 666 } 667 } 668 } 669 } 670 671 if (head_size == 0) { 672 return true; 673 } 674 if (head_size == 1) { 675 // Only one buffer has data, process it directly. 676 std::vector<std::unique_ptr<Record>> records = 677 ReadRecordsFromBuffer(*heads[0].attr, 678 record_buffer_.data(), buffer_pos); 679 for (auto& r : records) { 680 if (!record_callback_(r.get())) { 681 return false; 682 } 683 } 684 } else { 685 // Use a priority queue to merge records from different buffers. As 686 // records from the same buffer are already ordered by time, we only 687 // need to merge the first record from all buffers. And each time a 688 // record is popped from the queue, we put the next record from its 689 // buffer into the queue. 690 auto comparator = [&](RecordBufferHead* h1, RecordBufferHead* h2) { 691 return h1->timestamp > h2->timestamp; 692 }; 693 std::priority_queue<RecordBufferHead*, std::vector<RecordBufferHead*>, decltype(comparator)> q(comparator); 694 for (size_t i = 0; i < head_size; ++i) { 695 RecordBufferHead& h = heads[i]; 696 h.r = ReadRecordFromBuffer(*h.attr, &record_buffer_[h.current_pos]); 697 h.timestamp = h.r->Timestamp(); 698 h.current_pos += h.r->size(); 699 q.push(&h); 700 } 701 while (!q.empty()) { 702 RecordBufferHead* h = q.top(); 703 q.pop(); 704 if (!record_callback_(h->r.get())) { 705 return false; 706 } 707 if (h->current_pos < h->end_pos) { 708 h->r = ReadRecordFromBuffer(*h->attr, &record_buffer_[h->current_pos]); 709 h->timestamp = h->r->Timestamp(); 710 h->current_pos += h->r->size(); 711 q.push(h); 712 } 713 } 714 } 715 return true; 716 } 717 718 bool EventSelectionSet::FinishReadMmapEventData() { 719 if (!ReadMmapEventData()) { 720 return false; 721 } 722 if (!HasInplaceSampler()) { 723 return true; 724 } 725 // Inplace sampler server uses a buffer to cache samples before sending them, so we need to 726 // explicitly ask it to send the cached samples. 727 loop_.reset(new IOEventLoop); 728 size_t inplace_sampler_count = 0; 729 auto close_callback = [&]() { 730 if (--inplace_sampler_count == 0) { 731 return loop_->ExitLoop(); 732 } 733 return true; 734 }; 735 for (auto& group : groups_) { 736 for (auto& sel : group) { 737 for (auto& sampler : sel.inplace_samplers) { 738 if (!sampler->IsClosed()) { 739 if (!sampler->StopProfiling(*loop_, close_callback)) { 740 return false; 741 } 742 inplace_sampler_count++; 743 } 744 } 745 } 746 } 747 if (inplace_sampler_count == 0) { 748 return true; 749 } 750 751 // Set a timeout to exit the loop. 752 timeval tv; 753 tv.tv_sec = 1; 754 tv.tv_usec = 0; 755 if (!loop_->AddPeriodicEvent(tv, [&]() { return loop_->ExitLoop(); })) { 756 return false; 757 } 758 return loop_->RunLoop(); 759 } 760 761 bool EventSelectionSet::HandleCpuHotplugEvents(const std::vector<int>& monitored_cpus, 762 double check_interval_in_sec) { 763 monitored_cpus_.insert(monitored_cpus.begin(), monitored_cpus.end()); 764 online_cpus_ = GetOnlineCpus(); 765 if (!loop_->AddPeriodicEvent(SecondToTimeval(check_interval_in_sec), 766 [&]() { return DetectCpuHotplugEvents(); })) { 767 return false; 768 } 769 return true; 770 } 771 772 bool EventSelectionSet::DetectCpuHotplugEvents() { 773 std::vector<int> new_cpus = GetOnlineCpus(); 774 for (const auto& cpu : online_cpus_) { 775 if (std::find(new_cpus.begin(), new_cpus.end(), cpu) == new_cpus.end()) { 776 if (monitored_cpus_.empty() || 777 monitored_cpus_.find(cpu) != monitored_cpus_.end()) { 778 LOG(INFO) << "Cpu " << cpu << " is offlined"; 779 if (!HandleCpuOfflineEvent(cpu)) { 780 return false; 781 } 782 } 783 } 784 } 785 for (const auto& cpu : new_cpus) { 786 if (std::find(online_cpus_.begin(), online_cpus_.end(), cpu) == 787 online_cpus_.end()) { 788 if (monitored_cpus_.empty() || 789 monitored_cpus_.find(cpu) != monitored_cpus_.end()) { 790 LOG(INFO) << "Cpu " << cpu << " is onlined"; 791 if (!HandleCpuOnlineEvent(cpu)) { 792 return false; 793 } 794 } 795 } 796 } 797 online_cpus_ = new_cpus; 798 return true; 799 } 800 801 bool EventSelectionSet::HandleCpuOfflineEvent(int cpu) { 802 if (!for_stat_cmd_) { 803 // Read mmap data here, so we won't lose the existing records of the 804 // offlined cpu. 805 if (!ReadMmapEventData()) { 806 return false; 807 } 808 } 809 for (auto& group : groups_) { 810 for (auto& selection : group) { 811 for (auto it = selection.event_fds.begin(); 812 it != selection.event_fds.end();) { 813 if ((*it)->Cpu() == cpu) { 814 if (for_stat_cmd_) { 815 CounterInfo counter; 816 if (!ReadCounter(it->get(), &counter)) { 817 return false; 818 } 819 selection.hotplugged_counters.push_back(counter); 820 } else { 821 if ((*it)->HasMappedBuffer()) { 822 if (!(*it)->StopPolling()) { 823 return false; 824 } 825 } 826 } 827 it = selection.event_fds.erase(it); 828 } else { 829 ++it; 830 } 831 } 832 } 833 } 834 return true; 835 } 836 837 bool EventSelectionSet::HandleCpuOnlineEvent(int cpu) { 838 // We need to start profiling when opening new event files. 839 SetEnableOnExec(false); 840 std::map<pid_t, std::set<pid_t>> process_map = PrepareThreads(processes_, threads_); 841 for (auto& group : groups_) { 842 if (IsUserSpaceSamplerGroup(group)) { 843 continue; 844 } 845 for (const auto& pair : process_map) { 846 for (const auto& tid : pair.second) { 847 std::string failed_event_type; 848 if (!OpenEventFilesOnGroup(group, tid, cpu, &failed_event_type)) { 849 // If failed to open event files, maybe the cpu has been offlined. 850 PLOG(WARNING) << "failed to open perf event file for event_type " 851 << failed_event_type << " for " 852 << (tid == -1 ? "all threads" : "thread " + std::to_string(tid)) 853 << " on cpu " << cpu; 854 } 855 } 856 } 857 } 858 if (!for_stat_cmd_) { 859 // Prepare mapped buffer. 860 if (!CreateMappedBufferForCpu(cpu)) { 861 return false; 862 } 863 // Send a EventIdRecord. 864 std::vector<uint64_t> event_id_data; 865 uint64_t attr_id = 0; 866 for (const auto& group : groups_) { 867 for (const auto& selection : group) { 868 for (const auto& event_fd : selection.event_fds) { 869 if (event_fd->Cpu() == cpu) { 870 event_id_data.push_back(attr_id); 871 event_id_data.push_back(event_fd->Id()); 872 } 873 } 874 ++attr_id; 875 } 876 } 877 EventIdRecord r(event_id_data); 878 if (!record_callback_(&r)) { 879 return false; 880 } 881 } 882 return true; 883 } 884 885 bool EventSelectionSet::CreateMappedBufferForCpu(int cpu) { 886 EventFd* fd_with_buffer = nullptr; 887 for (auto& group : groups_) { 888 for (auto& selection : group) { 889 for (auto& event_fd : selection.event_fds) { 890 if (event_fd->Cpu() != cpu) { 891 continue; 892 } 893 if (fd_with_buffer == nullptr) { 894 if (!event_fd->CreateMappedBuffer(mmap_pages_, true)) { 895 return false; 896 } 897 fd_with_buffer = event_fd.get(); 898 } else { 899 if (!event_fd->ShareMappedBuffer(*fd_with_buffer, true)) { 900 fd_with_buffer->DestroyMappedBuffer(); 901 return false; 902 } 903 } 904 } 905 } 906 } 907 if (fd_with_buffer != nullptr && 908 !fd_with_buffer->StartPolling(*loop_, [this]() { 909 return ReadMmapEventData(); 910 })) { 911 return false; 912 } 913 return true; 914 } 915 916 bool EventSelectionSet::StopWhenNoMoreTargets(double check_interval_in_sec) { 917 return loop_->AddPeriodicEvent(SecondToTimeval(check_interval_in_sec), 918 [&]() { return CheckMonitoredTargets(); }); 919 } 920 921 bool EventSelectionSet::CheckMonitoredTargets() { 922 if (!HasSampler()) { 923 return loop_->ExitLoop(); 924 } 925 for (const auto& tid : threads_) { 926 if (IsThreadAlive(tid)) { 927 return true; 928 } 929 } 930 for (const auto& pid : processes_) { 931 if (IsThreadAlive(pid)) { 932 return true; 933 } 934 } 935 return loop_->ExitLoop(); 936 } 937 938 bool EventSelectionSet::HasSampler() { 939 for (auto& group : groups_) { 940 for (auto& sel : group) { 941 if (!sel.event_fds.empty()) { 942 return true; 943 } 944 for (auto& sampler : sel.inplace_samplers) { 945 if (!sampler->IsClosed()) { 946 return true; 947 } 948 } 949 } 950 } 951 return false; 952 } 953