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