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