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
33namespace simpleperf {
34
35std::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)) {
43      result.push_back(type.name);
44    }
45  }
46  return result;
47}
48
49bool 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);
59}
60
61class 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
105class 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
132bool 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
159void 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
170bool 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
197void 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
203void 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
209bool 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
226bool 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
242bool 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
257PerfEventSet* 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
267bool PerfEventSet::AddEvent(const std::string&) {
268  return false;
269}
270
271bool PerfEventSet::MonitorCurrentProcess() {
272  return false;
273}
274
275bool PerfEventSet::MonitorCurrentThread() {
276  return false;
277}
278
279bool PerfEventSet::MonitorThreadsInCurrentProcess(const std::vector<pid_t>&) {
280  return false;
281}
282
283bool PerfEventSet::StartCounters() {
284  return false;
285}
286
287bool PerfEventSet::StopCounters() {
288  return false;
289}
290
291bool PerfEventSet::ReadCounters(std::vector<Counter>*) {
292  return false;
293}
294
295}  // namespace simpleperf
296