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