event_selection_set.cpp revision 9fd3cc1048a3d0338df4a48760dfd655560992a1
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 <base/logging.h> 20#include <base/stringprintf.h> 21 22#include "environment.h" 23#include "event_attr.h" 24#include "event_type.h" 25 26bool IsBranchSamplingSupported() { 27 const EventType* type = FindEventTypeByName("cpu-cycles"); 28 if (type == nullptr) { 29 return false; 30 } 31 perf_event_attr attr = CreateDefaultPerfEventAttr(*type); 32 attr.sample_type |= PERF_SAMPLE_BRANCH_STACK; 33 attr.branch_sample_type = PERF_SAMPLE_BRANCH_ANY; 34 return IsEventAttrSupportedByKernel(attr); 35} 36 37bool EventSelectionSet::AddEventType(const EventTypeAndModifier& event_type_modifier) { 38 EventSelection selection; 39 selection.event_type = event_type_modifier.event_type; 40 selection.event_attr = CreateDefaultPerfEventAttr(event_type_modifier.event_type); 41 selection.event_attr.exclude_user = event_type_modifier.exclude_user; 42 selection.event_attr.exclude_kernel = event_type_modifier.exclude_kernel; 43 selection.event_attr.exclude_hv = event_type_modifier.exclude_hv; 44 selection.event_attr.exclude_host = event_type_modifier.exclude_host; 45 selection.event_attr.exclude_guest = event_type_modifier.exclude_guest; 46 selection.event_attr.precise_ip = event_type_modifier.precise_ip; 47 if (!IsEventAttrSupportedByKernel(selection.event_attr)) { 48 LOG(ERROR) << "Event type '" << selection.event_type.name << "' is not supported by the kernel"; 49 return false; 50 } 51 selections_.push_back(std::move(selection)); 52 return true; 53} 54 55void EventSelectionSet::SetEnableOnExec(bool enable) { 56 for (auto& selection : selections_) { 57 selection.event_attr.enable_on_exec = (enable ? 1 : 0); 58 } 59} 60 61bool EventSelectionSet::GetEnableOnExec() { 62 for (auto& selection : selections_) { 63 if (selection.event_attr.enable_on_exec == 0) { 64 return false; 65 } 66 } 67 return true; 68} 69 70void EventSelectionSet::SampleIdAll() { 71 for (auto& selection : selections_) { 72 selection.event_attr.sample_id_all = 1; 73 } 74} 75 76void EventSelectionSet::SetSampleFreq(uint64_t sample_freq) { 77 for (auto& selection : selections_) { 78 perf_event_attr& attr = selection.event_attr; 79 attr.freq = 1; 80 attr.sample_freq = sample_freq; 81 } 82} 83 84void EventSelectionSet::SetSamplePeriod(uint64_t sample_period) { 85 for (auto& selection : selections_) { 86 perf_event_attr& attr = selection.event_attr; 87 attr.freq = 0; 88 attr.sample_period = sample_period; 89 } 90} 91 92bool EventSelectionSet::SetBranchSampling(uint64_t branch_sample_type) { 93 if (branch_sample_type != 0 && 94 (branch_sample_type & (PERF_SAMPLE_BRANCH_ANY | PERF_SAMPLE_BRANCH_ANY_CALL | 95 PERF_SAMPLE_BRANCH_ANY_RETURN | PERF_SAMPLE_BRANCH_IND_CALL)) == 0) { 96 LOG(ERROR) << "Invalid branch_sample_type: 0x" << std::hex << branch_sample_type; 97 return false; 98 } 99 if (branch_sample_type != 0 && !IsBranchSamplingSupported()) { 100 LOG(ERROR) << "branch stack sampling is not supported on this device."; 101 return false; 102 } 103 for (auto& selection : selections_) { 104 perf_event_attr& attr = selection.event_attr; 105 if (branch_sample_type != 0) { 106 attr.sample_type |= PERF_SAMPLE_BRANCH_STACK; 107 } else { 108 attr.sample_type &= ~PERF_SAMPLE_BRANCH_STACK; 109 } 110 attr.branch_sample_type = branch_sample_type; 111 } 112 return true; 113} 114 115void EventSelectionSet::EnableCallChainSampling() { 116 for (auto& selection : selections_) { 117 selection.event_attr.sample_type |= PERF_SAMPLE_CALLCHAIN; 118 } 119} 120 121void EventSelectionSet::SetInherit(bool enable) { 122 for (auto& selection : selections_) { 123 selection.event_attr.inherit = (enable ? 1 : 0); 124 } 125} 126 127bool EventSelectionSet::OpenEventFilesForAllCpus() { 128 return OpenEventFilesForThreadsOnAllCpus({-1}); 129} 130 131bool EventSelectionSet::OpenEventFilesForThreads(const std::vector<pid_t>& threads) { 132 return OpenEventFiles(threads, {-1}); 133} 134 135bool EventSelectionSet::OpenEventFilesForThreadsOnAllCpus(const std::vector<pid_t>& threads) { 136 std::vector<int> cpus = GetOnlineCpus(); 137 if (cpus.empty()) { 138 return false; 139 } 140 return OpenEventFiles(threads, cpus); 141} 142 143bool EventSelectionSet::OpenEventFiles(const std::vector<pid_t>& threads, 144 const std::vector<int>& cpus) { 145 for (auto& selection : selections_) { 146 for (auto& tid : threads) { 147 size_t open_per_thread = 0; 148 for (auto& cpu : cpus) { 149 auto event_fd = EventFd::OpenEventFile(selection.event_attr, tid, cpu); 150 if (event_fd != nullptr) { 151 selection.event_fds.push_back(std::move(event_fd)); 152 ++open_per_thread; 153 } 154 } 155 // As the online cpus can be enabled or disabled at runtime, we may not open event file for 156 // all cpus successfully. But we should open at least one cpu successfully. 157 if (open_per_thread == 0) { 158 PLOG(ERROR) << "failed to open perf event file for event_type " << selection.event_type.name 159 << " for " 160 << (tid == -1 ? "all threads" : android::base::StringPrintf(" thread %d", tid)); 161 return false; 162 } 163 } 164 } 165 return true; 166} 167 168bool EventSelectionSet::EnableEvents() { 169 for (auto& selection : selections_) { 170 for (auto& event_fd : selection.event_fds) { 171 if (!event_fd->EnableEvent()) { 172 return false; 173 } 174 } 175 } 176 return true; 177} 178 179bool EventSelectionSet::ReadCounters( 180 std::map<const EventType*, std::vector<PerfCounter>>* counters_map) { 181 for (auto& selection : selections_) { 182 std::vector<PerfCounter> counters; 183 for (auto& event_fd : selection.event_fds) { 184 PerfCounter counter; 185 if (!event_fd->ReadCounter(&counter)) { 186 return false; 187 } 188 counters.push_back(counter); 189 } 190 counters_map->insert(std::make_pair(&selection.event_type, counters)); 191 } 192 return true; 193} 194 195void EventSelectionSet::PreparePollForEventFiles(std::vector<pollfd>* pollfds) { 196 for (auto& selection : selections_) { 197 for (auto& event_fd : selection.event_fds) { 198 pollfd poll_fd; 199 event_fd->PreparePollForMmapData(&poll_fd); 200 pollfds->push_back(poll_fd); 201 } 202 } 203} 204 205bool EventSelectionSet::MmapEventFiles(size_t mmap_pages) { 206 for (auto& selection : selections_) { 207 for (auto& event_fd : selection.event_fds) { 208 if (!event_fd->MmapContent(mmap_pages)) { 209 return false; 210 } 211 } 212 } 213 return true; 214} 215 216static bool ReadMmapEventDataForFd(std::unique_ptr<EventFd>& event_fd, 217 std::function<bool(const char*, size_t)> callback, 218 bool* have_data) { 219 *have_data = false; 220 while (true) { 221 char* data; 222 size_t size = event_fd->GetAvailableMmapData(&data); 223 if (size == 0) { 224 break; 225 } 226 if (!callback(data, size)) { 227 return false; 228 } 229 *have_data = true; 230 event_fd->DiscardMmapData(size); 231 } 232 return true; 233} 234 235bool EventSelectionSet::ReadMmapEventData(std::function<bool(const char*, size_t)> callback) { 236 for (auto& selection : selections_) { 237 for (auto& event_fd : selection.event_fds) { 238 while (true) { 239 bool have_data; 240 if (!ReadMmapEventDataForFd(event_fd, callback, &have_data)) { 241 return false; 242 } 243 if (!have_data) { 244 break; 245 } 246 } 247 } 248 } 249 return true; 250} 251 252std::string EventSelectionSet::FindEventFileNameById(uint64_t id) { 253 for (auto& selection : selections_) { 254 for (auto& event_fd : selection.event_fds) { 255 if (event_fd->Id() == id) { 256 return event_fd->Name(); 257 } 258 } 259 } 260 return ""; 261} 262 263EventSelectionSet::EventSelection* EventSelectionSet::FindSelectionByType( 264 const EventType& event_type) { 265 for (auto& selection : selections_) { 266 if (selection.event_type.name == event_type.name) { 267 return &selection; 268 } 269 } 270 return nullptr; 271} 272 273const perf_event_attr& EventSelectionSet::FindEventAttrByType(const EventType& event_type) { 274 return FindSelectionByType(event_type)->event_attr; 275} 276 277const std::vector<std::unique_ptr<EventFd>>& EventSelectionSet::FindEventFdsByType( 278 const EventType& event_type) { 279 return FindSelectionByType(event_type)->event_fds; 280} 281