Home | History | Annotate | Download | only in simpleperf
      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 "event_attr.h"
     32 #include "utils.h"
     33 
     34 #define EVENT_TYPE_TABLE_ENTRY(name, type, config, description, limited_arch) \
     35           {name, type, config, description, limited_arch},
     36 
     37 static const std::vector<EventType> static_event_type_array = {
     38 #include "event_type_table.h"
     39 };
     40 
     41 static std::string tracepoint_events;
     42 
     43 bool SetTracepointEventsFilePath(const std::string& filepath) {
     44   if (!android::base::ReadFileToString(filepath, &tracepoint_events)) {
     45     PLOG(ERROR) << "Failed to read " << filepath;
     46     return false;
     47   }
     48   return true;
     49 }
     50 
     51 std::string GetTracepointEvents() {
     52   std::string result;
     53   for (const EventType& event : GetAllEventTypes()) {
     54     if (event.type != PERF_TYPE_TRACEPOINT) {
     55       continue;
     56     }
     57     if (!result.empty()) {
     58       result.push_back('\n');
     59     }
     60     result += android::base::StringPrintf("%s %" PRIu64, event.name.c_str(), event.config);
     61   }
     62   return result;
     63 }
     64 
     65 static std::vector<EventType> GetTracepointEventTypesFromString(const std::string& s) {
     66   std::vector<EventType> result;
     67   for (auto& line : android::base::Split(s, "\n")) {
     68     std::vector<std::string> items = android::base::Split(line, " ");
     69     CHECK_EQ(items.size(), 2u);
     70     std::string event_name = items[0];
     71     uint64_t id;
     72     CHECK(android::base::ParseUint(items[1].c_str(), &id));
     73     result.push_back(EventType(event_name, PERF_TYPE_TRACEPOINT, id, "", ""));
     74   }
     75   return result;
     76 }
     77 
     78 static std::vector<EventType> GetTracepointEventTypesFromTraceFs() {
     79   std::vector<EventType> result;
     80   const std::string tracepoint_dirname = "/sys/kernel/debug/tracing/events";
     81   for (const auto& system_name : GetSubDirs(tracepoint_dirname)) {
     82     std::string system_path = tracepoint_dirname + "/" + system_name;
     83     for (const auto& event_name : GetSubDirs(system_path)) {
     84       std::string id_path = system_path + "/" + event_name + "/id";
     85       std::string id_content;
     86       if (!android::base::ReadFileToString(id_path, &id_content)) {
     87         continue;
     88       }
     89       char* endptr;
     90       uint64_t id = strtoull(id_content.c_str(), &endptr, 10);
     91       if (endptr == id_content.c_str()) {
     92         LOG(DEBUG) << "unexpected id '" << id_content << "' in " << id_path;
     93         continue;
     94       }
     95       result.push_back(EventType(system_name + ":" + event_name, PERF_TYPE_TRACEPOINT, id, "", ""));
     96     }
     97   }
     98   return result;
     99 }
    100 
    101 static std::vector<EventType> GetTracepointEventTypes() {
    102   std::vector<EventType> result;
    103   if (!tracepoint_events.empty()) {
    104     result = GetTracepointEventTypesFromString(tracepoint_events);
    105   } else {
    106     result = GetTracepointEventTypesFromTraceFs();
    107   }
    108   std::sort(result.begin(), result.end(),
    109             [](const EventType& type1, const EventType& type2) { return type1.name < type2.name; });
    110   return result;
    111 }
    112 
    113 static std::vector<EventType> event_type_array;
    114 
    115 std::string ScopedEventTypes::BuildString(const std::vector<const EventType*>& event_types) {
    116   std::string result;
    117   for (auto type : event_types) {
    118     if (!result.empty()) {
    119       result.push_back('\n');
    120     }
    121     result += android::base::StringPrintf("%s,%u,%" PRIu64, type->name.c_str(), type->type,
    122                                           type->config);
    123   }
    124   return result;
    125 }
    126 
    127 ScopedEventTypes::ScopedEventTypes(const std::string& event_type_str) {
    128   saved_event_types_ = std::move(event_type_array);
    129   event_type_array.clear();
    130   for (auto& s : android::base::Split(event_type_str, "\n")) {
    131     std::string name = s.substr(0, s.find(','));
    132     uint32_t type;
    133     uint64_t config;
    134     sscanf(s.c_str() + name.size(), ",%u,%" PRIu64, &type, &config);
    135     event_type_array.emplace_back(name, type, config, "", "");
    136   }
    137 }
    138 
    139 ScopedEventTypes::~ScopedEventTypes() {
    140   event_type_array = std::move(saved_event_types_);
    141 }
    142 
    143 const std::vector<EventType>& GetAllEventTypes() {
    144   if (event_type_array.empty()) {
    145     event_type_array.insert(event_type_array.end(), static_event_type_array.begin(),
    146                             static_event_type_array.end());
    147     std::vector<EventType> tracepoint_array = GetTracepointEventTypes();
    148     event_type_array.insert(event_type_array.end(), tracepoint_array.begin(),
    149                             tracepoint_array.end());
    150   }
    151   return event_type_array;
    152 }
    153 
    154 const EventType* FindEventTypeByName(const std::string& name, bool report_error) {
    155   const EventType* result = nullptr;
    156   for (auto& event_type : GetAllEventTypes()) {
    157     if (android::base::EqualsIgnoreCase(event_type.name, name)) {
    158       result = &event_type;
    159       break;
    160     }
    161   }
    162   if (result == nullptr && report_error) {
    163     LOG(ERROR) << "Unknown event_type '" << name
    164                << "', try `simpleperf list` to list all possible event type names";
    165     return nullptr;
    166   }
    167   return result;
    168 }
    169 
    170 std::unique_ptr<EventTypeAndModifier> ParseEventType(const std::string& event_type_str) {
    171   static std::string modifier_characters = "ukhGHp";
    172   std::unique_ptr<EventTypeAndModifier> event_type_modifier(new EventTypeAndModifier);
    173   event_type_modifier->name = event_type_str;
    174   std::string event_type_name = event_type_str;
    175   std::string modifier;
    176   size_t comm_pos = event_type_str.rfind(':');
    177   if (comm_pos != std::string::npos) {
    178     bool match_modifier = true;
    179     for (size_t i = comm_pos + 1; i < event_type_str.size(); ++i) {
    180       char c = event_type_str[i];
    181       if (c != ' ' && modifier_characters.find(c) == std::string::npos) {
    182         match_modifier = false;
    183         break;
    184       }
    185     }
    186     if (match_modifier) {
    187       event_type_name = event_type_str.substr(0, comm_pos);
    188       modifier = event_type_str.substr(comm_pos + 1);
    189     }
    190   }
    191   const EventType* event_type = FindEventTypeByName(event_type_name);
    192   if (event_type == nullptr) {
    193     // Try if the modifier belongs to the event type name, like some tracepoint events.
    194     if (!modifier.empty()) {
    195       event_type_name = event_type_str;
    196       modifier.clear();
    197       event_type = FindEventTypeByName(event_type_name);
    198     }
    199     if (event_type == nullptr) {
    200       return nullptr;
    201     }
    202   }
    203   event_type_modifier->event_type = *event_type;
    204   if (modifier.find_first_of("ukh") != std::string::npos) {
    205     event_type_modifier->exclude_user = true;
    206     event_type_modifier->exclude_kernel = true;
    207     event_type_modifier->exclude_hv = true;
    208   }
    209   if (modifier.find_first_of("GH") != std::string::npos) {
    210     event_type_modifier->exclude_guest = true;
    211     event_type_modifier->exclude_host = true;
    212   }
    213 
    214   for (auto& c : modifier) {
    215     switch (c) {
    216       case 'u':
    217         event_type_modifier->exclude_user = false;
    218         break;
    219       case 'k':
    220         event_type_modifier->exclude_kernel = false;
    221         break;
    222       case 'h':
    223         event_type_modifier->exclude_hv = false;
    224         break;
    225       case 'G':
    226         event_type_modifier->exclude_guest = false;
    227         break;
    228       case 'H':
    229         event_type_modifier->exclude_host = false;
    230         break;
    231       case 'p':
    232         event_type_modifier->precise_ip++;
    233         break;
    234       case ' ':
    235         break;
    236       default:
    237         LOG(ERROR) << "Unknown event type modifier '" << c << "'";
    238     }
    239   }
    240   event_type_modifier->modifier = modifier;
    241   return event_type_modifier;
    242 }
    243