• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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