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