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