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 void LoadBuiltinEventTypes(std::set<EventType>&);
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 { LoadBuiltinEventTypes(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
GetIntelAtomCpuConfig() const466 uint64_t EventType::GetIntelAtomCpuConfig() const {
467 if (auto pos = limited_arch.find("atom="); pos != std::string::npos) {
468 uint64_t atom_config;
469 if (android::base::ParseUint(limited_arch.substr(pos + 5), &atom_config)) {
470 return atom_config;
471 }
472 }
473 return config;
474 }
475
BuildString(const std::vector<const EventType * > & event_types)476 std::string ScopedEventTypes::BuildString(const std::vector<const EventType*>& event_types) {
477 std::string result;
478 for (auto type : event_types) {
479 if (!result.empty()) {
480 result.push_back('\n');
481 }
482 result +=
483 android::base::StringPrintf("%s,%u,%" PRIu64, type->name.c_str(), type->type, type->config);
484 }
485 return result;
486 }
487
ScopedEventTypes(const std::string & event_type_str)488 ScopedEventTypes::ScopedEventTypes(const std::string& event_type_str) {
489 std::set<EventType> event_types;
490 for (auto& s : android::base::Split(event_type_str, "\n")) {
491 std::string name = s.substr(0, s.find(','));
492 uint32_t type;
493 uint64_t config;
494 sscanf(s.c_str() + name.size(), ",%u,%" PRIu64, &type, &config);
495 event_types.emplace(name, type, config, "", "");
496 }
497 CHECK(EventTypeManager::Instance().GetScopedFinder() == nullptr);
498 EventTypeManager::Instance().SetScopedFinder(
499 std::make_unique<ScopedTypeFinder>(std::move(event_types)));
500 }
501
~ScopedEventTypes()502 ScopedEventTypes::~ScopedEventTypes() {
503 CHECK(EventTypeManager::Instance().GetScopedFinder() != nullptr);
504 EventTypeManager::Instance().SetScopedFinder(nullptr);
505 }
506
FindEventTypeByName(const std::string & name,bool report_error)507 const EventType* FindEventTypeByName(const std::string& name, bool report_error) {
508 const EventType* event_type = EventTypeManager::Instance().FindType(name);
509 if (event_type != nullptr) {
510 return event_type;
511 }
512 event_type = EventTypeManager::Instance().AddRawType(name);
513 if (event_type != nullptr) {
514 return event_type;
515 }
516 if (report_error) {
517 LOG(ERROR) << "Unknown event_type '" << name
518 << "', try `simpleperf list` to list all possible event type names";
519 }
520 return nullptr;
521 }
522
ParseEventType(const std::string & event_type_str)523 std::unique_ptr<EventTypeAndModifier> ParseEventType(const std::string& event_type_str) {
524 static std::string modifier_characters = "ukhGHp";
525 std::unique_ptr<EventTypeAndModifier> event_type_modifier(new EventTypeAndModifier);
526 event_type_modifier->name = event_type_str;
527 std::string event_type_name = event_type_str;
528 std::string modifier;
529 size_t comm_pos = event_type_str.rfind(':');
530 if (comm_pos != std::string::npos) {
531 bool match_modifier = true;
532 for (size_t i = comm_pos + 1; i < event_type_str.size(); ++i) {
533 char c = event_type_str[i];
534 if (c != ' ' && modifier_characters.find(c) == std::string::npos) {
535 match_modifier = false;
536 break;
537 }
538 }
539 if (match_modifier) {
540 event_type_name = event_type_str.substr(0, comm_pos);
541 modifier = event_type_str.substr(comm_pos + 1);
542 }
543 }
544 const EventType* event_type = FindEventTypeByName(event_type_name);
545 if (event_type == nullptr) {
546 // Try if the modifier belongs to the event type name, like some tracepoint events.
547 if (!modifier.empty()) {
548 event_type_name = event_type_str;
549 modifier.clear();
550 event_type = FindEventTypeByName(event_type_name);
551 }
552 if (event_type == nullptr) {
553 return nullptr;
554 }
555 }
556 event_type_modifier->event_type = *event_type;
557 if (modifier.find_first_of("ukh") != std::string::npos) {
558 event_type_modifier->exclude_user = true;
559 event_type_modifier->exclude_kernel = true;
560 event_type_modifier->exclude_hv = true;
561 }
562 if (modifier.find_first_of("GH") != std::string::npos) {
563 event_type_modifier->exclude_guest = true;
564 event_type_modifier->exclude_host = true;
565 }
566
567 for (auto& c : modifier) {
568 switch (c) {
569 case 'u':
570 event_type_modifier->exclude_user = false;
571 break;
572 case 'k':
573 event_type_modifier->exclude_kernel = false;
574 break;
575 case 'h':
576 event_type_modifier->exclude_hv = false;
577 break;
578 case 'G':
579 event_type_modifier->exclude_guest = false;
580 break;
581 case 'H':
582 event_type_modifier->exclude_host = false;
583 break;
584 case 'p':
585 event_type_modifier->precise_ip++;
586 break;
587 case ' ':
588 break;
589 default:
590 LOG(ERROR) << "Unknown event type modifier '" << c << "'";
591 }
592 }
593 event_type_modifier->modifier = modifier;
594 return event_type_modifier;
595 }
596
IsEtmEventType(uint32_t type)597 bool IsEtmEventType(uint32_t type) {
598 const EventType* event_type = EventTypeManager::Instance().FindType(kETMEventName);
599 return (event_type != nullptr) && (event_type->type == type);
600 }
601
602 } // namespace simpleperf
603