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 "environment.h" 32 #include "ETMRecorder.h" 33 #include "event_attr.h" 34 #include "utils.h" 35 36 using namespace simpleperf; 37 38 struct EventFormat { 39 EventFormat(const std::string& name, const std::string& attr, int shift) 40 : name(name), attr(attr), shift(shift) { 41 } 42 43 std::string name; 44 std::string attr; 45 int shift; 46 }; 47 48 #define EVENT_TYPE_TABLE_ENTRY(name, type, config, description, limited_arch) \ 49 {name, type, config, description, limited_arch}, 50 51 static const std::vector<EventType> static_event_type_array = { 52 #include "event_type_table.h" 53 }; 54 55 static std::string tracepoint_events; 56 static std::set<EventType> g_event_types; 57 static uint32_t g_etm_event_type; 58 59 bool SetTracepointEventsFilePath(const std::string& filepath) { 60 if (!android::base::ReadFileToString(filepath, &tracepoint_events)) { 61 PLOG(ERROR) << "Failed to read " << filepath; 62 return false; 63 } 64 return true; 65 } 66 67 std::string GetTracepointEvents() { 68 std::string result; 69 for (auto& event : GetAllEventTypes()) { 70 if (event.type != PERF_TYPE_TRACEPOINT) { 71 continue; 72 } 73 if (!result.empty()) { 74 result.push_back('\n'); 75 } 76 result += android::base::StringPrintf("%s %" PRIu64, event.name.c_str(), event.config); 77 } 78 return result; 79 } 80 81 static std::vector<EventType> GetTracepointEventTypesFromString(const std::string& s) { 82 std::vector<EventType> result; 83 for (auto& line : android::base::Split(s, "\n")) { 84 std::vector<std::string> items = android::base::Split(line, " "); 85 CHECK_EQ(items.size(), 2u); 86 std::string event_name = items[0]; 87 uint64_t id; 88 CHECK(android::base::ParseUint(items[1].c_str(), &id)); 89 result.push_back(EventType(event_name, PERF_TYPE_TRACEPOINT, id, "", "")); 90 } 91 return result; 92 } 93 94 static std::vector<EventType> GetTracepointEventTypesFromTraceFs() { 95 std::vector<EventType> result; 96 const char* tracefs_dir = GetTraceFsDir(); 97 if (tracefs_dir == nullptr) { 98 return result; 99 } 100 const std::string tracepoint_dirname = tracefs_dir + std::string("/events"); 101 for (const auto& system_name : GetSubDirs(tracepoint_dirname)) { 102 std::string system_path = tracepoint_dirname + "/" + system_name; 103 for (const auto& event_name : GetSubDirs(system_path)) { 104 std::string id_path = system_path + "/" + event_name + "/id"; 105 std::string id_content; 106 if (!android::base::ReadFileToString(id_path, &id_content)) { 107 continue; 108 } 109 char* endptr; 110 uint64_t id = strtoull(id_content.c_str(), &endptr, 10); 111 if (endptr == id_content.c_str()) { 112 LOG(DEBUG) << "unexpected id '" << id_content << "' in " << id_path; 113 continue; 114 } 115 result.push_back(EventType(system_name + ":" + event_name, PERF_TYPE_TRACEPOINT, id, "", "")); 116 } 117 } 118 return result; 119 } 120 121 static std::vector<EventType> GetTracepointEventTypes() { 122 std::vector<EventType> result; 123 if (!tracepoint_events.empty()) { 124 result = GetTracepointEventTypesFromString(tracepoint_events); 125 } else { 126 result = GetTracepointEventTypesFromTraceFs(); 127 } 128 std::sort(result.begin(), result.end(), 129 [](const EventType& type1, const EventType& type2) { return type1.name < type2.name; }); 130 return result; 131 } 132 133 static std::vector<EventFormat> ParseEventFormats(const std::string& evtdev_path) { 134 std::vector<EventFormat> v; 135 std::string formats_dirname = evtdev_path + "/format/"; 136 for (const auto& format_name : GetEntriesInDir(formats_dirname)) { 137 std::string format_path = formats_dirname + format_name; 138 std::string format_content; 139 if (!android::base::ReadFileToString(format_path, &format_content)) { 140 continue; 141 } 142 143 // format files look like below (currently only 'config' is supported) : 144 // # cat armv8_pmuv3/format/event 145 // config:0-15 146 int shift; 147 if (sscanf(format_content.c_str(), "config:%d", &shift) != 1) { 148 LOG(DEBUG) << "Invalid or unsupported event format: " << format_content; 149 continue; 150 } 151 152 v.emplace_back(EventFormat(format_name, "config", shift)); 153 } 154 return v; 155 } 156 157 static uint64_t MakeEventConfig(const std::string& event_str, std::vector<EventFormat>& formats) { 158 uint64_t config = 0; 159 160 // event files might have multiple terms, but usually have a term like: 161 // # cat armv8_pmuv3/events/cpu_cycles 162 // event=0x011 163 for (auto& s : android::base::Split(event_str, ",")) { 164 auto pos = s.find('='); 165 if (pos == std::string::npos) 166 continue; 167 168 auto format = s.substr(0, pos); 169 long val; 170 if (!android::base::ParseInt(android::base::Trim(s.substr(pos+1)), &val)) { 171 LOG(DEBUG) << "Invalid event format '" << s << "'"; 172 continue; 173 } 174 175 for (auto& f : formats) { 176 if (f.name == format) { 177 if (f.attr != "config") { 178 LOG(DEBUG) << "cannot support other attribute: " << s; 179 return ~0ULL; 180 } 181 182 config |= val << f.shift; 183 break; 184 } 185 } 186 } 187 return config; 188 } 189 190 static std::vector<EventType> GetPmuEventTypes() { 191 std::vector<EventType> result; 192 const std::string evtsrc_dirname = "/sys/bus/event_source/devices/"; 193 for (const auto& device_name : GetSubDirs(evtsrc_dirname)) { 194 std::string evtdev_path = evtsrc_dirname + device_name; 195 std::string type_path = evtdev_path + "/type"; 196 std::string type_content; 197 198 if (!android::base::ReadFileToString(type_path, &type_content)) { 199 LOG(DEBUG) << "cannot read event type: " << device_name; 200 continue; 201 } 202 uint64_t type_id = strtoull(type_content.c_str(), NULL, 10); 203 204 std::vector<EventFormat> formats = ParseEventFormats(evtdev_path); 205 206 std::string events_dirname = evtdev_path + "/events/"; 207 for (const auto& event_name : GetEntriesInDir(events_dirname)) { 208 std::string event_path = events_dirname + event_name; 209 std::string event_content; 210 if (!android::base::ReadFileToString(event_path, &event_content)) { 211 LOG(DEBUG) << "cannot read event content in " << event_name; 212 continue; 213 } 214 215 uint64_t config = MakeEventConfig(event_content, formats); 216 if (config == ~0ULL) { 217 LOG(DEBUG) << "cannot handle config format in " << event_name; 218 continue; 219 } 220 result.emplace_back(EventType(device_name + "/" + event_name + "/", 221 type_id, config, "", "")); 222 } 223 } 224 return result; 225 } 226 227 std::vector<int> EventType::GetPmuCpumask() { 228 std::vector<int> empty_result; 229 if (!IsPmuEvent()) 230 return empty_result; 231 232 std::string pmu = name.substr(0, name.find('/')); 233 std::string cpumask_path = "/sys/bus/event_source/devices/" + pmu + "/cpumask"; 234 std::string cpumask_content; 235 if (!android::base::ReadFileToString(cpumask_path, &cpumask_content)) { 236 LOG(DEBUG) << "cannot read cpumask content in " << pmu; 237 return empty_result; 238 } 239 return GetCpusFromString(cpumask_content); 240 } 241 242 std::string ScopedEventTypes::BuildString(const std::vector<const EventType*>& event_types) { 243 std::string result; 244 for (auto type : event_types) { 245 if (!result.empty()) { 246 result.push_back('\n'); 247 } 248 result += android::base::StringPrintf("%s,%u,%" PRIu64, type->name.c_str(), type->type, 249 type->config); 250 } 251 return result; 252 } 253 254 ScopedEventTypes::ScopedEventTypes(const std::string& event_type_str) { 255 saved_event_types_ = std::move(g_event_types); 256 saved_etm_event_type_ = g_etm_event_type; 257 g_event_types.clear(); 258 for (auto& s : android::base::Split(event_type_str, "\n")) { 259 std::string name = s.substr(0, s.find(',')); 260 uint32_t type; 261 uint64_t config; 262 sscanf(s.c_str() + name.size(), ",%u,%" PRIu64, &type, &config); 263 if (name == "cs-etm") { 264 g_etm_event_type = type; 265 } 266 g_event_types.emplace(name, type, config, "", ""); 267 } 268 } 269 270 ScopedEventTypes::~ScopedEventTypes() { 271 g_event_types = std::move(saved_event_types_); 272 g_etm_event_type = saved_etm_event_type_; 273 } 274 275 const std::set<EventType>& GetAllEventTypes() { 276 if (g_event_types.empty()) { 277 g_event_types.insert(static_event_type_array.begin(), static_event_type_array.end()); 278 std::vector<EventType> tracepoint_array = GetTracepointEventTypes(); 279 g_event_types.insert(tracepoint_array.begin(), tracepoint_array.end()); 280 std::vector<EventType> pmu_array = GetPmuEventTypes(); 281 g_event_types.insert(pmu_array.begin(), pmu_array.end()); 282 #if defined(__linux__) 283 std::unique_ptr<EventType> etm_type = ETMRecorder::GetInstance().BuildEventType(); 284 if (etm_type) { 285 g_etm_event_type = etm_type->type; 286 g_event_types.emplace(std::move(*etm_type)); 287 } 288 #endif 289 } 290 return g_event_types; 291 } 292 293 const EventType* FindEventTypeByName(const std::string& name, bool report_error) { 294 const auto& event_types = GetAllEventTypes(); 295 auto it = event_types.find(EventType(name, 0, 0, "", "")); 296 if (it != event_types.end()) { 297 return &*it; 298 } 299 if (!name.empty() && name[0] == 'r') { 300 char* end; 301 uint64_t config = strtoull(&name[1], &end, 16); 302 if (end != &name[1] && *end == '\0') { 303 auto result = g_event_types.emplace(name, PERF_TYPE_RAW, config, "", ""); 304 CHECK(result.second); 305 return &*(result.first); 306 } 307 } 308 if (report_error) { 309 LOG(ERROR) << "Unknown event_type '" << name 310 << "', try `simpleperf list` to list all possible event type names"; 311 } 312 return nullptr; 313 } 314 315 std::unique_ptr<EventTypeAndModifier> ParseEventType(const std::string& event_type_str) { 316 static std::string modifier_characters = "ukhGHp"; 317 std::unique_ptr<EventTypeAndModifier> event_type_modifier(new EventTypeAndModifier); 318 event_type_modifier->name = event_type_str; 319 std::string event_type_name = event_type_str; 320 std::string modifier; 321 size_t comm_pos = event_type_str.rfind(':'); 322 if (comm_pos != std::string::npos) { 323 bool match_modifier = true; 324 for (size_t i = comm_pos + 1; i < event_type_str.size(); ++i) { 325 char c = event_type_str[i]; 326 if (c != ' ' && modifier_characters.find(c) == std::string::npos) { 327 match_modifier = false; 328 break; 329 } 330 } 331 if (match_modifier) { 332 event_type_name = event_type_str.substr(0, comm_pos); 333 modifier = event_type_str.substr(comm_pos + 1); 334 } 335 } 336 const EventType* event_type = FindEventTypeByName(event_type_name); 337 if (event_type == nullptr) { 338 // Try if the modifier belongs to the event type name, like some tracepoint events. 339 if (!modifier.empty()) { 340 event_type_name = event_type_str; 341 modifier.clear(); 342 event_type = FindEventTypeByName(event_type_name); 343 } 344 if (event_type == nullptr) { 345 return nullptr; 346 } 347 } 348 event_type_modifier->event_type = *event_type; 349 if (modifier.find_first_of("ukh") != std::string::npos) { 350 event_type_modifier->exclude_user = true; 351 event_type_modifier->exclude_kernel = true; 352 event_type_modifier->exclude_hv = true; 353 } 354 if (modifier.find_first_of("GH") != std::string::npos) { 355 event_type_modifier->exclude_guest = true; 356 event_type_modifier->exclude_host = true; 357 } 358 359 for (auto& c : modifier) { 360 switch (c) { 361 case 'u': 362 event_type_modifier->exclude_user = false; 363 break; 364 case 'k': 365 event_type_modifier->exclude_kernel = false; 366 break; 367 case 'h': 368 event_type_modifier->exclude_hv = false; 369 break; 370 case 'G': 371 event_type_modifier->exclude_guest = false; 372 break; 373 case 'H': 374 event_type_modifier->exclude_host = false; 375 break; 376 case 'p': 377 event_type_modifier->precise_ip++; 378 break; 379 case ' ': 380 break; 381 default: 382 LOG(ERROR) << "Unknown event type modifier '" << c << "'"; 383 } 384 } 385 event_type_modifier->modifier = modifier; 386 return event_type_modifier; 387 } 388 389 bool IsEtmEventType(uint32_t type) { 390 return g_etm_event_type != 0 && type == g_etm_event_type; 391 } 392