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/file.h> 23 #include <android-base/logging.h> 24 25 #include "command.h" 26 #include "environment.h" 27 #include "ETMRecorder.h" 28 #include "event_attr.h" 29 #include "event_fd.h" 30 #include "event_selection_set.h" 31 #include "event_type.h" 32 33 using namespace simpleperf; 34 35 namespace { 36 37 enum EventTypeStatus { 38 NOT_SUPPORTED, 39 MAY_NOT_SUPPORTED, 40 SUPPORTED, 41 }; 42 43 static EventTypeStatus IsEventTypeSupported(const EventType& event_type) { 44 // Because PMU events are provided by kernel, we assume it's supported. 45 if (event_type.IsPmuEvent()) { 46 return EventTypeStatus::SUPPORTED; 47 } 48 if (event_type.type != PERF_TYPE_RAW) { 49 perf_event_attr attr = CreateDefaultPerfEventAttr(event_type); 50 // Exclude kernel to list supported events even when 51 // /proc/sys/kernel/perf_event_paranoid is 2. 52 attr.exclude_kernel = 1; 53 return IsEventAttrSupported(attr, event_type.name) ? EventTypeStatus::SUPPORTED 54 : EventTypeStatus::NOT_SUPPORTED; 55 } 56 if (event_type.limited_arch == "arm" && GetBuildArch() != ARCH_ARM && 57 GetBuildArch() != ARCH_ARM64) { 58 return EventTypeStatus::NOT_SUPPORTED; 59 } 60 // Because the kernel may not check whether the raw event is supported by the cpu pmu. 61 // We can't decide whether the raw event is supported by calling perf_event_open(). 62 // Instead, we can check if it can collect some real number. 63 perf_event_attr attr = CreateDefaultPerfEventAttr(event_type); 64 std::unique_ptr<EventFd> event_fd = 65 EventFd::OpenEventFile(attr, gettid(), -1, nullptr, event_type.name, false); 66 if (event_fd == nullptr) { 67 return EventTypeStatus::NOT_SUPPORTED; 68 } 69 auto work_function = []() { 70 TemporaryFile tmpfile; 71 FILE* fp = fopen(tmpfile.path, "w"); 72 if (fp == nullptr) { 73 return; 74 } 75 for (int i = 0; i < 10; ++i) { 76 fprintf(fp, "output some data\n"); 77 } 78 fclose(fp); 79 }; 80 work_function(); 81 PerfCounter counter; 82 if (!event_fd->ReadCounter(&counter)) { 83 return EventTypeStatus::NOT_SUPPORTED; 84 } 85 // For raw events, we may not be able to detect whether it is supported on device. 86 return (counter.value != 0u) ? EventTypeStatus::SUPPORTED : EventTypeStatus::MAY_NOT_SUPPORTED; 87 } 88 89 static void PrintEventTypesOfType(const std::string& type_name, const std::string& type_desc, 90 const std::function<bool(const EventType&)>& is_type_fn, 91 const std::set<EventType>& event_types) { 92 printf("List of %s:\n", type_desc.c_str()); 93 if (GetBuildArch() == ARCH_ARM || GetBuildArch() == ARCH_ARM64) { 94 if (type_name == "raw") { 95 printf( 96 // clang-format off 97 " # Please refer to \"PMU common architectural and microarchitectural event numbers\"\n" 98 " # and \"ARM recommendations for IMPLEMENTATION DEFINED event numbers\" listed in\n" 99 " # ARMv8 manual for details.\n" 100 " # A possible link is https://developer.arm.com/docs/ddi0487/latest/arm-architecture-reference-manual-armv8-for-armv8-a-architecture-profile.\n" 101 // clang-format on 102 ); 103 } else if (type_name == "cache") { 104 printf(" # More cache events are available in `simpleperf list raw`.\n"); 105 } 106 } 107 for (auto& event_type : event_types) { 108 if (is_type_fn(event_type)) { 109 EventTypeStatus status = IsEventTypeSupported(event_type); 110 if (status == EventTypeStatus::NOT_SUPPORTED) { 111 continue; 112 } 113 printf(" %s", event_type.name.c_str()); 114 if (status == EventTypeStatus::MAY_NOT_SUPPORTED) { 115 printf(" (may not supported)"); 116 } 117 if (!event_type.description.empty()) { 118 printf("\t\t# %s", event_type.description.c_str()); 119 } 120 printf("\n"); 121 } 122 } 123 printf("\n"); 124 } 125 126 class ListCommand : public Command { 127 public: 128 ListCommand() 129 : Command("list", "list available event types", 130 // clang-format off 131 "Usage: simpleperf list [options] [hw|sw|cache|raw|tracepoint|pmu]\n" 132 " List all available event types.\n" 133 " Filters can be used to show only event types belong to selected types:\n" 134 " hw hardware events\n" 135 " sw software events\n" 136 " cache hardware cache events\n" 137 " raw raw cpu pmu events\n" 138 " tracepoint tracepoint events\n" 139 " cs-etm coresight etm instruction tracing events\n" 140 " pmu system-specific pmu events\n" 141 "Options:\n" 142 "--show-features Show features supported on the device, including:\n" 143 " dwarf-based-call-graph\n" 144 " trace-offcpu\n" 145 // clang-format on 146 ) { 147 } 148 149 bool Run(const std::vector<std::string>& args) override; 150 151 private: 152 void ShowFeatures(); 153 }; 154 155 bool ListCommand::Run(const std::vector<std::string>& args) { 156 if (!CheckPerfEventLimit()) { 157 return false; 158 } 159 160 static std::map<std::string, std::pair<std::string, std::function<bool(const EventType&)>>> 161 type_map = { 162 {"hw", 163 {"hardware events", [](const EventType& e) { return e.type == PERF_TYPE_HARDWARE; }}}, 164 {"sw", 165 {"software events", [](const EventType& e) { return e.type == PERF_TYPE_SOFTWARE; }}}, 166 {"cache", 167 {"hw-cache events", [](const EventType& e) { return e.type == PERF_TYPE_HW_CACHE; }}}, 168 {"raw", 169 {"raw events provided by cpu pmu", 170 [](const EventType& e) { return e.type == PERF_TYPE_RAW; }}}, 171 {"tracepoint", 172 {"tracepoint events", 173 [](const EventType& e) { return e.type == PERF_TYPE_TRACEPOINT; }}}, 174 #if defined(__arm__) || defined(__aarch64__) 175 {"cs-etm", 176 {"coresight etm events", 177 [](const EventType& e) { 178 return e.type == ETMRecorder::GetInstance().GetEtmEventType(); 179 }}}, 180 #endif 181 {"pmu", {"pmu events", [](const EventType& e) { return e.IsPmuEvent(); }}}, 182 }; 183 184 std::vector<std::string> names; 185 if (args.empty()) { 186 for (auto& item : type_map) { 187 names.push_back(item.first); 188 } 189 } else { 190 for (auto& arg : args) { 191 if (type_map.find(arg) != type_map.end()) { 192 names.push_back(arg); 193 } else if (arg == "--show-features") { 194 ShowFeatures(); 195 return true; 196 } else { 197 LOG(ERROR) << "unknown event type category: " << arg << ", try using \"help list\""; 198 return false; 199 } 200 } 201 } 202 203 auto& event_types = GetAllEventTypes(); 204 205 for (auto& name : names) { 206 auto it = type_map.find(name); 207 PrintEventTypesOfType(name, it->second.first, it->second.second, event_types); 208 } 209 return true; 210 } 211 212 void ListCommand::ShowFeatures() { 213 if (IsDwarfCallChainSamplingSupported()) { 214 printf("dwarf-based-call-graph\n"); 215 } 216 if (IsDumpingRegsForTracepointEventsSupported()) { 217 printf("trace-offcpu\n"); 218 } 219 if (IsSettingClockIdSupported()) { 220 printf("set-clockid\n"); 221 } 222 } 223 224 } // namespace 225 226 void RegisterListCommand() { 227 RegisterCommand("list", [] { return std::unique_ptr<Command>(new ListCommand); }); 228 } 229