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 21#include "environment.h" 22#include "event_attr.h" 23#include "event_type.h" 24 25void EventSelectionSet::AddEventType(const EventType& event_type) { 26 EventSelection selection; 27 selection.event_type = &event_type; 28 selection.event_attr = CreateDefaultPerfEventAttr(event_type); 29 selections_.push_back(std::move(selection)); 30} 31 32void EventSelectionSet::EnableOnExec() { 33 for (auto& selection : selections_) { 34 selection.event_attr.enable_on_exec = 1; 35 } 36} 37 38void EventSelectionSet::SampleIdAll() { 39 for (auto& selection : selections_) { 40 selection.event_attr.sample_id_all = 1; 41 } 42} 43 44void EventSelectionSet::SetSampleFreq(uint64_t sample_freq) { 45 for (auto& selection : selections_) { 46 perf_event_attr& attr = selection.event_attr; 47 attr.freq = 1; 48 attr.sample_freq = sample_freq; 49 } 50} 51 52void EventSelectionSet::SetSamplePeriod(uint64_t sample_period) { 53 for (auto& selection : selections_) { 54 perf_event_attr& attr = selection.event_attr; 55 attr.freq = 0; 56 attr.sample_period = sample_period; 57 } 58} 59 60bool EventSelectionSet::OpenEventFilesForAllCpus() { 61 std::vector<int> cpus = GetOnlineCpus(); 62 if (cpus.empty()) { 63 return false; 64 } 65 for (auto& selection : selections_) { 66 for (auto& cpu : cpus) { 67 auto event_fd = EventFd::OpenEventFileForCpu(selection.event_attr, cpu); 68 if (event_fd != nullptr) { 69 selection.event_fds.push_back(std::move(event_fd)); 70 } 71 } 72 // As the online cpus can be enabled or disabled at runtime, we may not open event file for 73 // all cpus successfully. But we should open at least one cpu successfully. 74 if (selection.event_fds.empty()) { 75 LOG(ERROR) << "failed to open perf event file for event_type " << selection.event_type->name 76 << " on all cpus"; 77 return false; 78 } 79 } 80 return true; 81} 82 83bool EventSelectionSet::OpenEventFilesForProcess(pid_t pid) { 84 for (auto& selection : selections_) { 85 auto event_fd = EventFd::OpenEventFileForProcess(selection.event_attr, pid); 86 if (event_fd == nullptr) { 87 PLOG(ERROR) << "failed to open perf event file for event type " << selection.event_type->name 88 << " on pid " << pid; 89 return false; 90 } 91 selection.event_fds.push_back(std::move(event_fd)); 92 } 93 return true; 94} 95 96bool EventSelectionSet::EnableEvents() { 97 for (auto& selection : selections_) { 98 for (auto& event_fd : selection.event_fds) { 99 if (!event_fd->EnableEvent()) { 100 return false; 101 } 102 } 103 } 104 return true; 105} 106 107bool EventSelectionSet::ReadCounters( 108 std::map<const EventType*, std::vector<PerfCounter>>* counters_map) { 109 for (auto& selection : selections_) { 110 std::vector<PerfCounter> counters; 111 for (auto& event_fd : selection.event_fds) { 112 PerfCounter counter; 113 if (!event_fd->ReadCounter(&counter)) { 114 return false; 115 } 116 counters.push_back(counter); 117 } 118 counters_map->insert(std::make_pair(selection.event_type, counters)); 119 } 120 return true; 121} 122 123void EventSelectionSet::PreparePollForEventFiles(std::vector<pollfd>* pollfds) { 124 for (auto& selection : selections_) { 125 for (auto& event_fd : selection.event_fds) { 126 pollfd poll_fd; 127 event_fd->PreparePollForMmapData(&poll_fd); 128 pollfds->push_back(poll_fd); 129 } 130 } 131} 132 133bool EventSelectionSet::MmapEventFiles(size_t mmap_pages) { 134 for (auto& selection : selections_) { 135 for (auto& event_fd : selection.event_fds) { 136 if (!event_fd->MmapContent(mmap_pages)) { 137 return false; 138 } 139 } 140 } 141 return true; 142} 143 144static bool ReadMmapEventDataForFd(std::unique_ptr<EventFd>& event_fd, 145 std::function<bool(const char*, size_t)> callback, 146 bool* have_data) { 147 *have_data = false; 148 while (true) { 149 char* data; 150 size_t size = event_fd->GetAvailableMmapData(&data); 151 if (size == 0) { 152 break; 153 } 154 if (!callback(data, size)) { 155 return false; 156 } 157 *have_data = true; 158 event_fd->DiscardMmapData(size); 159 } 160 return true; 161} 162 163bool EventSelectionSet::ReadMmapEventData(std::function<bool(const char*, size_t)> callback) { 164 for (auto& selection : selections_) { 165 for (auto& event_fd : selection.event_fds) { 166 while (true) { 167 bool have_data; 168 if (!ReadMmapEventDataForFd(event_fd, callback, &have_data)) { 169 return false; 170 } 171 if (!have_data) { 172 break; 173 } 174 } 175 } 176 } 177 return true; 178} 179 180std::string EventSelectionSet::FindEventFileNameById(uint64_t id) { 181 for (auto& selection : selections_) { 182 for (auto& event_fd : selection.event_fds) { 183 if (event_fd->Id() == id) { 184 return event_fd->Name(); 185 } 186 } 187 } 188 return ""; 189} 190 191EventSelectionSet::EventSelection* EventSelectionSet::FindSelectionByType( 192 const EventType& event_type) { 193 for (auto& selection : selections_) { 194 if (strcmp(selection.event_type->name, event_type.name) == 0) { 195 return &selection; 196 } 197 } 198 return nullptr; 199} 200 201const perf_event_attr& EventSelectionSet::FindEventAttrByType(const EventType& event_type) { 202 return FindSelectionByType(event_type)->event_attr; 203} 204 205const std::vector<std::unique_ptr<EventFd>>& EventSelectionSet::FindEventFdsByType( 206 const EventType& event_type) { 207 return FindSelectionByType(event_type)->event_fds; 208} 209