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 <stdio.h>
     18 #include <map>
     19 #include <string>
     20 #include <vector>
     21 
     22 #include <android-base/logging.h>
     23 #include <android-base/test_utils.h>
     24 
     25 #include "command.h"
     26 #include "environment.h"
     27 #include "event_attr.h"
     28 #include "event_fd.h"
     29 #include "event_type.h"
     30 
     31 static bool IsEventTypeSupported(const EventType& event_type) {
     32   if (event_type.type != PERF_TYPE_RAW) {
     33     perf_event_attr attr = CreateDefaultPerfEventAttr(event_type);
     34     // Exclude kernel to list supported events even when
     35     // /proc/sys/kernel/perf_event_paranoid is 2.
     36     attr.exclude_kernel = 1;
     37     return IsEventAttrSupported(attr);
     38   }
     39   if (event_type.limited_arch == "arm" && GetBuildArch() != ARCH_ARM &&
     40       GetBuildArch() != ARCH_ARM64) {
     41     return false;
     42   }
     43   // Because the kernel may not check whether the raw event is supported by the cpu pmu.
     44   // We can't decide whether the raw event is supported by calling perf_event_open().
     45   // Instead, we can check if it can collect some real number.
     46   perf_event_attr attr = CreateDefaultPerfEventAttr(event_type);
     47   std::unique_ptr<EventFd> event_fd = EventFd::OpenEventFile(attr, gettid(), -1, nullptr);
     48   if (event_fd == nullptr) {
     49     return false;
     50   }
     51   auto work_function = []() {
     52     TemporaryFile tmpfile;
     53     FILE* fp = fopen(tmpfile.path, "w");
     54     if (fp == nullptr) {
     55       return;
     56     }
     57     for (int i = 0; i < 10; ++i) {
     58       fprintf(fp, "output some data\n");
     59     }
     60     fclose(fp);
     61   };
     62   work_function();
     63   PerfCounter counter;
     64   if (!event_fd->ReadCounter(&counter)) {
     65     return false;
     66   }
     67   return (counter.value != 0u);
     68 }
     69 
     70 static void PrintEventTypesOfType(uint32_t type, const std::string& type_name,
     71                                   const std::vector<EventType>& event_types) {
     72   printf("List of %s:\n", type_name.c_str());
     73   if (type == PERF_TYPE_RAW && (GetBuildArch() == ARCH_ARM || GetBuildArch() == ARCH_ARM64)) {
     74     printf("  # Please refer to PMU event numbers listed in ARMv8 manual for details.\n");
     75     printf("  # A possible link is https://developer.arm.com/docs/ddi0487/latest/arm-architecture-reference-manual-armv8-for-armv8-a-architecture-profile.\n");
     76   }
     77   for (auto& event_type : event_types) {
     78     if (event_type.type == type) {
     79       if (IsEventTypeSupported(event_type)) {
     80         printf("  %s", event_type.name.c_str());
     81         if (!event_type.description.empty()) {
     82           printf("\t\t# %s", event_type.description.c_str());
     83         }
     84         printf("\n");
     85       }
     86     }
     87   }
     88   printf("\n");
     89 }
     90 
     91 class ListCommand : public Command {
     92  public:
     93   ListCommand()
     94       : Command("list", "list available event types",
     95                 "Usage: simpleperf list [hw|sw|cache|raw|tracepoint]\n"
     96                 "    List all available perf events on this machine.\n") {
     97   }
     98 
     99   bool Run(const std::vector<std::string>& args) override;
    100 };
    101 
    102 bool ListCommand::Run(const std::vector<std::string>& args) {
    103   if (!CheckPerfEventLimit()) {
    104     return false;
    105   }
    106 
    107   static std::map<std::string, std::pair<int, std::string>> type_map = {
    108       {"hw", {PERF_TYPE_HARDWARE, "hardware events"}},
    109       {"sw", {PERF_TYPE_SOFTWARE, "software events"}},
    110       {"cache", {PERF_TYPE_HW_CACHE, "hw-cache events"}},
    111       {"raw", {PERF_TYPE_RAW, "raw events provided by cpu pmu"}},
    112       {"tracepoint", {PERF_TYPE_TRACEPOINT, "tracepoint events"}},
    113       {"user-space-sampler", {SIMPLEPERF_TYPE_USER_SPACE_SAMPLERS, "user-space samplers"}},
    114   };
    115 
    116   std::vector<std::string> names;
    117   if (args.empty()) {
    118     for (auto& item : type_map) {
    119       names.push_back(item.first);
    120     }
    121   } else {
    122     for (auto& arg : args) {
    123       if (type_map.find(arg) != type_map.end()) {
    124         names.push_back(arg);
    125       } else {
    126         LOG(ERROR) << "unknown event type category: " << arg << ", try using \"help list\"";
    127         return false;
    128       }
    129     }
    130   }
    131 
    132   auto& event_types = GetAllEventTypes();
    133 
    134   for (auto& name : names) {
    135     auto it = type_map.find(name);
    136     PrintEventTypesOfType(it->second.first, it->second.second, event_types);
    137   }
    138   return true;
    139 }
    140 
    141 void RegisterListCommand() {
    142   RegisterCommand("list", [] { return std::unique_ptr<Command>(new ListCommand); });
    143 }
    144