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 <poll.h>
     20 
     21 #include <android-base/logging.h>
     22 #include <android-base/stringprintf.h>
     23 
     24 #include "environment.h"
     25 #include "event_attr.h"
     26 #include "event_type.h"
     27 #include "perf_regs.h"
     28 
     29 bool IsBranchSamplingSupported() {
     30   const EventType* type = FindEventTypeByName("cpu-cycles");
     31   if (type == nullptr) {
     32     return false;
     33   }
     34   perf_event_attr attr = CreateDefaultPerfEventAttr(*type);
     35   attr.sample_type |= PERF_SAMPLE_BRANCH_STACK;
     36   attr.branch_sample_type = PERF_SAMPLE_BRANCH_ANY;
     37   return IsEventAttrSupportedByKernel(attr);
     38 }
     39 
     40 bool IsDwarfCallChainSamplingSupported() {
     41   const EventType* type = FindEventTypeByName("cpu-cycles");
     42   if (type == nullptr) {
     43     return false;
     44   }
     45   perf_event_attr attr = CreateDefaultPerfEventAttr(*type);
     46   attr.sample_type |= PERF_SAMPLE_CALLCHAIN | PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER;
     47   attr.exclude_callchain_user = 1;
     48   attr.sample_regs_user = GetSupportedRegMask(GetBuildArch());
     49   attr.sample_stack_user = 8192;
     50   return IsEventAttrSupportedByKernel(attr);
     51 }
     52 
     53 bool EventSelectionSet::AddEventType(const EventTypeAndModifier& event_type_modifier) {
     54   EventSelection selection;
     55   selection.event_type_modifier = event_type_modifier;
     56   selection.event_attr = CreateDefaultPerfEventAttr(event_type_modifier.event_type);
     57   selection.event_attr.exclude_user = event_type_modifier.exclude_user;
     58   selection.event_attr.exclude_kernel = event_type_modifier.exclude_kernel;
     59   selection.event_attr.exclude_hv = event_type_modifier.exclude_hv;
     60   selection.event_attr.exclude_host = event_type_modifier.exclude_host;
     61   selection.event_attr.exclude_guest = event_type_modifier.exclude_guest;
     62   selection.event_attr.precise_ip = event_type_modifier.precise_ip;
     63   if (!IsEventAttrSupportedByKernel(selection.event_attr)) {
     64     LOG(ERROR) << "Event type '" << event_type_modifier.name << "' is not supported by the kernel";
     65     return false;
     66   }
     67   selections_.push_back(std::move(selection));
     68   UnionSampleType();
     69   return true;
     70 }
     71 
     72 // Union the sample type of different event attrs can make reading sample records in perf.data
     73 // easier.
     74 void EventSelectionSet::UnionSampleType() {
     75   uint64_t sample_type = 0;
     76   for (auto& selection : selections_) {
     77     sample_type |= selection.event_attr.sample_type;
     78   }
     79   for (auto& selection : selections_) {
     80     selection.event_attr.sample_type = sample_type;
     81   }
     82 }
     83 
     84 void EventSelectionSet::SetEnableOnExec(bool enable) {
     85   for (auto& selection : selections_) {
     86     // If sampling is enabled on exec, then it is disabled at startup, otherwise
     87     // it should be enabled at startup. Don't use ioctl(PERF_EVENT_IOC_ENABLE)
     88     // to enable it after perf_event_open(). Because some android kernels can't
     89     // handle ioctl() well when cpu-hotplug happens. See http://b/25193162.
     90     if (enable) {
     91       selection.event_attr.enable_on_exec = 1;
     92       selection.event_attr.disabled = 1;
     93     } else {
     94       selection.event_attr.enable_on_exec = 0;
     95       selection.event_attr.disabled = 0;
     96     }
     97   }
     98 }
     99 
    100 bool EventSelectionSet::GetEnableOnExec() {
    101   for (auto& selection : selections_) {
    102     if (selection.event_attr.enable_on_exec == 0) {
    103       return false;
    104     }
    105   }
    106   return true;
    107 }
    108 
    109 void EventSelectionSet::SampleIdAll() {
    110   for (auto& selection : selections_) {
    111     selection.event_attr.sample_id_all = 1;
    112   }
    113 }
    114 
    115 void EventSelectionSet::SetSampleFreq(uint64_t sample_freq) {
    116   for (auto& selection : selections_) {
    117     perf_event_attr& attr = selection.event_attr;
    118     attr.freq = 1;
    119     attr.sample_freq = sample_freq;
    120   }
    121 }
    122 
    123 void EventSelectionSet::SetSamplePeriod(uint64_t sample_period) {
    124   for (auto& selection : selections_) {
    125     perf_event_attr& attr = selection.event_attr;
    126     attr.freq = 0;
    127     attr.sample_period = sample_period;
    128   }
    129 }
    130 
    131 bool EventSelectionSet::SetBranchSampling(uint64_t branch_sample_type) {
    132   if (branch_sample_type != 0 &&
    133       (branch_sample_type & (PERF_SAMPLE_BRANCH_ANY | PERF_SAMPLE_BRANCH_ANY_CALL |
    134                              PERF_SAMPLE_BRANCH_ANY_RETURN | PERF_SAMPLE_BRANCH_IND_CALL)) == 0) {
    135     LOG(ERROR) << "Invalid branch_sample_type: 0x" << std::hex << branch_sample_type;
    136     return false;
    137   }
    138   if (branch_sample_type != 0 && !IsBranchSamplingSupported()) {
    139     LOG(ERROR) << "branch stack sampling is not supported on this device.";
    140     return false;
    141   }
    142   for (auto& selection : selections_) {
    143     perf_event_attr& attr = selection.event_attr;
    144     if (branch_sample_type != 0) {
    145       attr.sample_type |= PERF_SAMPLE_BRANCH_STACK;
    146     } else {
    147       attr.sample_type &= ~PERF_SAMPLE_BRANCH_STACK;
    148     }
    149     attr.branch_sample_type = branch_sample_type;
    150   }
    151   return true;
    152 }
    153 
    154 void EventSelectionSet::EnableFpCallChainSampling() {
    155   for (auto& selection : selections_) {
    156     selection.event_attr.sample_type |= PERF_SAMPLE_CALLCHAIN;
    157   }
    158 }
    159 
    160 bool EventSelectionSet::EnableDwarfCallChainSampling(uint32_t dump_stack_size) {
    161   if (!IsDwarfCallChainSamplingSupported()) {
    162     LOG(ERROR) << "dwarf callchain sampling is not supported on this device.";
    163     return false;
    164   }
    165   for (auto& selection : selections_) {
    166     selection.event_attr.sample_type |=
    167         PERF_SAMPLE_CALLCHAIN | PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER;
    168     selection.event_attr.exclude_callchain_user = 1;
    169     selection.event_attr.sample_regs_user = GetSupportedRegMask(GetBuildArch());
    170     selection.event_attr.sample_stack_user = dump_stack_size;
    171   }
    172   return true;
    173 }
    174 
    175 void EventSelectionSet::SetInherit(bool enable) {
    176   for (auto& selection : selections_) {
    177     selection.event_attr.inherit = (enable ? 1 : 0);
    178   }
    179 }
    180 
    181 static bool CheckIfCpusOnline(const std::vector<int>& cpus) {
    182   std::vector<int> online_cpus = GetOnlineCpus();
    183   for (const auto& cpu : cpus) {
    184     if (std::find(online_cpus.begin(), online_cpus.end(), cpu) == online_cpus.end()) {
    185       LOG(ERROR) << "cpu " << cpu << " is not online.";
    186       return false;
    187     }
    188   }
    189   return true;
    190 }
    191 
    192 bool EventSelectionSet::OpenEventFilesForCpus(const std::vector<int>& cpus) {
    193   return OpenEventFilesForThreadsOnCpus({-1}, cpus);
    194 }
    195 
    196 bool EventSelectionSet::OpenEventFilesForThreadsOnCpus(const std::vector<pid_t>& threads,
    197                                                        std::vector<int> cpus) {
    198   if (!cpus.empty()) {
    199     if (!CheckIfCpusOnline(cpus)) {
    200       return false;
    201     }
    202   } else {
    203     cpus = GetOnlineCpus();
    204   }
    205   return OpenEventFiles(threads, cpus);
    206 }
    207 
    208 bool EventSelectionSet::OpenEventFiles(const std::vector<pid_t>& threads,
    209                                        const std::vector<int>& cpus) {
    210   for (auto& selection : selections_) {
    211     for (auto& tid : threads) {
    212       size_t open_per_thread = 0;
    213       for (auto& cpu : cpus) {
    214         auto event_fd = EventFd::OpenEventFile(selection.event_attr, tid, cpu);
    215         if (event_fd != nullptr) {
    216           LOG(VERBOSE) << "OpenEventFile for tid " << tid << ", cpu " << cpu;
    217           selection.event_fds.push_back(std::move(event_fd));
    218           ++open_per_thread;
    219         }
    220       }
    221       // As the online cpus can be enabled or disabled at runtime, we may not open event file for
    222       // all cpus successfully. But we should open at least one cpu successfully.
    223       if (open_per_thread == 0) {
    224         PLOG(ERROR) << "failed to open perf event file for event_type "
    225                     << selection.event_type_modifier.name << " for "
    226                     << (tid == -1 ? "all threads" : android::base::StringPrintf(" thread %d", tid));
    227         return false;
    228       }
    229     }
    230   }
    231   return true;
    232 }
    233 
    234 bool EventSelectionSet::ReadCounters(std::vector<CountersInfo>* counters) {
    235   counters->clear();
    236   for (auto& selection : selections_) {
    237     CountersInfo counters_info;
    238     counters_info.event_type = &selection.event_type_modifier;
    239     for (auto& event_fd : selection.event_fds) {
    240       CountersInfo::CounterInfo counter_info;
    241       if (!event_fd->ReadCounter(&counter_info.counter)) {
    242         return false;
    243       }
    244       counter_info.tid = event_fd->ThreadId();
    245       counter_info.cpu = event_fd->Cpu();
    246       counters_info.counters.push_back(counter_info);
    247     }
    248     counters->push_back(counters_info);
    249   }
    250   return true;
    251 }
    252 
    253 void EventSelectionSet::PreparePollForEventFiles(std::vector<pollfd>* pollfds) {
    254   for (auto& selection : selections_) {
    255     for (auto& event_fd : selection.event_fds) {
    256       pollfd poll_fd;
    257       event_fd->PreparePollForMmapData(&poll_fd);
    258       pollfds->push_back(poll_fd);
    259     }
    260   }
    261 }
    262 
    263 bool EventSelectionSet::MmapEventFiles(size_t mmap_pages) {
    264   for (auto& selection : selections_) {
    265     for (auto& event_fd : selection.event_fds) {
    266       if (!event_fd->MmapContent(mmap_pages)) {
    267         return false;
    268       }
    269     }
    270   }
    271   return true;
    272 }
    273 
    274 static bool ReadMmapEventDataForFd(std::unique_ptr<EventFd>& event_fd,
    275                                    std::function<bool(const char*, size_t)> callback,
    276                                    bool* have_data) {
    277   *have_data = false;
    278   while (true) {
    279     char* data;
    280     size_t size = event_fd->GetAvailableMmapData(&data);
    281     if (size == 0) {
    282       break;
    283     }
    284     if (!callback(data, size)) {
    285       return false;
    286     }
    287     *have_data = true;
    288   }
    289   return true;
    290 }
    291 
    292 bool EventSelectionSet::ReadMmapEventData(std::function<bool(const char*, size_t)> callback) {
    293   for (auto& selection : selections_) {
    294     for (auto& event_fd : selection.event_fds) {
    295       while (true) {
    296         bool have_data;
    297         if (!ReadMmapEventDataForFd(event_fd, callback, &have_data)) {
    298           return false;
    299         }
    300         if (!have_data) {
    301           break;
    302         }
    303       }
    304     }
    305   }
    306   return true;
    307 }
    308 
    309 EventSelectionSet::EventSelection* EventSelectionSet::FindSelectionByType(
    310     const EventTypeAndModifier& event_type_modifier) {
    311   for (auto& selection : selections_) {
    312     if (selection.event_type_modifier.name == event_type_modifier.name) {
    313       return &selection;
    314     }
    315   }
    316   return nullptr;
    317 }
    318 
    319 const perf_event_attr* EventSelectionSet::FindEventAttrByType(
    320     const EventTypeAndModifier& event_type_modifier) {
    321   EventSelection* selection = FindSelectionByType(event_type_modifier);
    322   return (selection != nullptr) ? &selection->event_attr : nullptr;
    323 }
    324 
    325 const std::vector<std::unique_ptr<EventFd>>* EventSelectionSet::FindEventFdsByType(
    326     const EventTypeAndModifier& event_type_modifier) {
    327   EventSelection* selection = FindSelectionByType(event_type_modifier);
    328   return (selection != nullptr) ? &selection->event_fds : nullptr;
    329 }
    330