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