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
GetAllEvents()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)) {
43 result.push_back(type.name);
44 }
45 }
46 return result;
47 }
48
IsEventSupported(const std::string & name)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);
59 }
60
61 class PerfEventSetImpl : public PerfEventSet {
62 public:
~PerfEventSetImpl()63 virtual ~PerfEventSetImpl() {}
64
AddEvent(const std::string & name)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
MonitorCurrentProcess()73 bool MonitorCurrentProcess() override {
74 whole_process_ = true;
75 return true;
76 }
77
MonitorCurrentThread()78 bool MonitorCurrentThread() override {
79 whole_process_ = false;
80 threads_.insert(gettid());
81 return true;
82 }
83
MonitorThreadsInCurrentProcess(const std::vector<pid_t> & threads)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:
PerfEventSetImpl()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:
PerfEventSetForCounting()107 PerfEventSetForCounting() : in_counting_state_(false) {}
~PerfEventSetForCounting()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
CreateEventSelectionSet()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
InitAccumulatedCounters()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
ReadRawCounters(std::vector<Counter> * counters)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
AddCounter(Counter & a,const Counter & b)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
SubCounter(Counter & a,const Counter & b)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
StartCounters()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
StopCounters()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
ReadCounters(std::vector<Counter> * counters)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
CreateInstance(PerfEventSet::Type type)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
AddEvent(const std::string &)267 bool PerfEventSet::AddEvent(const std::string&) {
268 return false;
269 }
270
MonitorCurrentProcess()271 bool PerfEventSet::MonitorCurrentProcess() {
272 return false;
273 }
274
MonitorCurrentThread()275 bool PerfEventSet::MonitorCurrentThread() {
276 return false;
277 }
278
MonitorThreadsInCurrentProcess(const std::vector<pid_t> &)279 bool PerfEventSet::MonitorThreadsInCurrentProcess(const std::vector<pid_t>&) {
280 return false;
281 }
282
StartCounters()283 bool PerfEventSet::StartCounters() {
284 return false;
285 }
286
StopCounters()287 bool PerfEventSet::StopCounters() {
288 return false;
289 }
290
ReadCounters(std::vector<Counter> *)291 bool PerfEventSet::ReadCounters(std::vector<Counter>*) {
292 return false;
293 }
294
295 } // namespace simpleperf
296