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 "event_selection_set.h"
18
19 #include <algorithm>
20 #include <atomic>
21 #include <thread>
22 #include <unordered_map>
23
24 #include <android-base/logging.h>
25 #include <android-base/stringprintf.h>
26 #include <android-base/strings.h>
27
28 #include "ETMRecorder.h"
29 #include "IOEventLoop.h"
30 #include "RecordReadThread.h"
31 #include "environment.h"
32 #include "event_attr.h"
33 #include "event_type.h"
34 #include "perf_regs.h"
35 #include "tracing.h"
36 #include "utils.h"
37
38 namespace simpleperf {
39
40 using android::base::StringPrintf;
41
IsBranchSamplingSupported()42 bool IsBranchSamplingSupported() {
43 const EventType* type = FindEventTypeByName("cpu-cycles");
44 if (type == nullptr) {
45 return false;
46 }
47 perf_event_attr attr = CreateDefaultPerfEventAttr(*type);
48 attr.sample_type |= PERF_SAMPLE_BRANCH_STACK;
49 attr.branch_sample_type = PERF_SAMPLE_BRANCH_ANY;
50 return IsEventAttrSupported(attr, type->name);
51 }
52
IsDwarfCallChainSamplingSupported()53 bool IsDwarfCallChainSamplingSupported() {
54 if (auto version = GetKernelVersion(); version && version.value() >= std::make_pair(3, 18)) {
55 // Skip test on kernel >= 3.18, which has all patches needed to support dwarf callchain.
56 return true;
57 }
58 const EventType* type = FindEventTypeByName("cpu-clock");
59 if (type == nullptr) {
60 return false;
61 }
62 perf_event_attr attr = CreateDefaultPerfEventAttr(*type);
63 attr.sample_type |= PERF_SAMPLE_CALLCHAIN | PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER;
64 attr.exclude_callchain_user = 1;
65 attr.sample_regs_user = GetSupportedRegMask(GetTargetArch());
66 attr.sample_stack_user = 8192;
67 return IsEventAttrSupported(attr, type->name);
68 }
69
IsDumpingRegsForTracepointEventsSupported()70 bool IsDumpingRegsForTracepointEventsSupported() {
71 if (auto version = GetKernelVersion(); version && version.value() >= std::make_pair(4, 2)) {
72 // Kernel >= 4.2 has patch "5b09a094f2 arm64: perf: Fix callchain parse error with kernel
73 // tracepoint events". So no need to test.
74 return true;
75 }
76 const EventType* event_type = FindEventTypeByName("sched:sched_switch", false);
77 if (event_type == nullptr) {
78 return false;
79 }
80 std::atomic<bool> done(false);
81 std::atomic<pid_t> thread_id(0);
82 std::thread thread([&]() {
83 thread_id = gettid();
84 while (!done) {
85 usleep(1);
86 }
87 usleep(1); // Make a sched out to generate one sample.
88 });
89 while (thread_id == 0) {
90 usleep(1);
91 }
92 perf_event_attr attr = CreateDefaultPerfEventAttr(*event_type);
93 attr.freq = 0;
94 attr.sample_period = 1;
95 std::unique_ptr<EventFd> event_fd =
96 EventFd::OpenEventFile(attr, thread_id, -1, nullptr, event_type->name);
97 if (event_fd == nullptr || !event_fd->CreateMappedBuffer(4, true)) {
98 done = true;
99 thread.join();
100 return false;
101 }
102 done = true;
103 thread.join();
104
105 // There are small chances that we don't see samples immediately after joining the thread on
106 // cuttlefish, probably due to data synchronization between cpus. To avoid flaky tests, use a
107 // loop to wait for samples.
108 for (int timeout = 0; timeout < 1000; timeout++) {
109 std::vector<char> buffer = event_fd->GetAvailableMmapData();
110 std::vector<std::unique_ptr<Record>> records =
111 ReadRecordsFromBuffer(attr, buffer.data(), buffer.size());
112 for (auto& r : records) {
113 if (r->type() == PERF_RECORD_SAMPLE) {
114 auto& record = *static_cast<SampleRecord*>(r.get());
115 return record.ip_data.ip != 0;
116 }
117 }
118 usleep(1);
119 }
120 return false;
121 }
122
IsSettingClockIdSupported()123 bool IsSettingClockIdSupported() {
124 // Do the real check only once and keep the result in a static variable.
125 static int is_supported = -1;
126 if (is_supported == -1) {
127 is_supported = 0;
128 if (auto version = GetKernelVersion(); version && version.value() >= std::make_pair(4, 1)) {
129 // Kernel >= 4.1 has patch "34f43927 perf: Add per event clockid support". So no need to test.
130 is_supported = 1;
131 } else if (const EventType* type = FindEventTypeByName("cpu-clock"); type != nullptr) {
132 // Check if the kernel supports setting clockid, which was added in kernel 4.0. Just check
133 // with one clockid is enough. Because all needed clockids were supported before kernel 4.0.
134 perf_event_attr attr = CreateDefaultPerfEventAttr(*type);
135 attr.use_clockid = 1;
136 attr.clockid = CLOCK_MONOTONIC;
137 is_supported = IsEventAttrSupported(attr, type->name) ? 1 : 0;
138 }
139 }
140 return is_supported;
141 }
142
IsMmap2Supported()143 bool IsMmap2Supported() {
144 if (auto version = GetKernelVersion(); version && version.value() >= std::make_pair(3, 12)) {
145 // Kernel >= 3.12 has patch "13d7a2410 perf: Add attr->mmap2 attribute to an event". So no need
146 // to test.
147 return true;
148 }
149 const EventType* type = FindEventTypeByName("cpu-clock");
150 if (type == nullptr) {
151 return false;
152 }
153 perf_event_attr attr = CreateDefaultPerfEventAttr(*type);
154 attr.mmap2 = 1;
155 return IsEventAttrSupported(attr, type->name);
156 }
157
IsHardwareEventSupported()158 bool IsHardwareEventSupported() {
159 const EventType* type = FindEventTypeByName("cpu-cycles");
160 if (type == nullptr) {
161 return false;
162 }
163 perf_event_attr attr = CreateDefaultPerfEventAttr(*type);
164 return IsEventAttrSupported(attr, type->name);
165 }
166
IsSwitchRecordSupported()167 bool IsSwitchRecordSupported() {
168 // Kernel >= 4.3 has patch "45ac1403f perf: Add PERF_RECORD_SWITCH to indicate context switches".
169 auto version = GetKernelVersion();
170 return version && version.value() >= std::make_pair(4, 3);
171 }
172
ToString() const173 std::string AddrFilter::ToString() const {
174 switch (type) {
175 case FILE_RANGE:
176 return StringPrintf("filter 0x%" PRIx64 "/0x%" PRIx64 "@%s", addr, size, file_path.c_str());
177 case AddrFilter::FILE_START:
178 return StringPrintf("start 0x%" PRIx64 "@%s", addr, file_path.c_str());
179 case AddrFilter::FILE_STOP:
180 return StringPrintf("stop 0x%" PRIx64 "@%s", addr, file_path.c_str());
181 case AddrFilter::KERNEL_RANGE:
182 return StringPrintf("filter 0x%" PRIx64 "/0x%" PRIx64, addr, size);
183 case AddrFilter::KERNEL_START:
184 return StringPrintf("start 0x%" PRIx64, addr);
185 case AddrFilter::KERNEL_STOP:
186 return StringPrintf("stop 0x%" PRIx64, addr);
187 }
188 }
189
EventSelectionSet(bool for_stat_cmd)190 EventSelectionSet::EventSelectionSet(bool for_stat_cmd)
191 : for_stat_cmd_(for_stat_cmd), loop_(new IOEventLoop) {}
192
~EventSelectionSet()193 EventSelectionSet::~EventSelectionSet() {}
194
BuildAndCheckEventSelection(const std::string & event_name,bool first_event,EventSelection * selection)195 bool EventSelectionSet::BuildAndCheckEventSelection(const std::string& event_name, bool first_event,
196 EventSelection* selection) {
197 std::unique_ptr<EventTypeAndModifier> event_type = ParseEventType(event_name);
198 if (event_type == nullptr) {
199 return false;
200 }
201 if (for_stat_cmd_) {
202 if (event_type->event_type.name == "cpu-clock" || event_type->event_type.name == "task-clock") {
203 if (event_type->exclude_user || event_type->exclude_kernel) {
204 LOG(ERROR) << "Modifier u and modifier k used in event type " << event_type->event_type.name
205 << " are not supported by the kernel.";
206 return false;
207 }
208 }
209 }
210 selection->event_type_modifier = *event_type;
211 selection->event_attr = CreateDefaultPerfEventAttr(event_type->event_type);
212 selection->event_attr.exclude_user = event_type->exclude_user;
213 selection->event_attr.exclude_kernel = event_type->exclude_kernel;
214 selection->event_attr.exclude_hv = event_type->exclude_hv;
215 selection->event_attr.exclude_host = event_type->exclude_host;
216 selection->event_attr.exclude_guest = event_type->exclude_guest;
217 selection->event_attr.precise_ip = event_type->precise_ip;
218 if (IsEtmEventType(event_type->event_type.type)) {
219 auto& etm_recorder = ETMRecorder::GetInstance();
220 if (auto result = etm_recorder.CheckEtmSupport(); !result.ok()) {
221 LOG(ERROR) << result.error();
222 return false;
223 }
224 ETMRecorder::GetInstance().SetEtmPerfEventAttr(&selection->event_attr);
225 }
226 bool set_default_sample_freq = false;
227 if (!for_stat_cmd_) {
228 if (event_type->event_type.type == PERF_TYPE_TRACEPOINT) {
229 selection->event_attr.freq = 0;
230 selection->event_attr.sample_period = DEFAULT_SAMPLE_PERIOD_FOR_TRACEPOINT_EVENT;
231 } else if (IsEtmEventType(event_type->event_type.type)) {
232 // ETM recording has no sample frequency to adjust. Using sample frequency only wastes time
233 // enabling/disabling etm devices. So don't adjust frequency by default.
234 selection->event_attr.freq = 0;
235 selection->event_attr.sample_period = 1;
236 } else {
237 selection->event_attr.freq = 1;
238 // Set default sample freq here may print msg "Adjust sample freq to max allowed sample
239 // freq". But this is misleading. Because default sample freq may not be the final sample
240 // freq we use. So use minimum sample freq (1) here.
241 selection->event_attr.sample_freq = 1;
242 set_default_sample_freq = true;
243 }
244 // We only need to dump mmap and comm records for the first event type. Because all event types
245 // are monitoring the same processes.
246 if (first_event) {
247 selection->event_attr.mmap = 1;
248 selection->event_attr.comm = 1;
249 if (IsMmap2Supported()) {
250 selection->event_attr.mmap2 = 1;
251 }
252 }
253 }
254 // PMU events are provided by kernel, so they should be supported
255 if (!event_type->event_type.IsPmuEvent() &&
256 !IsEventAttrSupported(selection->event_attr, selection->event_type_modifier.name)) {
257 LOG(ERROR) << "Event type '" << event_type->name << "' is not supported on the device";
258 return false;
259 }
260 if (set_default_sample_freq) {
261 selection->event_attr.sample_freq = DEFAULT_SAMPLE_FREQ_FOR_NONTRACEPOINT_EVENT;
262 }
263
264 selection->event_fds.clear();
265
266 for (const auto& group : groups_) {
267 for (const auto& sel : group) {
268 if (sel.event_type_modifier.name == selection->event_type_modifier.name) {
269 LOG(ERROR) << "Event type '" << sel.event_type_modifier.name << "' appears more than once";
270 return false;
271 }
272 }
273 }
274 return true;
275 }
276
AddEventType(const std::string & event_name,size_t * group_id)277 bool EventSelectionSet::AddEventType(const std::string& event_name, size_t* group_id) {
278 return AddEventGroup(std::vector<std::string>(1, event_name), group_id);
279 }
280
AddEventGroup(const std::vector<std::string> & event_names,size_t * group_id)281 bool EventSelectionSet::AddEventGroup(const std::vector<std::string>& event_names,
282 size_t* group_id) {
283 EventSelectionGroup group;
284 bool first_event = groups_.empty();
285 bool first_in_group = true;
286 for (const auto& event_name : event_names) {
287 EventSelection selection;
288 if (!BuildAndCheckEventSelection(event_name, first_event, &selection)) {
289 return false;
290 }
291 if (IsEtmEventType(selection.event_attr.type)) {
292 has_aux_trace_ = true;
293 }
294 if (first_in_group) {
295 auto& event_type = selection.event_type_modifier.event_type;
296 if (event_type.IsPmuEvent()) {
297 selection.allowed_cpus = event_type.GetPmuCpumask();
298 }
299 }
300 first_event = false;
301 first_in_group = false;
302 group.push_back(std::move(selection));
303 }
304 groups_.push_back(std::move(group));
305 UnionSampleType();
306 if (group_id != nullptr) {
307 *group_id = groups_.size() - 1;
308 }
309 return true;
310 }
311
AddCounters(const std::vector<std::string> & event_names)312 bool EventSelectionSet::AddCounters(const std::vector<std::string>& event_names) {
313 CHECK(!groups_.empty());
314 if (groups_.size() > 1) {
315 LOG(ERROR) << "Failed to add counters. Only one event group is allowed.";
316 return false;
317 }
318 for (const auto& event_name : event_names) {
319 EventSelection selection;
320 if (!BuildAndCheckEventSelection(event_name, false, &selection)) {
321 return false;
322 }
323 // Use a big sample_period to avoid getting samples for added counters.
324 selection.event_attr.freq = 0;
325 selection.event_attr.sample_period = INFINITE_SAMPLE_PERIOD;
326 selection.event_attr.inherit = 0;
327 groups_[0].emplace_back(std::move(selection));
328 }
329 // Add counters in each sample.
330 for (auto& selection : groups_[0]) {
331 selection.event_attr.sample_type |= PERF_SAMPLE_READ;
332 selection.event_attr.read_format |= PERF_FORMAT_GROUP;
333 }
334 return true;
335 }
336
GetEvents() const337 std::vector<const EventType*> EventSelectionSet::GetEvents() const {
338 std::vector<const EventType*> result;
339 for (const auto& group : groups_) {
340 for (const auto& selection : group) {
341 result.push_back(&selection.event_type_modifier.event_type);
342 }
343 }
344 return result;
345 }
346
GetTracepointEvents() const347 std::vector<const EventType*> EventSelectionSet::GetTracepointEvents() const {
348 std::vector<const EventType*> result;
349 for (const auto& group : groups_) {
350 for (const auto& selection : group) {
351 if (selection.event_type_modifier.event_type.type == PERF_TYPE_TRACEPOINT) {
352 result.push_back(&selection.event_type_modifier.event_type);
353 }
354 }
355 }
356 return result;
357 }
358
ExcludeKernel() const359 bool EventSelectionSet::ExcludeKernel() const {
360 for (const auto& group : groups_) {
361 for (const auto& selection : group) {
362 if (!selection.event_type_modifier.exclude_kernel) {
363 return false;
364 }
365 }
366 }
367 return true;
368 }
369
GetEventAttrWithId() const370 std::vector<EventAttrWithId> EventSelectionSet::GetEventAttrWithId() const {
371 std::vector<EventAttrWithId> result;
372 for (const auto& group : groups_) {
373 for (const auto& selection : group) {
374 EventAttrWithId attr_id;
375 attr_id.attr = &selection.event_attr;
376 for (const auto& fd : selection.event_fds) {
377 attr_id.ids.push_back(fd->Id());
378 }
379 result.push_back(attr_id);
380 }
381 }
382 return result;
383 }
384
GetEventNamesById() const385 std::unordered_map<uint64_t, std::string> EventSelectionSet::GetEventNamesById() const {
386 std::unordered_map<uint64_t, std::string> result;
387 for (const auto& group : groups_) {
388 for (const auto& selection : group) {
389 for (const auto& fd : selection.event_fds) {
390 result[fd->Id()] = selection.event_type_modifier.name;
391 }
392 }
393 }
394 return result;
395 }
396
397 // Union the sample type of different event attrs can make reading sample
398 // records in perf.data easier.
UnionSampleType()399 void EventSelectionSet::UnionSampleType() {
400 uint64_t sample_type = 0;
401 for (const auto& group : groups_) {
402 for (const auto& selection : group) {
403 sample_type |= selection.event_attr.sample_type;
404 }
405 }
406 for (auto& group : groups_) {
407 for (auto& selection : group) {
408 selection.event_attr.sample_type = sample_type;
409 }
410 }
411 }
412
SetEnableOnExec(bool enable)413 void EventSelectionSet::SetEnableOnExec(bool enable) {
414 for (auto& group : groups_) {
415 for (auto& selection : group) {
416 // If sampling is enabled on exec, then it is disabled at startup,
417 // otherwise it should be enabled at startup. Don't use
418 // ioctl(PERF_EVENT_IOC_ENABLE) to enable it after perf_event_open().
419 // Because some android kernels can't handle ioctl() well when cpu-hotplug
420 // happens. See http://b/25193162.
421 if (enable) {
422 selection.event_attr.enable_on_exec = 1;
423 selection.event_attr.disabled = 1;
424 } else {
425 selection.event_attr.enable_on_exec = 0;
426 selection.event_attr.disabled = 0;
427 }
428 }
429 }
430 }
431
GetEnableOnExec()432 bool EventSelectionSet::GetEnableOnExec() {
433 for (const auto& group : groups_) {
434 for (const auto& selection : group) {
435 if (selection.event_attr.enable_on_exec == 0) {
436 return false;
437 }
438 }
439 }
440 return true;
441 }
442
SampleIdAll()443 void EventSelectionSet::SampleIdAll() {
444 for (auto& group : groups_) {
445 for (auto& selection : group) {
446 selection.event_attr.sample_id_all = 1;
447 }
448 }
449 }
450
SetSampleSpeed(size_t group_id,const SampleSpeed & speed)451 void EventSelectionSet::SetSampleSpeed(size_t group_id, const SampleSpeed& speed) {
452 CHECK_LT(group_id, groups_.size());
453 for (auto& selection : groups_[group_id]) {
454 if (speed.UseFreq()) {
455 selection.event_attr.freq = 1;
456 selection.event_attr.sample_freq = speed.sample_freq;
457 } else {
458 selection.event_attr.freq = 0;
459 selection.event_attr.sample_period = speed.sample_period;
460 }
461 }
462 }
463
SetBranchSampling(uint64_t branch_sample_type)464 bool EventSelectionSet::SetBranchSampling(uint64_t branch_sample_type) {
465 if (branch_sample_type != 0 &&
466 (branch_sample_type & (PERF_SAMPLE_BRANCH_ANY | PERF_SAMPLE_BRANCH_ANY_CALL |
467 PERF_SAMPLE_BRANCH_ANY_RETURN | PERF_SAMPLE_BRANCH_IND_CALL)) == 0) {
468 LOG(ERROR) << "Invalid branch_sample_type: 0x" << std::hex << branch_sample_type;
469 return false;
470 }
471 if (branch_sample_type != 0 && !IsBranchSamplingSupported()) {
472 LOG(ERROR) << "branch stack sampling is not supported on this device.";
473 return false;
474 }
475 for (auto& group : groups_) {
476 for (auto& selection : group) {
477 perf_event_attr& attr = selection.event_attr;
478 if (branch_sample_type != 0) {
479 attr.sample_type |= PERF_SAMPLE_BRANCH_STACK;
480 } else {
481 attr.sample_type &= ~PERF_SAMPLE_BRANCH_STACK;
482 }
483 attr.branch_sample_type = branch_sample_type;
484 }
485 }
486 return true;
487 }
488
EnableFpCallChainSampling()489 void EventSelectionSet::EnableFpCallChainSampling() {
490 for (auto& group : groups_) {
491 for (auto& selection : group) {
492 selection.event_attr.sample_type |= PERF_SAMPLE_CALLCHAIN;
493 }
494 }
495 }
496
EnableDwarfCallChainSampling(uint32_t dump_stack_size)497 bool EventSelectionSet::EnableDwarfCallChainSampling(uint32_t dump_stack_size) {
498 if (!IsDwarfCallChainSamplingSupported()) {
499 LOG(ERROR) << "dwarf callchain sampling is not supported on this device.";
500 return false;
501 }
502 for (auto& group : groups_) {
503 for (auto& selection : group) {
504 selection.event_attr.sample_type |=
505 PERF_SAMPLE_CALLCHAIN | PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER;
506 selection.event_attr.exclude_callchain_user = 1;
507 selection.event_attr.sample_regs_user = GetSupportedRegMask(GetMachineArch());
508 selection.event_attr.sample_stack_user = dump_stack_size;
509 }
510 }
511 return true;
512 }
513
SetInherit(bool enable)514 void EventSelectionSet::SetInherit(bool enable) {
515 for (auto& group : groups_) {
516 for (auto& selection : group) {
517 selection.event_attr.inherit = (enable ? 1 : 0);
518 }
519 }
520 }
521
SetClockId(int clock_id)522 void EventSelectionSet::SetClockId(int clock_id) {
523 for (auto& group : groups_) {
524 for (auto& selection : group) {
525 selection.event_attr.use_clockid = 1;
526 selection.event_attr.clockid = clock_id;
527 }
528 }
529 }
530
NeedKernelSymbol() const531 bool EventSelectionSet::NeedKernelSymbol() const {
532 return !ExcludeKernel();
533 }
534
SetRecordNotExecutableMaps(bool record)535 void EventSelectionSet::SetRecordNotExecutableMaps(bool record) {
536 // We only need to dump non-executable mmap records for the first event type.
537 groups_[0][0].event_attr.mmap_data = record ? 1 : 0;
538 }
539
RecordNotExecutableMaps() const540 bool EventSelectionSet::RecordNotExecutableMaps() const {
541 return groups_[0][0].event_attr.mmap_data == 1;
542 }
543
EnableSwitchRecord()544 void EventSelectionSet::EnableSwitchRecord() {
545 groups_[0][0].event_attr.context_switch = 1;
546 }
547
WakeupPerSample()548 void EventSelectionSet::WakeupPerSample() {
549 for (auto& group : groups_) {
550 for (auto& selection : group) {
551 selection.event_attr.watermark = 0;
552 selection.event_attr.wakeup_events = 1;
553 }
554 }
555 }
556
SetTracepointFilter(const std::string & filter)557 bool EventSelectionSet::SetTracepointFilter(const std::string& filter) {
558 // 1. Find the tracepoint event to set filter.
559 EventSelection* selection = nullptr;
560 if (!groups_.empty()) {
561 auto& group = groups_.back();
562 if (group.size() == 1) {
563 if (group[0].event_attr.type == PERF_TYPE_TRACEPOINT) {
564 selection = &group[0];
565 }
566 }
567 }
568 if (selection == nullptr) {
569 LOG(ERROR) << "No tracepoint event before filter: " << filter;
570 return false;
571 }
572
573 // 2. Check the format of the filter.
574 bool use_quote = false;
575 // Quotes are needed for string operands in kernel >= 4.19, probably after patch "tracing: Rewrite
576 // filter logic to be simpler and faster".
577 if (auto version = GetKernelVersion(); version && version.value() >= std::make_pair(4, 19)) {
578 use_quote = true;
579 }
580
581 FieldNameSet used_fields;
582 auto adjusted_filter = AdjustTracepointFilter(filter, use_quote, &used_fields);
583 if (!adjusted_filter) {
584 return false;
585 }
586
587 // 3. Check if used fields are available in the tracepoint event.
588 auto& event_type = selection->event_type_modifier.event_type;
589 if (auto opt_fields = GetFieldNamesForTracepointEvent(event_type); opt_fields) {
590 FieldNameSet& fields = opt_fields.value();
591 for (const auto& field : used_fields) {
592 if (fields.find(field) == fields.end()) {
593 LOG(ERROR) << "field name " << field << " used in \"" << filter << "\" doesn't exist in "
594 << event_type.name << ". Available fields are "
595 << android::base::Join(fields, ",");
596 return false;
597 }
598 }
599 }
600
601 // 4. Connect the filter to the event.
602 selection->tracepoint_filter = adjusted_filter.value();
603 return true;
604 }
605
CheckIfCpusOnline(const std::vector<int> & cpus)606 static bool CheckIfCpusOnline(const std::vector<int>& cpus) {
607 std::vector<int> online_cpus = GetOnlineCpus();
608 for (const auto& cpu : cpus) {
609 if (std::find(online_cpus.begin(), online_cpus.end(), cpu) == online_cpus.end()) {
610 LOG(ERROR) << "cpu " << cpu << " is not online.";
611 return false;
612 }
613 }
614 return true;
615 }
616
OpenEventFilesOnGroup(EventSelectionGroup & group,pid_t tid,int cpu,std::string * failed_event_type)617 bool EventSelectionSet::OpenEventFilesOnGroup(EventSelectionGroup& group, pid_t tid, int cpu,
618 std::string* failed_event_type) {
619 std::vector<std::unique_ptr<EventFd>> event_fds;
620 // Given a tid and cpu, events on the same group should be all opened
621 // successfully or all failed to open.
622 EventFd* group_fd = nullptr;
623 for (auto& selection : group) {
624 std::unique_ptr<EventFd> event_fd = EventFd::OpenEventFile(
625 selection.event_attr, tid, cpu, group_fd, selection.event_type_modifier.name, false);
626 if (!event_fd) {
627 *failed_event_type = selection.event_type_modifier.name;
628 return false;
629 }
630 LOG(VERBOSE) << "OpenEventFile for " << event_fd->Name();
631 event_fds.push_back(std::move(event_fd));
632 if (group_fd == nullptr) {
633 group_fd = event_fds.back().get();
634 }
635 }
636 for (size_t i = 0; i < group.size(); ++i) {
637 group[i].event_fds.push_back(std::move(event_fds[i]));
638 }
639 return true;
640 }
641
PrepareThreads(const std::set<pid_t> & processes,const std::set<pid_t> & threads)642 static std::set<pid_t> PrepareThreads(const std::set<pid_t>& processes,
643 const std::set<pid_t>& threads) {
644 std::set<pid_t> result = threads;
645 for (auto& pid : processes) {
646 std::vector<pid_t> tids = GetThreadsInProcess(pid);
647 result.insert(tids.begin(), tids.end());
648 }
649 return result;
650 }
651
OpenEventFiles(const std::vector<int> & cpus)652 bool EventSelectionSet::OpenEventFiles(const std::vector<int>& cpus) {
653 std::vector<int> monitored_cpus;
654 if (cpus.empty()) {
655 monitored_cpus = GetOnlineCpus();
656 } else if (cpus.size() == 1 && cpus[0] == -1) {
657 monitored_cpus = {-1};
658 } else {
659 if (!CheckIfCpusOnline(cpus)) {
660 return false;
661 }
662 monitored_cpus = cpus;
663 }
664 std::set<pid_t> threads = PrepareThreads(processes_, threads_);
665 for (auto& group : groups_) {
666 size_t success_count = 0;
667 std::string failed_event_type;
668 for (const auto tid : threads) {
669 const std::vector<int>* pcpus = &monitored_cpus;
670 if (!group[0].allowed_cpus.empty()) {
671 // override cpu list if event's PMU has a cpumask as those PMUs are
672 // agnostic to cpu and it's meaningless to specify cpus for them.
673 pcpus = &group[0].allowed_cpus;
674 }
675 for (const auto& cpu : *pcpus) {
676 if (OpenEventFilesOnGroup(group, tid, cpu, &failed_event_type)) {
677 success_count++;
678 }
679 }
680 }
681 // We can't guarantee to open perf event file successfully for each thread on each cpu.
682 // Because threads may exit between PrepareThreads() and OpenEventFilesOnGroup(), and
683 // cpus may be offlined between GetOnlineCpus() and OpenEventFilesOnGroup().
684 // So we only check that we can at least monitor one thread for each event group.
685 if (success_count == 0) {
686 int error_number = errno;
687 PLOG(ERROR) << "failed to open perf event file for event_type " << failed_event_type;
688 if (error_number == EMFILE) {
689 LOG(ERROR) << "Please increase hard limit of open file numbers.";
690 }
691 return false;
692 }
693 }
694 return ApplyFilters();
695 }
696
ApplyFilters()697 bool EventSelectionSet::ApplyFilters() {
698 return ApplyAddrFilters() && ApplyTracepointFilters();
699 }
700
ApplyAddrFilters()701 bool EventSelectionSet::ApplyAddrFilters() {
702 if (addr_filters_.empty()) {
703 return true;
704 }
705 if (!has_aux_trace_) {
706 LOG(ERROR) << "addr filters only take effect in cs-etm instruction tracing";
707 return false;
708 }
709
710 // Check filter count limit.
711 size_t required_etm_filter_count = 0;
712 for (auto& filter : addr_filters_) {
713 // A range filter needs two etm filters.
714 required_etm_filter_count +=
715 (filter.type == AddrFilter::FILE_RANGE || filter.type == AddrFilter::KERNEL_RANGE) ? 2 : 1;
716 }
717 size_t etm_filter_count = ETMRecorder::GetInstance().GetAddrFilterPairs() * 2;
718 if (etm_filter_count < required_etm_filter_count) {
719 LOG(ERROR) << "needed " << required_etm_filter_count << " etm filters, but only "
720 << etm_filter_count << " filters are available.";
721 return false;
722 }
723
724 std::string filter_str;
725 for (auto& filter : addr_filters_) {
726 if (!filter_str.empty()) {
727 filter_str += ',';
728 }
729 filter_str += filter.ToString();
730 }
731
732 for (auto& group : groups_) {
733 for (auto& selection : group) {
734 if (IsEtmEventType(selection.event_type_modifier.event_type.type)) {
735 for (auto& event_fd : selection.event_fds) {
736 if (!event_fd->SetFilter(filter_str)) {
737 return false;
738 }
739 }
740 }
741 }
742 }
743 return true;
744 }
745
ApplyTracepointFilters()746 bool EventSelectionSet::ApplyTracepointFilters() {
747 for (auto& group : groups_) {
748 for (auto& selection : group) {
749 if (!selection.tracepoint_filter.empty()) {
750 for (auto& event_fd : selection.event_fds) {
751 if (!event_fd->SetFilter(selection.tracepoint_filter)) {
752 return false;
753 }
754 }
755 }
756 }
757 }
758 return true;
759 }
760
ReadCounter(EventFd * event_fd,CounterInfo * counter)761 static bool ReadCounter(EventFd* event_fd, CounterInfo* counter) {
762 if (!event_fd->ReadCounter(&counter->counter)) {
763 return false;
764 }
765 counter->tid = event_fd->ThreadId();
766 counter->cpu = event_fd->Cpu();
767 return true;
768 }
769
ReadCounters(std::vector<CountersInfo> * counters)770 bool EventSelectionSet::ReadCounters(std::vector<CountersInfo>* counters) {
771 counters->clear();
772 for (size_t i = 0; i < groups_.size(); ++i) {
773 for (auto& selection : groups_[i]) {
774 CountersInfo counters_info;
775 counters_info.group_id = i;
776 counters_info.event_name = selection.event_type_modifier.event_type.name;
777 counters_info.event_modifier = selection.event_type_modifier.modifier;
778 counters_info.counters = selection.hotplugged_counters;
779 for (auto& event_fd : selection.event_fds) {
780 CounterInfo counter;
781 if (!ReadCounter(event_fd.get(), &counter)) {
782 return false;
783 }
784 counters_info.counters.push_back(counter);
785 }
786 counters->push_back(counters_info);
787 }
788 }
789 return true;
790 }
791
MmapEventFiles(size_t min_mmap_pages,size_t max_mmap_pages,size_t aux_buffer_size,size_t record_buffer_size,bool allow_cutting_samples,bool exclude_perf)792 bool EventSelectionSet::MmapEventFiles(size_t min_mmap_pages, size_t max_mmap_pages,
793 size_t aux_buffer_size, size_t record_buffer_size,
794 bool allow_cutting_samples, bool exclude_perf) {
795 record_read_thread_.reset(new simpleperf::RecordReadThread(
796 record_buffer_size, groups_[0][0].event_attr, min_mmap_pages, max_mmap_pages, aux_buffer_size,
797 allow_cutting_samples, exclude_perf));
798 return true;
799 }
800
PrepareToReadMmapEventData(const std::function<bool (Record *)> & callback)801 bool EventSelectionSet::PrepareToReadMmapEventData(const std::function<bool(Record*)>& callback) {
802 // Prepare record callback function.
803 record_callback_ = callback;
804 if (!record_read_thread_->RegisterDataCallback(*loop_,
805 [this]() { return ReadMmapEventData(true); })) {
806 return false;
807 }
808 std::vector<EventFd*> event_fds;
809 for (auto& group : groups_) {
810 for (auto& selection : group) {
811 for (auto& event_fd : selection.event_fds) {
812 event_fds.push_back(event_fd.get());
813 }
814 }
815 }
816 return record_read_thread_->AddEventFds(event_fds);
817 }
818
SyncKernelBuffer()819 bool EventSelectionSet::SyncKernelBuffer() {
820 return record_read_thread_->SyncKernelBuffer();
821 }
822
823 // Read records from the RecordBuffer. If with_time_limit is false, read until the RecordBuffer is
824 // empty, otherwise stop after 100 ms or when the record buffer is empty.
ReadMmapEventData(bool with_time_limit)825 bool EventSelectionSet::ReadMmapEventData(bool with_time_limit) {
826 uint64_t start_time_in_ns;
827 if (with_time_limit) {
828 start_time_in_ns = GetSystemClock();
829 }
830 std::unique_ptr<Record> r;
831 while ((r = record_read_thread_->GetRecord()) != nullptr) {
832 if (!record_callback_(r.get())) {
833 return false;
834 }
835 if (with_time_limit && (GetSystemClock() - start_time_in_ns) >= 1e8) {
836 break;
837 }
838 }
839 return true;
840 }
841
FinishReadMmapEventData()842 bool EventSelectionSet::FinishReadMmapEventData() {
843 return ReadMmapEventData(false);
844 }
845
CloseEventFiles()846 void EventSelectionSet::CloseEventFiles() {
847 if (record_read_thread_) {
848 record_read_thread_->StopReadThread();
849 }
850 for (auto& group : groups_) {
851 for (auto& event : group) {
852 event.event_fds.clear();
853 }
854 }
855 }
856
StopWhenNoMoreTargets(double check_interval_in_sec)857 bool EventSelectionSet::StopWhenNoMoreTargets(double check_interval_in_sec) {
858 return loop_->AddPeriodicEvent(SecondToTimeval(check_interval_in_sec),
859 [&]() { return CheckMonitoredTargets(); });
860 }
861
CheckMonitoredTargets()862 bool EventSelectionSet::CheckMonitoredTargets() {
863 if (!HasSampler()) {
864 return loop_->ExitLoop();
865 }
866 for (const auto& tid : threads_) {
867 if (IsThreadAlive(tid)) {
868 return true;
869 }
870 }
871 for (const auto& pid : processes_) {
872 if (IsThreadAlive(pid)) {
873 return true;
874 }
875 }
876 return loop_->ExitLoop();
877 }
878
HasSampler()879 bool EventSelectionSet::HasSampler() {
880 for (auto& group : groups_) {
881 for (auto& sel : group) {
882 if (!sel.event_fds.empty()) {
883 return true;
884 }
885 }
886 }
887 return false;
888 }
889
SetEnableEvents(bool enable)890 bool EventSelectionSet::SetEnableEvents(bool enable) {
891 for (auto& group : groups_) {
892 for (auto& sel : group) {
893 for (auto& fd : sel.event_fds) {
894 if (!fd->SetEnableEvent(enable)) {
895 return false;
896 }
897 }
898 }
899 }
900 return true;
901 }
902
903 } // namespace simpleperf
904