• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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 #include "event_type.h"
18 
19 #include <inttypes.h>
20 #include <unistd.h>
21 #include <algorithm>
22 #include <string>
23 #include <vector>
24 
25 #include <android-base/file.h>
26 #include <android-base/logging.h>
27 #include <android-base/parseint.h>
28 #include <android-base/stringprintf.h>
29 #include <android-base/strings.h>
30 
31 #include "ETMRecorder.h"
32 #include "environment.h"
33 #include "event_attr.h"
34 #include "utils.h"
35 
36 namespace simpleperf {
37 
38 struct EventFormat {
EventFormatsimpleperf::EventFormat39   EventFormat(const std::string& name, const std::string& attr, int shift)
40       : name(name), attr(attr), shift(shift) {}
41 
42   std::string name;
43   std::string attr;
44   int shift;
45 };
46 
47 #define EVENT_TYPE_TABLE_ENTRY(name, type, config, description, limited_arch) \
48   {name, type, config, description, limited_arch},
49 
50 static const std::set<EventType> builtin_event_types = {
51 #include "event_type_table.h"
52 };
53 
54 enum class EventFinderType {
55   BUILTIN,
56   TRACEPOINT_STRING,
57   TRACEPOINT_SYSTEM,
58   PMU,
59   ETM,
60   RAW,
61   SCOPED,
62 };
63 
64 class EventTypeFinder {
65  public:
EventTypeFinder(EventFinderType type)66   EventTypeFinder(EventFinderType type) : finder_type_(type) {}
~EventTypeFinder()67   virtual ~EventTypeFinder() {}
68 
GetFinderType() const69   EventFinderType GetFinderType() const { return finder_type_; }
70 
GetTypes()71   const std::set<EventType>& GetTypes() {
72     if (!loaded_) {
73       loaded_ = true;
74       LoadTypes();
75     }
76     return types_;
77   }
78 
FindType(const std::string & name)79   virtual const EventType* FindType(const std::string& name) {
80     const auto& types = GetTypes();
81     auto it = types.find(EventType(name, 0, 0, "", ""));
82     if (it != types.end()) {
83       return &*it;
84     }
85     return nullptr;
86   }
87 
88  protected:
89   virtual void LoadTypes() = 0;
90 
91   const EventFinderType finder_type_;
92   std::set<EventType> types_;
93   bool loaded_ = false;
94 };
95 
96 class BuiltinTypeFinder : public EventTypeFinder {
97  public:
BuiltinTypeFinder()98   BuiltinTypeFinder() : EventTypeFinder(EventFinderType::BUILTIN) {}
99 
100  protected:
LoadTypes()101   void LoadTypes() override { types_ = std::move(builtin_event_types); }
102 };
103 
104 class TracepointStringFinder : public EventTypeFinder {
105  public:
TracepointStringFinder(std::string && s)106   TracepointStringFinder(std::string&& s)
107       : EventTypeFinder(EventFinderType::TRACEPOINT_STRING), s_(std::move(s)) {}
108 
109  protected:
LoadTypes()110   void LoadTypes() override {
111     for (const auto& line : android::base::Split(s_, "\n")) {
112       std::vector<std::string> items = android::base::Split(line, " ");
113       CHECK_EQ(items.size(), 2u);
114       std::string event_name = items[0];
115       uint64_t id;
116       CHECK(android::base::ParseUint(items[1].c_str(), &id));
117       types_.emplace(event_name, PERF_TYPE_TRACEPOINT, id, "", "");
118     }
119   }
120 
121  private:
122   const std::string s_;
123 };
124 
125 class TracepointSystemFinder : public EventTypeFinder {
126  public:
TracepointSystemFinder()127   TracepointSystemFinder() : EventTypeFinder(EventFinderType::TRACEPOINT_SYSTEM) {}
128 
FindType(const std::string & name)129   const EventType* FindType(const std::string& name) override {
130     if (auto it = types_.find(EventType(name, 0, 0, "", "")); it != types_.end()) {
131       return &*it;
132     }
133     std::vector<std::string> strs = android::base::Split(name, ":");
134     if (strs.size() != 2) {
135       return nullptr;
136     }
137     const char* tracefs_dir = GetTraceFsDir();
138     if (tracefs_dir == nullptr) {
139       return nullptr;
140     }
141     std::string path = tracefs_dir + std::string("/events/") + strs[0] + "/" + strs[1] + "/id";
142     uint64_t id;
143     if (!ReadEventId(path, &id)) {
144       return nullptr;
145     }
146     auto res = types_.emplace(name, PERF_TYPE_TRACEPOINT, id, "", "");
147     return &*res.first;
148   }
149 
RemoveType(const std::string & name)150   void RemoveType(const std::string& name) { types_.erase(EventType(name, 0, 0, "", "")); }
151 
ToString()152   std::string ToString() {
153     std::string result;
154     for (auto& type : GetTypes()) {
155       if (!result.empty()) {
156         result.push_back('\n');
157       }
158       result += android::base::StringPrintf("%s %" PRIu64, type.name.c_str(), type.config);
159     }
160     return result;
161   }
162 
163  protected:
LoadTypes()164   void LoadTypes() override {
165     const char* tracefs_dir = GetTraceFsDir();
166     if (tracefs_dir == nullptr) {
167       return;
168     }
169     const std::string tracepoint_dirname = tracefs_dir + std::string("/events");
170     for (const auto& system_name : GetSubDirs(tracepoint_dirname)) {
171       std::string system_path = tracepoint_dirname + "/" + system_name;
172       for (const auto& event_name : GetSubDirs(system_path)) {
173         std::string id_path = system_path + "/" + event_name + "/id";
174         uint64_t id;
175         if (ReadEventId(id_path, &id)) {
176           types_.emplace(system_name + ":" + event_name, PERF_TYPE_TRACEPOINT, id, "", "");
177         }
178       }
179     }
180   }
181 
182  private:
ReadEventId(const std::string & id_path,uint64_t * id)183   bool ReadEventId(const std::string& id_path, uint64_t* id) {
184     std::string id_content;
185     if (!android::base::ReadFileToString(id_path, &id_content)) {
186       return false;
187     }
188     if (!android::base::ParseUint(android::base::Trim(id_content), id)) {
189       LOG(DEBUG) << "unexpected id '" << id_content << "' in " << id_path;
190       return false;
191     }
192     return true;
193   }
194 };
195 
196 class PMUTypeFinder : public EventTypeFinder {
197  public:
PMUTypeFinder()198   PMUTypeFinder() : EventTypeFinder(EventFinderType::PMU) {}
199 
FindType(const std::string & name)200   const EventType* FindType(const std::string& name) override {
201     if (name.find('/') == std::string::npos) {
202       return nullptr;
203     }
204     return EventTypeFinder::FindType(name);
205   }
206 
207  protected:
LoadTypes()208   void LoadTypes() override {
209     const std::string evtsrc_dirname = "/sys/bus/event_source/devices/";
210     for (const auto& device_name : GetSubDirs(evtsrc_dirname)) {
211       std::string evtdev_path = evtsrc_dirname + device_name;
212       std::string type_path = evtdev_path + "/type";
213       std::string type_content;
214 
215       if (!android::base::ReadFileToString(type_path, &type_content)) {
216         LOG(DEBUG) << "cannot read event type: " << device_name;
217         continue;
218       }
219       uint64_t type_id = strtoull(type_content.c_str(), NULL, 10);
220 
221       std::vector<EventFormat> formats = ParseEventFormats(evtdev_path);
222 
223       std::string events_dirname = evtdev_path + "/events/";
224       for (const auto& event_name : GetEntriesInDir(events_dirname)) {
225         std::string event_path = events_dirname + event_name;
226         std::string event_content;
227         if (!android::base::ReadFileToString(event_path, &event_content)) {
228           LOG(DEBUG) << "cannot read event content in " << event_name;
229           continue;
230         }
231 
232         uint64_t config = MakeEventConfig(event_content, formats);
233         if (config == ~0ULL) {
234           LOG(DEBUG) << "cannot handle config format in " << event_name;
235           continue;
236         }
237         types_.emplace(device_name + "/" + event_name + "/", type_id, config, "", "");
238       }
239     }
240   }
241 
242  private:
ParseEventFormats(const std::string & evtdev_path)243   std::vector<EventFormat> ParseEventFormats(const std::string& evtdev_path) {
244     std::vector<EventFormat> v;
245     std::string formats_dirname = evtdev_path + "/format/";
246     for (const auto& format_name : GetEntriesInDir(formats_dirname)) {
247       std::string format_path = formats_dirname + format_name;
248       std::string format_content;
249       if (!android::base::ReadFileToString(format_path, &format_content)) {
250         continue;
251       }
252 
253       // format files look like below (currently only 'config' is supported) :
254       //   # cat armv8_pmuv3/format/event
255       //   config:0-15
256       int shift;
257       if (sscanf(format_content.c_str(), "config:%d", &shift) != 1) {
258         LOG(DEBUG) << "Invalid or unsupported event format: " << format_content;
259         continue;
260       }
261 
262       v.emplace_back(EventFormat(format_name, "config", shift));
263     }
264     return v;
265   }
266 
MakeEventConfig(const std::string & event_str,std::vector<EventFormat> & formats)267   uint64_t MakeEventConfig(const std::string& event_str, std::vector<EventFormat>& formats) {
268     uint64_t config = 0;
269 
270     // event files might have multiple terms, but usually have a term like:
271     //   # cat armv8_pmuv3/events/cpu_cycles
272     //   event=0x011
273     for (auto& s : android::base::Split(event_str, ",")) {
274       auto pos = s.find('=');
275       if (pos == std::string::npos) continue;
276 
277       auto format = s.substr(0, pos);
278       long val;
279       if (!android::base::ParseInt(android::base::Trim(s.substr(pos + 1)), &val)) {
280         LOG(DEBUG) << "Invalid event format '" << s << "'";
281         continue;
282       }
283 
284       for (auto& f : formats) {
285         if (f.name == format) {
286           if (f.attr != "config") {
287             LOG(DEBUG) << "cannot support other attribute: " << s;
288             return ~0ULL;
289           }
290 
291           config |= val << f.shift;
292           break;
293         }
294       }
295     }
296     return config;
297   }
298 };
299 
300 class ETMTypeFinder : public EventTypeFinder {
301  public:
ETMTypeFinder()302   ETMTypeFinder() : EventTypeFinder(EventFinderType::ETM) {}
303 
FindType(const std::string & name)304   const EventType* FindType(const std::string& name) override {
305     if (name != kETMEventName) {
306       return nullptr;
307     }
308     return EventTypeFinder::FindType(name);
309   }
310 
311  protected:
LoadTypes()312   void LoadTypes() override {
313 #if defined(__linux__)
314     std::unique_ptr<EventType> etm_type = ETMRecorder::GetInstance().BuildEventType();
315     if (etm_type) {
316       types_.emplace(std::move(*etm_type));
317     }
318 #endif
319   }
320 };
321 
322 class RawTypeFinder : public EventTypeFinder {
323  public:
RawTypeFinder()324   RawTypeFinder() : EventTypeFinder(EventFinderType::RAW) {}
325 
AddType(EventType && type)326   const EventType* AddType(EventType&& type) {
327     auto result = types_.emplace(std::move(type));
328     return &*(result.first);
329   }
330 
331  protected:
LoadTypes()332   void LoadTypes() override {}
333 };
334 
335 class ScopedTypeFinder : public EventTypeFinder {
336  public:
ScopedTypeFinder(std::set<EventType> && types)337   ScopedTypeFinder(std::set<EventType>&& types) : EventTypeFinder(EventFinderType::SCOPED) {
338     types_ = std::move(types);
339   }
340 
341  protected:
LoadTypes()342   void LoadTypes() override {}
343 };
344 
345 EventTypeManager EventTypeManager::instance_;
346 
EventTypeManager()347 EventTypeManager::EventTypeManager() {
348   type_finders_.emplace_back(new BuiltinTypeFinder());
349   type_finders_.emplace_back(new TracepointSystemFinder());
350   type_finders_.emplace_back(new PMUTypeFinder());
351   type_finders_.emplace_back(new ETMTypeFinder());
352   type_finders_.emplace_back(new RawTypeFinder());
353 }
354 
~EventTypeManager()355 EventTypeManager::~EventTypeManager() {}
356 
GetFinder(EventFinderType type)357 std::unique_ptr<EventTypeFinder>& EventTypeManager::GetFinder(EventFinderType type) {
358   for (auto& finder : type_finders_) {
359     if (finder->GetFinderType() == type) {
360       return finder;
361     }
362   }
363   LOG(FATAL) << "Failed to get EventTypeFinder";
364   __builtin_unreachable();
365 }
366 
GetRawTypeFinder()367 RawTypeFinder& EventTypeManager::GetRawTypeFinder() {
368   return *static_cast<RawTypeFinder*>(GetFinder(EventFinderType::RAW).get());
369 }
370 
GetTracepointSystemFinder()371 TracepointSystemFinder& EventTypeManager::GetTracepointSystemFinder() {
372   return *static_cast<TracepointSystemFinder*>(GetFinder(EventFinderType::TRACEPOINT_SYSTEM).get());
373 }
374 
ReadTracepointsFromFile(const std::string & filepath)375 bool EventTypeManager::ReadTracepointsFromFile(const std::string& filepath) {
376   std::string data;
377   if (!android::base::ReadFileToString(filepath, &data)) {
378     PLOG(ERROR) << "Failed to read " << filepath;
379     return false;
380   }
381   // Replace TracepointSystemFinder with TracepointStringFinder.
382   auto& finder = GetFinder(EventFinderType::TRACEPOINT_SYSTEM);
383   finder.reset(new TracepointStringFinder(std::move(data)));
384   return true;
385 }
386 
WriteTracepointsToFile(const std::string & filepath)387 bool EventTypeManager::WriteTracepointsToFile(const std::string& filepath) {
388   auto& tp_finder = GetTracepointSystemFinder();
389   std::string s = tp_finder.ToString();
390   if (!android::base::WriteStringToFile(s, filepath)) {
391     PLOG(ERROR) << "Failed to store tracepoint events";
392     return false;
393   }
394   return true;
395 }
396 
ForEachType(const std::function<bool (const EventType &)> & callback)397 bool EventTypeManager::ForEachType(const std::function<bool(const EventType&)>& callback) {
398   if (scoped_finder_) {
399     for (const auto& type : scoped_finder_->GetTypes()) {
400       if (!callback(type)) {
401         return false;
402       }
403     }
404   } else {
405     for (auto& finder : type_finders_) {
406       for (const auto& type : finder->GetTypes()) {
407         if (!callback(type)) {
408           return false;
409         }
410       }
411     }
412   }
413   return true;
414 }
415 
FindType(const std::string & name)416 const EventType* EventTypeManager::FindType(const std::string& name) {
417   if (scoped_finder_) {
418     return scoped_finder_->FindType(name);
419   }
420   for (auto& finder : type_finders_) {
421     if (auto type = finder->FindType(name)) {
422       return type;
423     }
424   }
425   return nullptr;
426 }
427 
AddRawType(const std::string & name)428 const EventType* EventTypeManager::AddRawType(const std::string& name) {
429   if (name.empty() || name[0] != 'r') {
430     return nullptr;
431   }
432   errno = 0;
433   char* end;
434   uint64_t config = strtoull(&name[1], &end, 16);
435   if (errno != 0 || *end != '\0') {
436     return nullptr;
437   }
438   auto& raw_finder = GetRawTypeFinder();
439   return raw_finder.AddType(EventType(name, PERF_TYPE_RAW, config, "", ""));
440 }
441 
RemoveProbeType(const std::string & name)442 void EventTypeManager::RemoveProbeType(const std::string& name) {
443   GetTracepointSystemFinder().RemoveType(name);
444 }
445 
SetScopedFinder(std::unique_ptr<EventTypeFinder> && finder)446 void EventTypeManager::SetScopedFinder(std::unique_ptr<EventTypeFinder>&& finder) {
447   scoped_finder_ = std::move(finder);
448 }
449 
GetPmuCpumask()450 std::vector<int> EventType::GetPmuCpumask() {
451   std::vector<int> empty_result;
452   if (!IsPmuEvent()) return empty_result;
453 
454   std::string pmu = name.substr(0, name.find('/'));
455   std::string cpumask_path = "/sys/bus/event_source/devices/" + pmu + "/cpumask";
456   std::string cpumask_content;
457   if (!android::base::ReadFileToString(cpumask_path, &cpumask_content)) {
458     LOG(DEBUG) << "cannot read cpumask content in " << pmu;
459     return empty_result;
460   }
461   if (auto cpus = GetCpusFromString(cpumask_content); cpus) {
462     return std::vector<int>(cpus->begin(), cpus->end());
463   }
464   return empty_result;
465 }
466 
BuildString(const std::vector<const EventType * > & event_types)467 std::string ScopedEventTypes::BuildString(const std::vector<const EventType*>& event_types) {
468   std::string result;
469   for (auto type : event_types) {
470     if (!result.empty()) {
471       result.push_back('\n');
472     }
473     result +=
474         android::base::StringPrintf("%s,%u,%" PRIu64, type->name.c_str(), type->type, type->config);
475   }
476   return result;
477 }
478 
ScopedEventTypes(const std::string & event_type_str)479 ScopedEventTypes::ScopedEventTypes(const std::string& event_type_str) {
480   std::set<EventType> event_types;
481   for (auto& s : android::base::Split(event_type_str, "\n")) {
482     std::string name = s.substr(0, s.find(','));
483     uint32_t type;
484     uint64_t config;
485     sscanf(s.c_str() + name.size(), ",%u,%" PRIu64, &type, &config);
486     event_types.emplace(name, type, config, "", "");
487   }
488   CHECK(EventTypeManager::Instance().GetScopedFinder() == nullptr);
489   EventTypeManager::Instance().SetScopedFinder(
490       std::make_unique<ScopedTypeFinder>(std::move(event_types)));
491 }
492 
~ScopedEventTypes()493 ScopedEventTypes::~ScopedEventTypes() {
494   CHECK(EventTypeManager::Instance().GetScopedFinder() != nullptr);
495   EventTypeManager::Instance().SetScopedFinder(nullptr);
496 }
497 
FindEventTypeByName(const std::string & name,bool report_error)498 const EventType* FindEventTypeByName(const std::string& name, bool report_error) {
499   const EventType* event_type = EventTypeManager::Instance().FindType(name);
500   if (event_type != nullptr) {
501     return event_type;
502   }
503   event_type = EventTypeManager::Instance().AddRawType(name);
504   if (event_type != nullptr) {
505     return event_type;
506   }
507   if (report_error) {
508     LOG(ERROR) << "Unknown event_type '" << name
509                << "', try `simpleperf list` to list all possible event type names";
510   }
511   return nullptr;
512 }
513 
ParseEventType(const std::string & event_type_str)514 std::unique_ptr<EventTypeAndModifier> ParseEventType(const std::string& event_type_str) {
515   static std::string modifier_characters = "ukhGHp";
516   std::unique_ptr<EventTypeAndModifier> event_type_modifier(new EventTypeAndModifier);
517   event_type_modifier->name = event_type_str;
518   std::string event_type_name = event_type_str;
519   std::string modifier;
520   size_t comm_pos = event_type_str.rfind(':');
521   if (comm_pos != std::string::npos) {
522     bool match_modifier = true;
523     for (size_t i = comm_pos + 1; i < event_type_str.size(); ++i) {
524       char c = event_type_str[i];
525       if (c != ' ' && modifier_characters.find(c) == std::string::npos) {
526         match_modifier = false;
527         break;
528       }
529     }
530     if (match_modifier) {
531       event_type_name = event_type_str.substr(0, comm_pos);
532       modifier = event_type_str.substr(comm_pos + 1);
533     }
534   }
535   const EventType* event_type = FindEventTypeByName(event_type_name);
536   if (event_type == nullptr) {
537     // Try if the modifier belongs to the event type name, like some tracepoint events.
538     if (!modifier.empty()) {
539       event_type_name = event_type_str;
540       modifier.clear();
541       event_type = FindEventTypeByName(event_type_name);
542     }
543     if (event_type == nullptr) {
544       return nullptr;
545     }
546   }
547   event_type_modifier->event_type = *event_type;
548   if (modifier.find_first_of("ukh") != std::string::npos) {
549     event_type_modifier->exclude_user = true;
550     event_type_modifier->exclude_kernel = true;
551     event_type_modifier->exclude_hv = true;
552   }
553   if (modifier.find_first_of("GH") != std::string::npos) {
554     event_type_modifier->exclude_guest = true;
555     event_type_modifier->exclude_host = true;
556   }
557 
558   for (auto& c : modifier) {
559     switch (c) {
560       case 'u':
561         event_type_modifier->exclude_user = false;
562         break;
563       case 'k':
564         event_type_modifier->exclude_kernel = false;
565         break;
566       case 'h':
567         event_type_modifier->exclude_hv = false;
568         break;
569       case 'G':
570         event_type_modifier->exclude_guest = false;
571         break;
572       case 'H':
573         event_type_modifier->exclude_host = false;
574         break;
575       case 'p':
576         event_type_modifier->precise_ip++;
577         break;
578       case ' ':
579         break;
580       default:
581         LOG(ERROR) << "Unknown event type modifier '" << c << "'";
582     }
583   }
584   event_type_modifier->modifier = modifier;
585   return event_type_modifier;
586 }
587 
IsEtmEventType(uint32_t type)588 bool IsEtmEventType(uint32_t type) {
589   const EventType* event_type = EventTypeManager::Instance().FindType(kETMEventName);
590   return (event_type != nullptr) && (event_type->type == type);
591 }
592 
593 }  // namespace simpleperf
594