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