1 /* 2 * Copyright (C) 2017 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 #define SIMPLEPERF_EXPORT __attribute__((visibility("default"))) 18 #include "include/simpleperf.h" 19 20 #include <memory> 21 #include <set> 22 #include <string> 23 #include <vector> 24 25 #include <android-base/logging.h> 26 27 #include "environment.h" 28 #include "event_attr.h" 29 #include "event_fd.h" 30 #include "event_selection_set.h" 31 #include "event_type.h" 32 33 namespace simpleperf { 34 35 std::vector<std::string> GetAllEvents() { 36 std::vector<std::string> result; 37 if (!CheckPerfEventLimit()) { 38 return result; 39 } 40 for (auto& type : GetAllEventTypes()) { 41 perf_event_attr attr = CreateDefaultPerfEventAttr(type); 42 if (IsEventAttrSupported(attr, type.name)) { 43 result.push_back(type.name); 44 } 45 } 46 return result; 47 } 48 49 bool IsEventSupported(const std::string& name) { 50 if (!CheckPerfEventLimit()) { 51 return false; 52 } 53 std::unique_ptr<EventTypeAndModifier> type = ParseEventType(name); 54 if (type == nullptr) { 55 return false; 56 } 57 perf_event_attr attr = CreateDefaultPerfEventAttr(type->event_type); 58 return IsEventAttrSupported(attr, type->name); 59 } 60 61 class PerfEventSetImpl : public PerfEventSet { 62 public: 63 virtual ~PerfEventSetImpl() {} 64 65 bool AddEvent(const std::string& name) override { 66 if (!IsEventSupported(name)) { 67 return false; 68 } 69 event_names_.push_back(name); 70 return true; 71 } 72 73 bool MonitorCurrentProcess() override { 74 whole_process_ = true; 75 return true; 76 } 77 78 bool MonitorCurrentThread() override { 79 whole_process_ = false; 80 threads_.insert(gettid()); 81 return true; 82 } 83 84 bool MonitorThreadsInCurrentProcess(const std::vector<pid_t>& threads) override { 85 whole_process_ = false; 86 std::vector<pid_t> tids = GetThreadsInProcess(getpid()); 87 for (auto& tid : threads) { 88 if (std::find(tids.begin(), tids.end(), tid) == tids.end()) { 89 LOG(ERROR) << "Thread " << tid << " doesn't exist in current process."; 90 return false; 91 } 92 } 93 threads_.insert(threads.begin(), threads.end()); 94 return true; 95 } 96 97 protected: 98 PerfEventSetImpl() : whole_process_(false) {} 99 100 std::vector<std::string> event_names_; 101 bool whole_process_; 102 std::set<pid_t> threads_; 103 }; 104 105 class PerfEventSetForCounting : public PerfEventSetImpl { 106 public: 107 PerfEventSetForCounting() : in_counting_state_(false) {} 108 virtual ~PerfEventSetForCounting() {} 109 110 bool StartCounters() override; 111 bool StopCounters() override; 112 bool ReadCounters(std::vector<Counter>* counters) override; 113 114 private: 115 bool CreateEventSelectionSet(); 116 void InitAccumulatedCounters(); 117 bool ReadRawCounters(std::vector<Counter>* counters); 118 // Add counter b to a. 119 void AddCounter(Counter& a, const Counter& b); 120 // Sub counter b from a. 121 void SubCounter(Counter& a, const Counter& b); 122 123 bool in_counting_state_; 124 std::unique_ptr<EventSelectionSet> event_selection_set_; 125 // The counters at the last time calling StartCounting(). 126 std::vector<Counter> last_start_counters_; 127 // The accumulated counters of counting periods, excluding 128 // the last one. 129 std::vector<Counter> accumulated_counters_; 130 }; 131 132 bool PerfEventSetForCounting::CreateEventSelectionSet() { 133 std::unique_ptr<EventSelectionSet> set(new EventSelectionSet(true)); 134 if (event_names_.empty()) { 135 LOG(ERROR) << "No events."; 136 return false; 137 } 138 for (const auto& name : event_names_) { 139 if (!set->AddEventType(name)) { 140 return false; 141 } 142 } 143 if (whole_process_) { 144 set->AddMonitoredProcesses({getpid()}); 145 } else { 146 if (threads_.empty()) { 147 LOG(ERROR) << "No monitored threads."; 148 return false; 149 } 150 set->AddMonitoredThreads(threads_); 151 } 152 if (!set->OpenEventFiles({-1})) { 153 return false; 154 } 155 event_selection_set_ = std::move(set); 156 return true; 157 } 158 159 void PerfEventSetForCounting::InitAccumulatedCounters() { 160 for (const auto& name : event_names_) { 161 Counter counter; 162 counter.event = name; 163 counter.value = 0; 164 counter.time_enabled_in_ns = 0; 165 counter.time_running_in_ns = 0; 166 accumulated_counters_.push_back(counter); 167 } 168 } 169 170 bool PerfEventSetForCounting::ReadRawCounters(std::vector<Counter>* counters) { 171 CHECK(event_selection_set_); 172 std::vector<CountersInfo> s; 173 if (!event_selection_set_->ReadCounters(&s)) { 174 return false; 175 } 176 CHECK_EQ(s.size(), event_names_.size()); 177 counters->resize(s.size()); 178 for (size_t i = 0; i < s.size(); ++i) { 179 CountersInfo& info = s[i]; 180 std::string name = info.event_modifier.empty() ? info.event_name : 181 info.event_name + ":" + info.event_modifier; 182 CHECK_EQ(name, event_names_[i]); 183 Counter& sum = (*counters)[i]; 184 sum.event = name; 185 sum.value = 0; 186 sum.time_enabled_in_ns = 0; 187 sum.time_running_in_ns = 0; 188 for (CounterInfo& c : info.counters) { 189 sum.value += c.counter.value; 190 sum.time_enabled_in_ns += c.counter.time_enabled; 191 sum.time_running_in_ns += c.counter.time_running; 192 } 193 } 194 return true; 195 } 196 197 void PerfEventSetForCounting::AddCounter(Counter& a, const Counter& b) { 198 a.value += b.value; 199 a.time_enabled_in_ns += b.time_enabled_in_ns; 200 a.time_running_in_ns += b.time_enabled_in_ns; 201 } 202 203 void PerfEventSetForCounting::SubCounter(Counter& a, const Counter& b) { 204 a.value -= b.value; 205 a.time_enabled_in_ns -= b.time_enabled_in_ns; 206 a.time_running_in_ns -= b.time_running_in_ns; 207 } 208 209 bool PerfEventSetForCounting::StartCounters() { 210 if (in_counting_state_) { 211 return true; 212 } 213 if (event_selection_set_ == nullptr) { 214 if (!CreateEventSelectionSet()) { 215 return false; 216 } 217 InitAccumulatedCounters(); 218 } 219 if (!ReadRawCounters(&last_start_counters_)) { 220 return false; 221 } 222 in_counting_state_ = true; 223 return true; 224 } 225 226 bool PerfEventSetForCounting::StopCounters() { 227 if (!in_counting_state_) { 228 return true; 229 } 230 std::vector<Counter> cur; 231 if (!ReadRawCounters(&cur)) { 232 return false; 233 } 234 for (size_t i = 0; i < event_names_.size(); ++i) { 235 SubCounter(cur[i], last_start_counters_[i]); 236 AddCounter(accumulated_counters_[i], cur[i]); 237 } 238 in_counting_state_ = false; 239 return true; 240 } 241 242 bool PerfEventSetForCounting::ReadCounters(std::vector<Counter>* counters) { 243 if (!in_counting_state_) { 244 *counters = accumulated_counters_; 245 return true; 246 } 247 if (!ReadRawCounters(counters)) { 248 return false; 249 } 250 for (size_t i = 0; i < event_names_.size(); ++i) { 251 SubCounter((*counters)[i], last_start_counters_[i]); 252 AddCounter((*counters)[i], accumulated_counters_[i]); 253 } 254 return true; 255 } 256 257 PerfEventSet* PerfEventSet::CreateInstance(PerfEventSet::Type type) { 258 if (!CheckPerfEventLimit()) { 259 return nullptr; 260 } 261 if (type == Type::kPerfForCounting) { 262 return new PerfEventSetForCounting; 263 } 264 return nullptr; 265 } 266 267 bool PerfEventSet::AddEvent(const std::string&) { 268 return false; 269 } 270 271 bool PerfEventSet::MonitorCurrentProcess() { 272 return false; 273 } 274 275 bool PerfEventSet::MonitorCurrentThread() { 276 return false; 277 } 278 279 bool PerfEventSet::MonitorThreadsInCurrentProcess(const std::vector<pid_t>&) { 280 return false; 281 } 282 283 bool PerfEventSet::StartCounters() { 284 return false; 285 } 286 287 bool PerfEventSet::StopCounters() { 288 return false; 289 } 290 291 bool PerfEventSet::ReadCounters(std::vector<Counter>*) { 292 return false; 293 } 294 295 } // namespace simpleperf 296