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 <sched.h>
18 #include <stdio.h>
19
20 #include <atomic>
21 #include <map>
22 #include <string>
23 #include <thread>
24 #include <vector>
25
26 #include <android-base/file.h>
27 #include <android-base/logging.h>
28
29 #include "ETMRecorder.h"
30 #include "RegEx.h"
31 #include "command.h"
32 #include "environment.h"
33 #include "event_attr.h"
34 #include "event_fd.h"
35 #include "event_selection_set.h"
36 #include "event_type.h"
37
38 namespace simpleperf {
39
40 extern std::unordered_map<std::string, std::unordered_set<int>> cpu_supported_raw_events;
41
42 #if defined(__aarch64__) || defined(__arm__)
43 extern std::unordered_map<uint64_t, std::string> cpuid_to_name;
44 #endif // defined(__aarch64__) || defined(__arm__)
45
46 #if defined(__riscv)
47 extern std::map<std::tuple<uint64_t, std::string, std::string>, std::string> cpuid_to_name;
48 #endif // defined(__riscv)
49
50 namespace {
51
52 struct RawEventTestThreadArg {
53 int cpu;
54 std::atomic<pid_t> tid;
55 std::atomic<bool> start;
56 };
57
RawEventTestThread(RawEventTestThreadArg * arg)58 static void RawEventTestThread(RawEventTestThreadArg* arg) {
59 cpu_set_t mask;
60 CPU_ZERO(&mask);
61 CPU_SET(arg->cpu, &mask);
62 int tid = gettid();
63 sched_setaffinity(tid, sizeof(mask), &mask);
64 arg->tid = tid;
65 while (!arg->start) {
66 std::this_thread::sleep_for(std::chrono::milliseconds(1));
67 }
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
79 struct RawEventSupportStatus {
80 std::vector<int> supported_cpus;
81 std::vector<int> may_supported_cpus;
82 };
83
84 #if defined(__riscv)
to_hex_string(uint64_t value)85 std::string to_hex_string(uint64_t value) {
86 std::stringstream stream;
87 stream << "0x" << std::hex << value;
88 return stream.str();
89 }
90
find_cpu_name(const std::tuple<uint64_t,uint64_t,uint64_t> & cpu_id,const std::map<std::tuple<uint64_t,std::string,std::string>,std::string> & cpuid_to_name)91 auto find_cpu_name(
92 const std::tuple<uint64_t, uint64_t, uint64_t>& cpu_id,
93 const std::map<std::tuple<uint64_t, std::string, std::string>, std::string>& cpuid_to_name) {
94 // cpu_id: mvendorid, marchid, mimpid
95 // cpuid_to_name: mvendorid, marchid regex, mimpid regex
96
97 std::string marchid_hex = to_hex_string(get<1>(cpu_id));
98 std::string mimpid_hex = to_hex_string(get<2>(cpu_id));
99 uint64_t mvendorid = std::get<0>(cpu_id);
100
101 // Search the first entry that matches mvendorid
102 auto it = cpuid_to_name.lower_bound({mvendorid, "", ""});
103
104 // Search the iterator of correct regex for current CPU from entries with same mvendorid
105 for (; it != cpuid_to_name.end() && std::get<0>(it->first) == mvendorid; ++it) {
106 const auto& [_, marchid_regex, mimpid_regex] = it->first;
107 if (RegEx::Create(marchid_regex)->Match(marchid_hex) &&
108 RegEx::Create(mimpid_regex)->Match(mimpid_hex)) {
109 break;
110 }
111 }
112
113 return it;
114 }
115 #endif // defined(__riscv)
116
117 class RawEventSupportChecker {
118 public:
Init()119 bool Init() {
120 cpu_models_ = GetCpuModels();
121 if (cpu_models_.empty()) {
122 LOG(ERROR) << "can't get device cpu info";
123 return false;
124 }
125 for (const auto& model : cpu_models_) {
126 cpu_model_names_.push_back(GetCpuModelName(model));
127 }
128 return true;
129 }
130
GetCpusSupportingEvent(const EventType & event_type)131 RawEventSupportStatus GetCpusSupportingEvent(const EventType& event_type) {
132 RawEventSupportStatus status;
133 std::string required_cpu_model;
134 // For cpu model specific events, the limited_arch is like "arm64:Cortex-A520".
135 if (auto pos = event_type.limited_arch.find(':'); pos != std::string::npos) {
136 required_cpu_model = event_type.limited_arch.substr(pos + 1);
137 }
138
139 for (size_t i = 0; i < cpu_models_.size(); ++i) {
140 const CpuModel& model = cpu_models_[i];
141 const std::string& model_name = cpu_model_names_[i];
142 bool got_status = false;
143 bool supported = false;
144 bool may_supported = false;
145
146 if (model.arch == "arm") {
147 if (!required_cpu_model.empty()) {
148 // This is a cpu model specific event, only supported on required_cpu_model.
149 supported = model_name == required_cpu_model;
150 got_status = true;
151 } else if (!model_name.empty()) {
152 // We know events supported on this cpu model.
153 auto it = cpu_supported_raw_events.find(model_name);
154 CHECK(it != cpu_supported_raw_events.end())
155 << "no events configuration for " << model_name;
156 supported = it->second.count(event_type.config) > 0;
157 got_status = true;
158 }
159 } else if (model.arch == "x86") {
160 if (event_type.limited_arch != model_name) {
161 supported = false;
162 got_status = true;
163 }
164 }
165
166 if (!got_status) {
167 // We need to test the event support status.
168 TestEventSupportOnCpu(event_type, model.cpus[0], supported, may_supported);
169 }
170
171 if (supported) {
172 status.supported_cpus.insert(status.supported_cpus.end(), model.cpus.begin(),
173 model.cpus.end());
174 } else if (may_supported) {
175 status.may_supported_cpus.insert(status.may_supported_cpus.end(), model.cpus.begin(),
176 model.cpus.end());
177 }
178 }
179 return status;
180 }
181
182 private:
GetCpuModelName(const CpuModel & model)183 std::string GetCpuModelName(const CpuModel& model) {
184 #if defined(__aarch64__) || defined(__arm__)
185 uint64_t cpu_id =
186 (static_cast<uint64_t>(model.arm_data.implementer) << 32) | model.arm_data.partnum;
187 auto it = cpuid_to_name.find(cpu_id);
188 if (it != cpuid_to_name.end()) {
189 return it->second;
190 }
191 #elif defined(__riscv)
192 std::tuple<uint64_t, uint64_t, uint64_t> cpu_id = {
193 model.riscv_data.mvendorid, model.riscv_data.marchid, model.riscv_data.mimpid};
194 auto it = find_cpu_name(cpu_id, cpuid_to_name);
195 if (it != cpuid_to_name.end()) {
196 return it->second;
197 }
198 #elif defined(__i386__) || defined(__x86_64__)
199 if (model.x86_data.vendor_id == "GenuineIntel") {
200 return "x86-intel";
201 }
202 if (model.x86_data.vendor_id == "AuthenticAMD") {
203 return "x86-amd";
204 }
205 #endif // defined(__i386__) || defined(__x86_64__)
206 return "";
207 }
208
TestEventSupportOnCpu(const EventType & event_type,int cpu,bool & supported,bool & may_supported)209 void TestEventSupportOnCpu(const EventType& event_type, int cpu, bool& supported,
210 bool& may_supported) {
211 // Because the kernel may not check whether the raw event is supported by the cpu pmu.
212 // We can't decide whether the raw event is supported by calling perf_event_open().
213 // Instead, we can check if it can collect some real number.
214 RawEventTestThreadArg test_thread_arg;
215 test_thread_arg.cpu = cpu;
216 test_thread_arg.tid = 0;
217 test_thread_arg.start = false;
218 std::thread test_thread(RawEventTestThread, &test_thread_arg);
219 while (test_thread_arg.tid == 0) {
220 std::this_thread::sleep_for(std::chrono::milliseconds(1));
221 }
222 perf_event_attr attr = CreateDefaultPerfEventAttr(event_type);
223 std::unique_ptr<EventFd> event_fd = EventFd::OpenEventFile(
224 attr, test_thread_arg.tid, test_thread_arg.cpu, nullptr, event_type.name, false);
225 test_thread_arg.start = true;
226 test_thread.join();
227 if (event_fd == nullptr) {
228 supported = may_supported = false;
229 return;
230 }
231 PerfCounter counter;
232 if (!event_fd->ReadCounter(&counter)) {
233 supported = may_supported = false;
234 return;
235 }
236 if (counter.value != 0) {
237 supported = true;
238 may_supported = false;
239 } else {
240 supported = false;
241 may_supported = true;
242 }
243 }
244
245 std::vector<CpuModel> cpu_models_;
246
247 std::vector<std::string> cpu_model_names_;
248 };
249
ToCpuString(const std::vector<int> & cpus)250 static std::string ToCpuString(const std::vector<int>& cpus) {
251 std::string s;
252 if (cpus.empty()) {
253 return s;
254 }
255 s += std::to_string(cpus[0]);
256 int last_cpu = cpus[0];
257 bool added = true;
258 for (size_t i = 1; i < cpus.size(); ++i) {
259 if (cpus[i] == last_cpu + 1) {
260 last_cpu = cpus[i];
261 added = false;
262 } else {
263 s += "-" + std::to_string(last_cpu) + "," + std::to_string(cpus[i]);
264 last_cpu = cpus[i];
265 added = true;
266 }
267 }
268 if (!added) {
269 s += "-" + std::to_string(last_cpu);
270 }
271 return s;
272 }
273
PrintRawEventTypes(const std::string & type_desc)274 static void PrintRawEventTypes(const std::string& type_desc) {
275 printf("List of %s:\n", type_desc.c_str());
276 #if defined(__aarch64__) || defined(__arm__)
277 printf(
278 // clang-format off
279 " # Please refer to \"PMU common architectural and microarchitectural event numbers\"\n"
280 " # and \"ARM recommendations for IMPLEMENTATION DEFINED event numbers\" listed in\n"
281 " # ARMv9 manual for details.\n"
282 " # A possible link is https://developer.arm.com/documentation/ddi0487.\n"
283 // clang-format on
284 );
285 #endif // defined(__aarch64__) || defined(__arm__)
286 RawEventSupportChecker support_checker;
287 if (!support_checker.Init()) {
288 return;
289 }
290 auto callback = [&](const EventType& event_type) {
291 if (event_type.type != PERF_TYPE_RAW) {
292 return true;
293 }
294 RawEventSupportStatus status = support_checker.GetCpusSupportingEvent(event_type);
295 if (status.supported_cpus.empty() && status.may_supported_cpus.empty()) {
296 return true;
297 }
298 std::string text = " " + event_type.name + " (";
299 if (!status.supported_cpus.empty()) {
300 text += "supported on cpu " + ToCpuString(status.supported_cpus);
301 if (!status.may_supported_cpus.empty()) {
302 text += ", ";
303 }
304 }
305 if (!status.may_supported_cpus.empty()) {
306 text += "may supported on cpu " + ToCpuString(status.may_supported_cpus);
307 }
308 text += ")";
309 printf("%s", text.c_str());
310 if (!event_type.description.empty()) {
311 printf("\t\t# %s", event_type.description.c_str());
312 }
313 printf("\n");
314 return true;
315 };
316 EventTypeManager::Instance().ForEachType(callback);
317 printf("\n");
318 }
319
IsEventTypeSupported(const EventType & event_type)320 static bool IsEventTypeSupported(const EventType& event_type) {
321 // PMU and tracepoint events are provided by kernel. So we assume they're supported.
322 if (event_type.IsPmuEvent() || event_type.IsTracepointEvent()) {
323 return true;
324 }
325 perf_event_attr attr = CreateDefaultPerfEventAttr(event_type);
326 // Exclude kernel to list supported events even when kernel recording isn't allowed.
327 attr.exclude_kernel = 1;
328 return IsEventAttrSupported(attr, event_type.name);
329 }
330
PrintEventTypesOfType(const std::string & type_name,const std::string & type_desc,const std::function<bool (const EventType &)> & is_type_fn)331 static void PrintEventTypesOfType(const std::string& type_name, const std::string& type_desc,
332 const std::function<bool(const EventType&)>& is_type_fn) {
333 if (type_name == "raw") {
334 return PrintRawEventTypes(type_desc);
335 }
336 printf("List of %s:\n", type_desc.c_str());
337 if (GetTargetArch() == ARCH_ARM || GetTargetArch() == ARCH_ARM64) {
338 if (type_name == "cache") {
339 printf(" # More cache events are available in `simpleperf list raw`.\n");
340 }
341 }
342 auto callback = [&](const EventType& event_type) {
343 if (is_type_fn(event_type)) {
344 if (!IsEventTypeSupported(event_type)) {
345 return true;
346 }
347 printf(" %s", event_type.name.c_str());
348 if (!event_type.description.empty()) {
349 printf("\t\t# %s", event_type.description.c_str());
350 }
351 printf("\n");
352 }
353 return true;
354 };
355 EventTypeManager::Instance().ForEachType(callback);
356 printf("\n");
357 }
358
359 class ListCommand : public Command {
360 public:
ListCommand()361 ListCommand()
362 : Command("list", "list available event types",
363 // clang-format off
364 "Usage: simpleperf list [options] [hw|sw|cache|raw|tracepoint|pmu]\n"
365 " List all available event types.\n"
366 " Filters can be used to show only event types belong to selected types:\n"
367 " hw hardware events\n"
368 " sw software events\n"
369 " cache hardware cache events\n"
370 " raw raw cpu pmu events\n"
371 " tracepoint tracepoint events\n"
372 " cs-etm coresight etm instruction tracing events\n"
373 " pmu system-specific pmu events\n"
374 "Options:\n"
375 "--show-features Show features supported on the device, including:\n"
376 " dwarf-based-call-graph\n"
377 " trace-offcpu\n"
378 // clang-format on
379 ) {}
380
381 bool Run(const std::vector<std::string>& args) override;
382
383 private:
384 void ShowFeatures();
385 };
386
Run(const std::vector<std::string> & args)387 bool ListCommand::Run(const std::vector<std::string>& args) {
388 if (!CheckPerfEventLimit()) {
389 return false;
390 }
391
392 static std::map<std::string, std::pair<std::string, std::function<bool(const EventType&)>>>
393 type_map = {
394 {"hw",
395 {"hardware events", [](const EventType& e) { return e.type == PERF_TYPE_HARDWARE; }}},
396 {"sw",
397 {"software events", [](const EventType& e) { return e.type == PERF_TYPE_SOFTWARE; }}},
398 {"cache",
399 {"hw-cache events", [](const EventType& e) { return e.type == PERF_TYPE_HW_CACHE; }}},
400 {"raw",
401 {"raw events provided by cpu pmu",
402 [](const EventType& e) { return e.type == PERF_TYPE_RAW; }}},
403 {"tracepoint",
404 {"tracepoint events",
405 [](const EventType& e) { return e.type == PERF_TYPE_TRACEPOINT; }}},
406 #if defined(__arm__) || defined(__aarch64__)
407 {"cs-etm",
408 {"coresight etm events",
409 [](const EventType& e) {
410 return e.type == ETMRecorder::GetInstance().GetEtmEventType();
411 }}},
412 #endif
413 {"pmu", {"pmu events", [](const EventType& e) { return e.IsPmuEvent(); }}},
414 };
415
416 std::vector<std::string> names;
417 if (args.empty()) {
418 for (auto& item : type_map) {
419 names.push_back(item.first);
420 }
421 } else {
422 for (auto& arg : args) {
423 if (type_map.find(arg) != type_map.end()) {
424 names.push_back(arg);
425 } else if (arg == "--show-features") {
426 ShowFeatures();
427 return true;
428 } else {
429 LOG(ERROR) << "unknown event type category: " << arg << ", try using \"help list\"";
430 return false;
431 }
432 }
433 }
434
435 for (auto& name : names) {
436 auto it = type_map.find(name);
437 PrintEventTypesOfType(name, it->second.first, it->second.second);
438 }
439 return true;
440 }
441
ShowFeatures()442 void ListCommand::ShowFeatures() {
443 if (IsDwarfCallChainSamplingSupported()) {
444 printf("dwarf-based-call-graph\n");
445 }
446 if (IsDumpingRegsForTracepointEventsSupported()) {
447 printf("trace-offcpu\n");
448 }
449 if (IsSettingClockIdSupported()) {
450 printf("set-clockid\n");
451 }
452 }
453
454 } // namespace
455
RegisterListCommand()456 void RegisterListCommand() {
457 RegisterCommand("list", [] { return std::unique_ptr<Command>(new ListCommand); });
458 }
459
460 } // namespace simpleperf
461