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, false);
    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         size_t success_count = 0;
    406         std::string failed_event_type;
    407         for (const auto& tid : pair.second) {
    408           for (const auto& cpu : cpus) {
    409             if (OpenEventFilesOnGroup(group, tid, cpu, &failed_event_type)) {
    410               success_count++;
    411             }
    412           }
    413         }
    414         // We can't guarantee to open perf event file successfully for each thread on each cpu.
    415         // Because threads may exit between PrepareThreads() and OpenEventFilesOnGroup(), and
    416         // cpus may be offlined between GetOnlineCpus() and OpenEventFilesOnGroup().
    417         // So we only check that we can at least monitor one thread for each process.
    418         if (success_count == 0) {
    419           PLOG(ERROR) << "failed to open perf event file for event_type "
    420                       << failed_event_type << " for "
    421                       << (pair.first == -1 ? "all threads"
    422                                            : "threads in process " + std::to_string(pair.first));
    423           return false;
    424         }
    425       }
    426     }
    427   }
    428   return true;
    429 }
    430 
    431 bool EventSelectionSet::IsUserSpaceSamplerGroup(EventSelectionGroup& group) {
    432   return group.size() == 1 && group[0].event_attr.type == SIMPLEPERF_TYPE_USER_SPACE_SAMPLERS;
    433 }
    434 
    435 bool EventSelectionSet::OpenUserSpaceSamplersOnGroup(EventSelectionGroup& group,
    436     const std::map<pid_t, std::set<pid_t>>& process_map) {
    437   CHECK_EQ(group.size(), 1u);
    438   for (auto& selection : group) {
    439     if (selection.event_attr.type == SIMPLEPERF_TYPE_USER_SPACE_SAMPLERS &&
    440         selection.event_attr.config == SIMPLEPERF_CONFIG_INPLACE_SAMPLER) {
    441       for (auto& pair : process_map) {
    442         std::unique_ptr<InplaceSamplerClient> sampler = InplaceSamplerClient::Create(
    443             selection.event_attr, pair.first, pair.second);
    444         if (sampler == nullptr) {
    445           return false;
    446         }
    447         selection.inplace_samplers.push_back(std::move(sampler));
    448       }
    449     }
    450   }
    451   return true;
    452 }
    453 
    454 static bool ReadCounter(EventFd* event_fd, CounterInfo* counter) {
    455   if (!event_fd->ReadCounter(&counter->counter)) {
    456     return false;
    457   }
    458   counter->tid = event_fd->ThreadId();
    459   counter->cpu = event_fd->Cpu();
    460   return true;
    461 }
    462 
    463 bool EventSelectionSet::ReadCounters(std::vector<CountersInfo>* counters) {
    464   counters->clear();
    465   for (size_t i = 0; i < groups_.size(); ++i) {
    466     for (auto& selection : groups_[i]) {
    467       CountersInfo counters_info;
    468       counters_info.group_id = i;
    469       counters_info.event_name = selection.event_type_modifier.event_type.name;
    470       counters_info.event_modifier = selection.event_type_modifier.modifier;
    471       counters_info.counters = selection.hotplugged_counters;
    472       for (auto& event_fd : selection.event_fds) {
    473         CounterInfo counter;
    474         if (!ReadCounter(event_fd.get(), &counter)) {
    475           return false;
    476         }
    477         counters_info.counters.push_back(counter);
    478       }
    479       counters->push_back(counters_info);
    480     }
    481   }
    482   return true;
    483 }
    484 
    485 bool EventSelectionSet::MmapEventFiles(size_t min_mmap_pages,
    486                                        size_t max_mmap_pages) {
    487   for (size_t i = max_mmap_pages; i >= min_mmap_pages; i >>= 1) {
    488     if (MmapEventFiles(i, i == min_mmap_pages)) {
    489       LOG(VERBOSE) << "Mapped buffer size is " << i << " pages.";
    490       mmap_pages_ = i;
    491       return true;
    492     }
    493     for (auto& group : groups_) {
    494       for (auto& selection : group) {
    495         for (auto& event_fd : selection.event_fds) {
    496           event_fd->DestroyMappedBuffer();
    497         }
    498       }
    499     }
    500   }
    501   return false;
    502 }
    503 
    504 bool EventSelectionSet::MmapEventFiles(size_t mmap_pages, bool report_error) {
    505   // Allocate a mapped buffer for each cpu.
    506   std::map<int, EventFd*> cpu_map;
    507   for (auto& group : groups_) {
    508     for (auto& selection : group) {
    509       for (auto& event_fd : selection.event_fds) {
    510         auto it = cpu_map.find(event_fd->Cpu());
    511         if (it != cpu_map.end()) {
    512           if (!event_fd->ShareMappedBuffer(*(it->second), report_error)) {
    513             return false;
    514           }
    515         } else {
    516           if (!event_fd->CreateMappedBuffer(mmap_pages, report_error)) {
    517             return false;
    518           }
    519           cpu_map[event_fd->Cpu()] = event_fd.get();
    520         }
    521       }
    522     }
    523   }
    524   return true;
    525 }
    526 
    527 bool EventSelectionSet::PrepareToReadMmapEventData(const std::function<bool(Record*)>& callback) {
    528   // Add read Events for perf event files having mapped buffer.
    529   for (auto& group : groups_) {
    530     for (auto& selection : group) {
    531       for (auto& event_fd : selection.event_fds) {
    532         if (event_fd->HasMappedBuffer()) {
    533           if (!event_fd->StartPolling(*loop_, [this]() {
    534                 return ReadMmapEventData();
    535               })) {
    536             return false;
    537           }
    538         }
    539       }
    540       for (auto& sampler : selection.inplace_samplers) {
    541         if (!sampler->StartPolling(*loop_, callback,
    542                                    [&] { return CheckMonitoredTargets(); })) {
    543           return false;
    544         }
    545       }
    546     }
    547   }
    548 
    549   // Prepare record callback function.
    550   record_callback_ = callback;
    551   return true;
    552 }
    553 
    554 // When reading from mmap buffers, we prefer reading from all buffers at once
    555 // rather than reading one buffer at a time. Because by reading all buffers
    556 // at once, we can merge records from different buffers easily in memory.
    557 // Otherwise, we have to sort records with greater effort.
    558 bool EventSelectionSet::ReadMmapEventData() {
    559   size_t head_size = 0;
    560   std::vector<RecordBufferHead>& heads = record_buffer_heads_;
    561   if (heads.empty()) {
    562     heads.resize(1);
    563   }
    564   heads[0].current_pos = 0;
    565   size_t buffer_pos = 0;
    566 
    567   for (auto& group : groups_) {
    568     for (auto& selection : group) {
    569       for (auto& event_fd : selection.event_fds) {
    570         if (event_fd->HasMappedBuffer()) {
    571           if (event_fd->GetAvailableMmapData(record_buffer_, buffer_pos) != 0) {
    572             heads[head_size].end_pos = buffer_pos;
    573             heads[head_size].attr = &selection.event_attr;
    574             head_size++;
    575             if (heads.size() == head_size) {
    576               heads.resize(head_size + 1);
    577             }
    578             heads[head_size].current_pos = buffer_pos;
    579           }
    580         }
    581       }
    582     }
    583   }
    584 
    585   if (head_size == 0) {
    586     return true;
    587   }
    588   if (head_size == 1) {
    589     // Only one buffer has data, process it directly.
    590     std::vector<std::unique_ptr<Record>> records =
    591         ReadRecordsFromBuffer(*heads[0].attr,
    592                               record_buffer_.data(), buffer_pos);
    593     for (auto& r : records) {
    594       if (!record_callback_(r.get())) {
    595         return false;
    596       }
    597     }
    598   } else {
    599     // Use a priority queue to merge records from different buffers. As
    600     // records from the same buffer are already ordered by time, we only
    601     // need to merge the first record from all buffers. And each time a
    602     // record is popped from the queue, we put the next record from its
    603     // buffer into the queue.
    604     auto comparator = [&](RecordBufferHead* h1, RecordBufferHead* h2) {
    605       return h1->timestamp > h2->timestamp;
    606     };
    607     std::priority_queue<RecordBufferHead*, std::vector<RecordBufferHead*>, decltype(comparator)> q(comparator);
    608     for (size_t i = 0; i < head_size; ++i) {
    609       RecordBufferHead& h = heads[i];
    610       h.r = ReadRecordFromBuffer(*h.attr, &record_buffer_[h.current_pos]);
    611       h.timestamp = h.r->Timestamp();
    612       h.current_pos += h.r->size();
    613       q.push(&h);
    614     }
    615     while (!q.empty()) {
    616       RecordBufferHead* h = q.top();
    617       q.pop();
    618       if (!record_callback_(h->r.get())) {
    619         return false;
    620       }
    621       if (h->current_pos < h->end_pos) {
    622         h->r = ReadRecordFromBuffer(*h->attr, &record_buffer_[h->current_pos]);
    623         h->timestamp = h->r->Timestamp();
    624         h->current_pos += h->r->size();
    625         q.push(h);
    626       }
    627     }
    628   }
    629   return true;
    630 }
    631 
    632 bool EventSelectionSet::FinishReadMmapEventData() {
    633   if (!ReadMmapEventData()) {
    634     return false;
    635   }
    636   if (!HasInplaceSampler()) {
    637     return true;
    638   }
    639   // Inplace sampler server uses a buffer to cache samples before sending them, so we need to
    640   // explicitly ask it to send the cached samples.
    641   loop_.reset(new IOEventLoop);
    642   size_t inplace_sampler_count = 0;
    643   auto close_callback = [&]() {
    644     if (--inplace_sampler_count == 0) {
    645       return loop_->ExitLoop();
    646     }
    647     return true;
    648   };
    649   for (auto& group : groups_) {
    650     for (auto& sel : group) {
    651       for (auto& sampler : sel.inplace_samplers) {
    652         if (!sampler->IsClosed()) {
    653           if (!sampler->StopProfiling(*loop_, close_callback)) {
    654             return false;
    655           }
    656           inplace_sampler_count++;
    657         }
    658       }
    659     }
    660   }
    661   if (inplace_sampler_count == 0) {
    662     return true;
    663   }
    664 
    665   // Set a timeout to exit the loop.
    666   timeval tv;
    667   tv.tv_sec = 1;
    668   tv.tv_usec = 0;
    669   if (!loop_->AddPeriodicEvent(tv, [&]() { return loop_->ExitLoop(); })) {
    670     return false;
    671   }
    672   return loop_->RunLoop();
    673 }
    674 
    675 bool EventSelectionSet::HandleCpuHotplugEvents(const std::vector<int>& monitored_cpus,
    676                                                double check_interval_in_sec) {
    677   monitored_cpus_.insert(monitored_cpus.begin(), monitored_cpus.end());
    678   online_cpus_ = GetOnlineCpus();
    679   if (!loop_->AddPeriodicEvent(SecondToTimeval(check_interval_in_sec),
    680                                [&]() { return DetectCpuHotplugEvents(); })) {
    681     return false;
    682   }
    683   return true;
    684 }
    685 
    686 bool EventSelectionSet::DetectCpuHotplugEvents() {
    687   std::vector<int> new_cpus = GetOnlineCpus();
    688   for (const auto& cpu : online_cpus_) {
    689     if (std::find(new_cpus.begin(), new_cpus.end(), cpu) == new_cpus.end()) {
    690       if (monitored_cpus_.empty() ||
    691           monitored_cpus_.find(cpu) != monitored_cpus_.end()) {
    692         LOG(INFO) << "Cpu " << cpu << " is offlined";
    693         if (!HandleCpuOfflineEvent(cpu)) {
    694           return false;
    695         }
    696       }
    697     }
    698   }
    699   for (const auto& cpu : new_cpus) {
    700     if (std::find(online_cpus_.begin(), online_cpus_.end(), cpu) ==
    701         online_cpus_.end()) {
    702       if (monitored_cpus_.empty() ||
    703           monitored_cpus_.find(cpu) != monitored_cpus_.end()) {
    704         LOG(INFO) << "Cpu " << cpu << " is onlined";
    705         if (!HandleCpuOnlineEvent(cpu)) {
    706           return false;
    707         }
    708       }
    709     }
    710   }
    711   online_cpus_ = new_cpus;
    712   return true;
    713 }
    714 
    715 bool EventSelectionSet::HandleCpuOfflineEvent(int cpu) {
    716   if (!for_stat_cmd_) {
    717     // Read mmap data here, so we won't lose the existing records of the
    718     // offlined cpu.
    719     if (!ReadMmapEventData()) {
    720       return false;
    721     }
    722   }
    723   for (auto& group : groups_) {
    724     for (auto& selection : group) {
    725       for (auto it = selection.event_fds.begin();
    726            it != selection.event_fds.end();) {
    727         if ((*it)->Cpu() == cpu) {
    728           if (for_stat_cmd_) {
    729             CounterInfo counter;
    730             if (!ReadCounter(it->get(), &counter)) {
    731               return false;
    732             }
    733             selection.hotplugged_counters.push_back(counter);
    734           } else {
    735             if ((*it)->HasMappedBuffer()) {
    736               if (!(*it)->StopPolling()) {
    737                 return false;
    738               }
    739             }
    740           }
    741           it = selection.event_fds.erase(it);
    742         } else {
    743           ++it;
    744         }
    745       }
    746     }
    747   }
    748   return true;
    749 }
    750 
    751 bool EventSelectionSet::HandleCpuOnlineEvent(int cpu) {
    752   // We need to start profiling when opening new event files.
    753   SetEnableOnExec(false);
    754   std::map<pid_t, std::set<pid_t>> process_map = PrepareThreads(processes_, threads_);
    755   for (auto& group : groups_) {
    756     if (IsUserSpaceSamplerGroup(group)) {
    757       continue;
    758     }
    759     for (const auto& pair : process_map) {
    760       for (const auto& tid : pair.second) {
    761         std::string failed_event_type;
    762         if (!OpenEventFilesOnGroup(group, tid, cpu, &failed_event_type)) {
    763           // If failed to open event files, maybe the cpu has been offlined.
    764           PLOG(WARNING) << "failed to open perf event file for event_type "
    765                         << failed_event_type << " for "
    766                         << (tid == -1 ? "all threads" : "thread " + std::to_string(tid))
    767                         << " on cpu " << cpu;
    768         }
    769       }
    770     }
    771   }
    772   if (!for_stat_cmd_) {
    773     // Prepare mapped buffer.
    774     if (!CreateMappedBufferForCpu(cpu)) {
    775       return false;
    776     }
    777     // Send a EventIdRecord.
    778     std::vector<uint64_t> event_id_data;
    779     uint64_t attr_id = 0;
    780     for (const auto& group : groups_) {
    781       for (const auto& selection : group) {
    782         for (const auto& event_fd : selection.event_fds) {
    783           if (event_fd->Cpu() == cpu) {
    784             event_id_data.push_back(attr_id);
    785             event_id_data.push_back(event_fd->Id());
    786           }
    787         }
    788         ++attr_id;
    789       }
    790     }
    791     EventIdRecord r(event_id_data);
    792     if (!record_callback_(&r)) {
    793       return false;
    794     }
    795   }
    796   return true;
    797 }
    798 
    799 bool EventSelectionSet::CreateMappedBufferForCpu(int cpu) {
    800   EventFd* fd_with_buffer = nullptr;
    801   for (auto& group : groups_) {
    802     for (auto& selection : group) {
    803       for (auto& event_fd : selection.event_fds) {
    804         if (event_fd->Cpu() != cpu) {
    805           continue;
    806         }
    807         if (fd_with_buffer == nullptr) {
    808           if (!event_fd->CreateMappedBuffer(mmap_pages_, true)) {
    809             return false;
    810           }
    811           fd_with_buffer = event_fd.get();
    812         } else {
    813           if (!event_fd->ShareMappedBuffer(*fd_with_buffer, true)) {
    814             fd_with_buffer->DestroyMappedBuffer();
    815             return false;
    816           }
    817         }
    818       }
    819     }
    820   }
    821   if (fd_with_buffer != nullptr &&
    822       !fd_with_buffer->StartPolling(*loop_, [this]() {
    823         return ReadMmapEventData();
    824       })) {
    825     return false;
    826   }
    827   return true;
    828 }
    829 
    830 bool EventSelectionSet::StopWhenNoMoreTargets(double check_interval_in_sec) {
    831   return loop_->AddPeriodicEvent(SecondToTimeval(check_interval_in_sec),
    832                                  [&]() { return CheckMonitoredTargets(); });
    833 }
    834 
    835 bool EventSelectionSet::CheckMonitoredTargets() {
    836   if (!HasSampler()) {
    837     return loop_->ExitLoop();
    838   }
    839   for (const auto& tid : threads_) {
    840     if (IsThreadAlive(tid)) {
    841       return true;
    842     }
    843   }
    844   for (const auto& pid : processes_) {
    845     if (IsThreadAlive(pid)) {
    846       return true;
    847     }
    848   }
    849   return loop_->ExitLoop();
    850 }
    851 
    852 bool EventSelectionSet::HasSampler() {
    853   for (auto& group : groups_) {
    854     for (auto& sel : group) {
    855       if (!sel.event_fds.empty()) {
    856         return true;
    857       }
    858       for (auto& sampler : sel.inplace_samplers) {
    859         if (!sampler->IsClosed()) {
    860           return true;
    861         }
    862       }
    863     }
    864   }
    865   return false;
    866 }
    867