xref: /aosp_15_r20/system/extras/simpleperf/event_selection_set.cpp (revision 288bf5226967eb3dac5cce6c939ccc2a7f2b4fe5)
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("BR_INST_RETIRED.NEAR_TAKEN");
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     // The kernel (rb_allocate_aux) allocates high order of pages based on aux_watermark.
226     // To avoid that, use aux_watermark <= 1 page size.
227     selection->event_attr.aux_watermark = 4096;
228   }
229   bool set_default_sample_freq = false;
230   if (!for_stat_cmd_) {
231     if (event_type->event_type.type == PERF_TYPE_TRACEPOINT) {
232       selection->event_attr.freq = 0;
233       selection->event_attr.sample_period = DEFAULT_SAMPLE_PERIOD_FOR_TRACEPOINT_EVENT;
234     } else if (IsEtmEventType(event_type->event_type.type)) {
235       // ETM recording has no sample frequency to adjust. Using sample frequency only wastes time
236       // enabling/disabling etm devices. So don't adjust frequency by default.
237       selection->event_attr.freq = 0;
238       selection->event_attr.sample_period = 1;
239       // An ETM event can't be enabled without mmap aux buffer. So disable it by default.
240       selection->event_attr.disabled = 1;
241     } else {
242       selection->event_attr.freq = 1;
243       // Set default sample freq here may print msg "Adjust sample freq to max allowed sample
244       // freq". But this is misleading. Because default sample freq may not be the final sample
245       // freq we use. So use minimum sample freq (1) here.
246       selection->event_attr.sample_freq = 1;
247       set_default_sample_freq = true;
248     }
249     // We only need to dump mmap and comm records for the first event type. Because all event types
250     // are monitoring the same processes.
251     if (first_event) {
252       selection->event_attr.mmap = 1;
253       selection->event_attr.comm = 1;
254       if (IsMmap2Supported()) {
255         selection->event_attr.mmap2 = 1;
256       }
257     }
258   }
259   // PMU events are provided by kernel, so they should be supported
260   if (!event_type->event_type.IsPmuEvent() &&
261       !IsEventAttrSupported(selection->event_attr, selection->event_type_modifier.name)) {
262     LOG(ERROR) << "Event type '" << event_type->name << "' is not supported on the device";
263     return false;
264   }
265   if (set_default_sample_freq) {
266     selection->event_attr.sample_freq = DEFAULT_SAMPLE_FREQ_FOR_NONTRACEPOINT_EVENT;
267   }
268 
269   selection->event_fds.clear();
270 
271   for (const auto& group : groups_) {
272     for (const auto& sel : group.selections) {
273       if (sel.event_type_modifier.name == selection->event_type_modifier.name) {
274         LOG(ERROR) << "Event type '" << sel.event_type_modifier.name << "' appears more than once";
275         return false;
276       }
277     }
278   }
279   return true;
280 }
281 
AddEventType(const std::string & event_name)282 bool EventSelectionSet::AddEventType(const std::string& event_name) {
283   return AddEventGroup(std::vector<std::string>(1, event_name));
284 }
285 
AddEventType(const std::string & event_name,const SampleRate & sample_rate)286 bool EventSelectionSet::AddEventType(const std::string& event_name, const SampleRate& sample_rate) {
287   if (!AddEventGroup(std::vector<std::string>(1, event_name))) {
288     return false;
289   }
290   SetSampleRateForGroup(groups_.back(), sample_rate);
291   return true;
292 }
293 
AddEventGroup(const std::vector<std::string> & event_names)294 bool EventSelectionSet::AddEventGroup(const std::vector<std::string>& event_names) {
295   EventSelectionGroup group;
296   bool first_event = groups_.empty();
297   bool first_in_group = true;
298   for (const auto& event_name : event_names) {
299     EventSelection selection;
300     if (!BuildAndCheckEventSelection(event_name, first_event, &selection)) {
301       return false;
302     }
303     if (IsEtmEventType(selection.event_attr.type)) {
304       has_aux_trace_ = true;
305     }
306     if (first_in_group) {
307       auto& event_type = selection.event_type_modifier.event_type;
308       if (event_type.IsPmuEvent()) {
309         selection.allowed_cpus = event_type.GetPmuCpumask();
310       }
311     }
312     first_event = false;
313     first_in_group = false;
314     group.selections.emplace_back(std::move(selection));
315   }
316   if (sample_rate_) {
317     SetSampleRateForGroup(group, sample_rate_.value());
318   }
319   if (cpus_) {
320     group.cpus = cpus_.value();
321   }
322   groups_.emplace_back(std::move(group));
323   UnionSampleType();
324   return true;
325 }
326 
AddCounters(const std::vector<std::string> & event_names)327 bool EventSelectionSet::AddCounters(const std::vector<std::string>& event_names) {
328   CHECK(!groups_.empty());
329   if (groups_.size() > 1) {
330     LOG(ERROR) << "Failed to add counters. Only one event group is allowed.";
331     return false;
332   }
333   for (const auto& event_name : event_names) {
334     EventSelection selection;
335     if (!BuildAndCheckEventSelection(event_name, false, &selection)) {
336       return false;
337     }
338     // Use a big sample_period to avoid getting samples for added counters.
339     selection.event_attr.freq = 0;
340     selection.event_attr.sample_period = INFINITE_SAMPLE_PERIOD;
341     selection.event_attr.inherit = 0;
342     groups_[0].selections.emplace_back(std::move(selection));
343   }
344   // Add counters in each sample.
345   for (auto& selection : groups_[0].selections) {
346     selection.event_attr.sample_type |= PERF_SAMPLE_READ;
347     selection.event_attr.read_format |= PERF_FORMAT_GROUP;
348   }
349   return true;
350 }
351 
GetEvents() const352 std::vector<const EventType*> EventSelectionSet::GetEvents() const {
353   std::vector<const EventType*> result;
354   for (const auto& group : groups_) {
355     for (const auto& selection : group.selections) {
356       result.push_back(&selection.event_type_modifier.event_type);
357     }
358   }
359   return result;
360 }
361 
GetTracepointEvents() const362 std::vector<const EventType*> EventSelectionSet::GetTracepointEvents() const {
363   std::vector<const EventType*> result;
364   for (const auto& group : groups_) {
365     for (const auto& selection : group.selections) {
366       if (selection.event_type_modifier.event_type.type == PERF_TYPE_TRACEPOINT) {
367         result.push_back(&selection.event_type_modifier.event_type);
368       }
369     }
370   }
371   return result;
372 }
373 
ExcludeKernel() const374 bool EventSelectionSet::ExcludeKernel() const {
375   for (const auto& group : groups_) {
376     for (const auto& selection : group.selections) {
377       if (!selection.event_type_modifier.exclude_kernel) {
378         return false;
379       }
380     }
381   }
382   return true;
383 }
384 
GetEventAttrWithId() const385 EventAttrIds EventSelectionSet::GetEventAttrWithId() const {
386   EventAttrIds result;
387   for (const auto& group : groups_) {
388     for (const auto& selection : group.selections) {
389       std::vector<uint64_t> ids;
390       for (const auto& fd : selection.event_fds) {
391         ids.push_back(fd->Id());
392       }
393       result.resize(result.size() + 1);
394       result.back().attr = selection.event_attr;
395       result.back().ids = std::move(ids);
396     }
397   }
398   return result;
399 }
400 
GetEventNamesById() const401 std::unordered_map<uint64_t, std::string> EventSelectionSet::GetEventNamesById() const {
402   std::unordered_map<uint64_t, std::string> result;
403   for (const auto& group : groups_) {
404     for (const auto& selection : group.selections) {
405       for (const auto& fd : selection.event_fds) {
406         result[fd->Id()] = selection.event_type_modifier.name;
407       }
408     }
409   }
410   return result;
411 }
412 
GetCpusById() const413 std::unordered_map<uint64_t, int> EventSelectionSet::GetCpusById() const {
414   std::unordered_map<uint64_t, int> result;
415   for (const auto& group : groups_) {
416     for (const auto& selection : group.selections) {
417       for (const auto& fd : selection.event_fds) {
418         result[fd->Id()] = fd->Cpu();
419       }
420     }
421   }
422   return result;
423 }
424 
GetHardwareCountersForCpus() const425 std::map<int, size_t> EventSelectionSet::GetHardwareCountersForCpus() const {
426   std::map<int, size_t> cpu_map;
427   std::vector<int> online_cpus = GetOnlineCpus();
428 
429   for (const auto& group : groups_) {
430     size_t hardware_events = 0;
431     for (const auto& selection : group.selections) {
432       if (selection.event_type_modifier.event_type.IsHardwareEvent()) {
433         hardware_events++;
434       }
435     }
436     const std::vector<int>* pcpus = group.cpus.empty() ? &online_cpus : &group.cpus;
437     for (int cpu : *pcpus) {
438       cpu_map[cpu] += hardware_events;
439     }
440   }
441   return cpu_map;
442 }
443 
444 // Union the sample type of different event attrs can make reading sample
445 // records in perf.data easier.
UnionSampleType()446 void EventSelectionSet::UnionSampleType() {
447   uint64_t sample_type = 0;
448   for (const auto& group : groups_) {
449     for (const auto& selection : group.selections) {
450       sample_type |= selection.event_attr.sample_type;
451     }
452   }
453   for (auto& group : groups_) {
454     for (auto& selection : group.selections) {
455       selection.event_attr.sample_type = sample_type;
456     }
457   }
458 }
459 
SetEnableCondition(bool enable_on_open,bool enable_on_exec)460 void EventSelectionSet::SetEnableCondition(bool enable_on_open, bool enable_on_exec) {
461   for (auto& group : groups_) {
462     for (auto& selection : group.selections) {
463       selection.event_attr.disabled = !enable_on_open;
464       selection.event_attr.enable_on_exec = enable_on_exec;
465     }
466   }
467 }
468 
IsEnabledOnExec() const469 bool EventSelectionSet::IsEnabledOnExec() const {
470   for (const auto& group : groups_) {
471     for (const auto& selection : group.selections) {
472       if (!selection.event_attr.enable_on_exec) {
473         return false;
474       }
475     }
476   }
477   return true;
478 }
479 
SampleIdAll()480 void EventSelectionSet::SampleIdAll() {
481   for (auto& group : groups_) {
482     for (auto& selection : group.selections) {
483       selection.event_attr.sample_id_all = 1;
484     }
485   }
486 }
487 
SetSampleRateForNewEvents(const SampleRate & rate)488 void EventSelectionSet::SetSampleRateForNewEvents(const SampleRate& rate) {
489   sample_rate_ = rate;
490   for (auto& group : groups_) {
491     if (!group.set_sample_rate) {
492       SetSampleRateForGroup(group, rate);
493     }
494   }
495 }
496 
SetCpusForNewEvents(const std::vector<int> & cpus)497 void EventSelectionSet::SetCpusForNewEvents(const std::vector<int>& cpus) {
498   cpus_ = cpus;
499   for (auto& group : groups_) {
500     if (group.cpus.empty()) {
501       group.cpus = cpus_.value();
502     }
503   }
504 }
505 
SetSampleRateForGroup(EventSelectionSet::EventSelectionGroup & group,const SampleRate & rate)506 void EventSelectionSet::SetSampleRateForGroup(EventSelectionSet::EventSelectionGroup& group,
507                                               const SampleRate& rate) {
508   group.set_sample_rate = true;
509   for (auto& selection : group.selections) {
510     if (rate.UseFreq()) {
511       selection.event_attr.freq = 1;
512       selection.event_attr.sample_freq = rate.sample_freq;
513     } else {
514       selection.event_attr.freq = 0;
515       selection.event_attr.sample_period = rate.sample_period;
516     }
517   }
518 }
519 
SetBranchSampling(uint64_t branch_sample_type)520 bool EventSelectionSet::SetBranchSampling(uint64_t branch_sample_type) {
521   if (branch_sample_type != 0 &&
522       (branch_sample_type & (PERF_SAMPLE_BRANCH_ANY | PERF_SAMPLE_BRANCH_ANY_CALL |
523                              PERF_SAMPLE_BRANCH_ANY_RETURN | PERF_SAMPLE_BRANCH_IND_CALL)) == 0) {
524     LOG(ERROR) << "Invalid branch_sample_type: 0x" << std::hex << branch_sample_type;
525     return false;
526   }
527   if (branch_sample_type != 0 && !IsBranchSamplingSupported()) {
528     LOG(ERROR) << "branch stack sampling is not supported on this device.";
529     return false;
530   }
531   for (auto& group : groups_) {
532     for (auto& selection : group.selections) {
533       perf_event_attr& attr = selection.event_attr;
534       if (branch_sample_type != 0) {
535         attr.sample_type |= PERF_SAMPLE_BRANCH_STACK;
536       } else {
537         attr.sample_type &= ~PERF_SAMPLE_BRANCH_STACK;
538       }
539       attr.branch_sample_type = branch_sample_type;
540     }
541   }
542   return true;
543 }
544 
EnableFpCallChainSampling()545 void EventSelectionSet::EnableFpCallChainSampling() {
546   for (auto& group : groups_) {
547     for (auto& selection : group.selections) {
548       selection.event_attr.sample_type |= PERF_SAMPLE_CALLCHAIN;
549     }
550   }
551 }
552 
EnableDwarfCallChainSampling(uint32_t dump_stack_size)553 bool EventSelectionSet::EnableDwarfCallChainSampling(uint32_t dump_stack_size) {
554   if (!IsDwarfCallChainSamplingSupported()) {
555     LOG(ERROR) << "dwarf callchain sampling is not supported on this device.";
556     return false;
557   }
558   for (auto& group : groups_) {
559     for (auto& selection : group.selections) {
560       selection.event_attr.sample_type |=
561           PERF_SAMPLE_CALLCHAIN | PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER;
562       selection.event_attr.exclude_callchain_user = 1;
563       selection.event_attr.sample_regs_user = GetSupportedRegMask(GetMachineArch());
564       selection.event_attr.sample_stack_user = dump_stack_size;
565     }
566   }
567   return true;
568 }
569 
SetInherit(bool enable)570 void EventSelectionSet::SetInherit(bool enable) {
571   for (auto& group : groups_) {
572     for (auto& selection : group.selections) {
573       selection.event_attr.inherit = (enable ? 1 : 0);
574     }
575   }
576 }
577 
SetClockId(int clock_id)578 void EventSelectionSet::SetClockId(int clock_id) {
579   for (auto& group : groups_) {
580     for (auto& selection : group.selections) {
581       selection.event_attr.use_clockid = 1;
582       selection.event_attr.clockid = clock_id;
583     }
584   }
585 }
586 
NeedKernelSymbol() const587 bool EventSelectionSet::NeedKernelSymbol() const {
588   return !ExcludeKernel();
589 }
590 
SetRecordNotExecutableMaps(bool record)591 void EventSelectionSet::SetRecordNotExecutableMaps(bool record) {
592   // We only need to dump non-executable mmap records for the first event type.
593   groups_[0].selections[0].event_attr.mmap_data = record ? 1 : 0;
594 }
595 
RecordNotExecutableMaps() const596 bool EventSelectionSet::RecordNotExecutableMaps() const {
597   return groups_[0].selections[0].event_attr.mmap_data == 1;
598 }
599 
EnableSwitchRecord()600 void EventSelectionSet::EnableSwitchRecord() {
601   groups_[0].selections[0].event_attr.context_switch = 1;
602 }
603 
WakeupPerSample()604 void EventSelectionSet::WakeupPerSample() {
605   for (auto& group : groups_) {
606     for (auto& selection : group.selections) {
607       selection.event_attr.watermark = 0;
608       selection.event_attr.wakeup_events = 1;
609     }
610   }
611 }
612 
SetTracepointFilter(const std::string & filter)613 bool EventSelectionSet::SetTracepointFilter(const std::string& filter) {
614   // 1. Find the tracepoint event to set filter.
615   EventSelection* selection = nullptr;
616   if (!groups_.empty()) {
617     auto& group = groups_.back();
618     if (group.selections.size() == 1) {
619       if (group.selections[0].event_attr.type == PERF_TYPE_TRACEPOINT) {
620         selection = &group.selections[0];
621       }
622     }
623   }
624   if (selection == nullptr) {
625     LOG(ERROR) << "No tracepoint event before filter: " << filter;
626     return false;
627   }
628 
629   // 2. Check the format of the filter.
630   bool use_quote = false;
631   // Quotes are needed for string operands in kernel >= 4.19, probably after patch "tracing: Rewrite
632   // filter logic to be simpler and faster".
633   if (auto version = GetKernelVersion(); version && version.value() >= std::make_pair(4, 19)) {
634     use_quote = true;
635   }
636 
637   FieldNameSet used_fields;
638   auto adjusted_filter = AdjustTracepointFilter(filter, use_quote, &used_fields);
639   if (!adjusted_filter) {
640     return false;
641   }
642 
643   // 3. Check if used fields are available in the tracepoint event.
644   auto& event_type = selection->event_type_modifier.event_type;
645   if (auto opt_fields = GetFieldNamesForTracepointEvent(event_type); opt_fields) {
646     FieldNameSet& fields = opt_fields.value();
647     for (const auto& field : used_fields) {
648       if (fields.find(field) == fields.end()) {
649         LOG(ERROR) << "field name " << field << " used in \"" << filter << "\" doesn't exist in "
650                    << event_type.name << ". Available fields are "
651                    << android::base::Join(fields, ",");
652         return false;
653       }
654     }
655   }
656 
657   // 4. Connect the filter to the event.
658   selection->tracepoint_filter = adjusted_filter.value();
659   return true;
660 }
661 
OpenEventFilesOnGroup(EventSelectionGroup & group,pid_t tid,int cpu,std::string * failed_event_type)662 bool EventSelectionSet::OpenEventFilesOnGroup(EventSelectionGroup& group, pid_t tid, int cpu,
663                                               std::string* failed_event_type) {
664   std::vector<std::unique_ptr<EventFd>> event_fds;
665   // Given a tid and cpu, events on the same group should be all opened
666   // successfully or all failed to open.
667   EventFd* group_fd = nullptr;
668   for (auto& selection : group.selections) {
669     std::unique_ptr<EventFd> event_fd = EventFd::OpenEventFile(
670         selection.event_attr, tid, cpu, group_fd, selection.event_type_modifier.name, false);
671     if (!event_fd) {
672       *failed_event_type = selection.event_type_modifier.name;
673       return false;
674     }
675     LOG(VERBOSE) << "OpenEventFile for " << event_fd->Name();
676     event_fds.emplace_back(std::move(event_fd));
677     if (group_fd == nullptr) {
678       group_fd = event_fds.back().get();
679     }
680   }
681   for (size_t i = 0; i < group.selections.size(); ++i) {
682     group.selections[i].event_fds.emplace_back(std::move(event_fds[i]));
683   }
684   return true;
685 }
686 
PrepareThreads(const std::set<pid_t> & processes,const std::set<pid_t> & threads)687 static std::set<pid_t> PrepareThreads(const std::set<pid_t>& processes,
688                                       const std::set<pid_t>& threads) {
689   std::set<pid_t> result = threads;
690   for (auto& pid : processes) {
691     std::vector<pid_t> tids = GetThreadsInProcess(pid);
692     result.insert(tids.begin(), tids.end());
693   }
694   return result;
695 }
696 
OpenEventFiles()697 bool EventSelectionSet::OpenEventFiles() {
698   std::vector<int> online_cpus = GetOnlineCpus();
699 
700   auto check_if_cpus_online = [&](const std::vector<int>& cpus) {
701     if (cpus.size() == 1 && cpus[0] == -1) {
702       return true;
703     }
704     for (int cpu : cpus) {
705       if (std::find(online_cpus.begin(), online_cpus.end(), cpu) == online_cpus.end()) {
706         LOG(ERROR) << "cpu " << cpu << " is not online.";
707         return false;
708       }
709     }
710     return true;
711   };
712 
713   std::set<pid_t> threads = PrepareThreads(processes_, threads_);
714   for (auto& group : groups_) {
715     const std::vector<int>* pcpus = &group.cpus;
716     if (!group.selections[0].allowed_cpus.empty()) {
717       // override cpu list if event's PMU has a cpumask as those PMUs are
718       // agnostic to cpu and it's meaningless to specify cpus for them.
719       pcpus = &group.selections[0].allowed_cpus;
720     }
721     if (pcpus->empty()) {
722       pcpus = &online_cpus;
723     } else if (!check_if_cpus_online(*pcpus)) {
724       return false;
725     }
726 
727     size_t success_count = 0;
728     std::string failed_event_type;
729     for (const auto tid : threads) {
730       for (const auto& cpu : *pcpus) {
731         if (OpenEventFilesOnGroup(group, tid, cpu, &failed_event_type)) {
732           success_count++;
733         }
734       }
735     }
736     // We can't guarantee to open perf event file successfully for each thread on each cpu.
737     // Because threads may exit between PrepareThreads() and OpenEventFilesOnGroup(), and
738     // cpus may be offlined between GetOnlineCpus() and OpenEventFilesOnGroup().
739     // So we only check that we can at least monitor one thread for each event group.
740     if (success_count == 0) {
741       int error_number = errno;
742       PLOG(ERROR) << "failed to open perf event file for event_type " << failed_event_type;
743       if (error_number == EMFILE) {
744         LOG(ERROR) << "Please increase hard limit of open file numbers.";
745       }
746       return false;
747     }
748   }
749   return ApplyFilters();
750 }
751 
ApplyFilters()752 bool EventSelectionSet::ApplyFilters() {
753   return ApplyAddrFilters() && ApplyTracepointFilters();
754 }
755 
ApplyAddrFilters()756 bool EventSelectionSet::ApplyAddrFilters() {
757   if (addr_filters_.empty()) {
758     return true;
759   }
760   if (!has_aux_trace_) {
761     LOG(ERROR) << "addr filters only take effect in cs-etm instruction tracing";
762     return false;
763   }
764 
765   // Check filter count limit.
766   size_t required_etm_filter_count = 0;
767   for (auto& filter : addr_filters_) {
768     // A range filter needs two etm filters.
769     required_etm_filter_count +=
770         (filter.type == AddrFilter::FILE_RANGE || filter.type == AddrFilter::KERNEL_RANGE) ? 2 : 1;
771   }
772   size_t etm_filter_count = ETMRecorder::GetInstance().GetAddrFilterPairs() * 2;
773   if (etm_filter_count < required_etm_filter_count) {
774     LOG(ERROR) << "needed " << required_etm_filter_count << " etm filters, but only "
775                << etm_filter_count << " filters are available.";
776     return false;
777   }
778 
779   std::string filter_str;
780   for (auto& filter : addr_filters_) {
781     if (!filter_str.empty()) {
782       filter_str += ',';
783     }
784     filter_str += filter.ToString();
785   }
786 
787   for (auto& group : groups_) {
788     for (auto& selection : group.selections) {
789       if (IsEtmEventType(selection.event_type_modifier.event_type.type)) {
790         for (auto& event_fd : selection.event_fds) {
791           if (!event_fd->SetFilter(filter_str)) {
792             return false;
793           }
794         }
795       }
796     }
797   }
798   return true;
799 }
800 
ApplyTracepointFilters()801 bool EventSelectionSet::ApplyTracepointFilters() {
802   for (auto& group : groups_) {
803     for (auto& selection : group.selections) {
804       if (!selection.tracepoint_filter.empty()) {
805         for (auto& event_fd : selection.event_fds) {
806           if (!event_fd->SetFilter(selection.tracepoint_filter)) {
807             return false;
808           }
809         }
810       }
811     }
812   }
813   return true;
814 }
815 
ReadCounter(EventFd * event_fd,CounterInfo * counter)816 static bool ReadCounter(EventFd* event_fd, CounterInfo* counter) {
817   if (!event_fd->ReadCounter(&counter->counter)) {
818     return false;
819   }
820   counter->tid = event_fd->ThreadId();
821   counter->cpu = event_fd->Cpu();
822   return true;
823 }
824 
ReadCounters(std::vector<CountersInfo> * counters)825 bool EventSelectionSet::ReadCounters(std::vector<CountersInfo>* counters) {
826   counters->clear();
827   for (size_t i = 0; i < groups_.size(); ++i) {
828     for (auto& selection : groups_[i].selections) {
829       CountersInfo counters_info;
830       counters_info.group_id = i;
831       counters_info.event_name = selection.event_type_modifier.event_type.name;
832       counters_info.event_modifier = selection.event_type_modifier.modifier;
833       counters_info.counters = selection.hotplugged_counters;
834       for (auto& event_fd : selection.event_fds) {
835         CounterInfo counter;
836         if (!ReadCounter(event_fd.get(), &counter)) {
837           return false;
838         }
839         counters_info.counters.push_back(counter);
840       }
841       counters->push_back(counters_info);
842     }
843   }
844   return true;
845 }
846 
MmapEventFiles(size_t min_mmap_pages,size_t max_mmap_pages,size_t aux_buffer_size,size_t record_buffer_size,bool allow_truncating_samples,bool exclude_perf)847 bool EventSelectionSet::MmapEventFiles(size_t min_mmap_pages, size_t max_mmap_pages,
848                                        size_t aux_buffer_size, size_t record_buffer_size,
849                                        bool allow_truncating_samples, bool exclude_perf) {
850   record_read_thread_.reset(new simpleperf::RecordReadThread(
851       record_buffer_size, groups_[0].selections[0].event_attr, min_mmap_pages, max_mmap_pages,
852       aux_buffer_size, allow_truncating_samples, exclude_perf));
853   return true;
854 }
855 
PrepareToReadMmapEventData(const std::function<bool (Record *)> & callback)856 bool EventSelectionSet::PrepareToReadMmapEventData(const std::function<bool(Record*)>& callback) {
857   // Prepare record callback function.
858   record_callback_ = callback;
859   if (!record_read_thread_->RegisterDataCallback(*loop_,
860                                                  [this]() { return ReadMmapEventData(true); })) {
861     return false;
862   }
863   std::vector<EventFd*> event_fds;
864   for (auto& group : groups_) {
865     for (auto& selection : group.selections) {
866       for (auto& event_fd : selection.event_fds) {
867         event_fds.push_back(event_fd.get());
868       }
869     }
870   }
871   return record_read_thread_->AddEventFds(event_fds);
872 }
873 
SyncKernelBuffer()874 bool EventSelectionSet::SyncKernelBuffer() {
875   return record_read_thread_->SyncKernelBuffer();
876 }
877 
878 // Read records from the RecordBuffer. If with_time_limit is false, read until the RecordBuffer is
879 // empty, otherwise stop after 100 ms or when the record buffer is empty.
ReadMmapEventData(bool with_time_limit)880 bool EventSelectionSet::ReadMmapEventData(bool with_time_limit) {
881   uint64_t start_time_in_ns;
882   if (with_time_limit) {
883     start_time_in_ns = GetSystemClock();
884   }
885   std::unique_ptr<Record> r;
886   while ((r = record_read_thread_->GetRecord()) != nullptr) {
887     if (!record_callback_(r.get())) {
888       return false;
889     }
890     if (with_time_limit && (GetSystemClock() - start_time_in_ns) >= 1e8) {
891       break;
892     }
893   }
894   return true;
895 }
896 
FinishReadMmapEventData()897 bool EventSelectionSet::FinishReadMmapEventData() {
898   return ReadMmapEventData(false);
899 }
900 
CloseEventFiles()901 void EventSelectionSet::CloseEventFiles() {
902   if (record_read_thread_) {
903     record_read_thread_->StopReadThread();
904   }
905   for (auto& group : groups_) {
906     for (auto& event : group.selections) {
907       event.event_fds.clear();
908     }
909   }
910 }
911 
StopWhenNoMoreTargets(double check_interval_in_sec)912 bool EventSelectionSet::StopWhenNoMoreTargets(double check_interval_in_sec) {
913   return loop_->AddPeriodicEvent(SecondToTimeval(check_interval_in_sec),
914                                  [&]() { return CheckMonitoredTargets(); });
915 }
916 
CheckMonitoredTargets()917 bool EventSelectionSet::CheckMonitoredTargets() {
918   if (!HasSampler()) {
919     return loop_->ExitLoop();
920   }
921   for (const auto& tid : threads_) {
922     if (IsThreadAlive(tid)) {
923       return true;
924     }
925   }
926   for (const auto& pid : processes_) {
927     if (IsThreadAlive(pid)) {
928       return true;
929     }
930   }
931   return loop_->ExitLoop();
932 }
933 
HasSampler()934 bool EventSelectionSet::HasSampler() {
935   for (auto& group : groups_) {
936     for (auto& sel : group.selections) {
937       if (!sel.event_fds.empty()) {
938         return true;
939       }
940     }
941   }
942   return false;
943 }
944 
SetEnableEvents(bool enable)945 bool EventSelectionSet::SetEnableEvents(bool enable) {
946   for (auto& group : groups_) {
947     for (auto& sel : group.selections) {
948       for (auto& fd : sel.event_fds) {
949         if (!fd->SetEnableEvent(enable)) {
950           return false;
951         }
952       }
953     }
954   }
955   return true;
956 }
957 
EnableETMEvents()958 bool EventSelectionSet::EnableETMEvents() {
959   for (auto& group : groups_) {
960     for (auto& sel : group.selections) {
961       if (!sel.event_type_modifier.event_type.IsEtmEvent()) {
962         continue;
963       }
964       for (auto& fd : sel.event_fds) {
965         if (!fd->SetEnableEvent(true)) {
966           return false;
967         }
968       }
969     }
970   }
971   return true;
972 }
973 
DisableETMEvents()974 bool EventSelectionSet::DisableETMEvents() {
975   for (auto& group : groups_) {
976     for (auto& sel : group.selections) {
977       if (!sel.event_type_modifier.event_type.IsEtmEvent()) {
978         continue;
979       }
980       // When using ETR, ETM data is flushed to the aux buffer of the last cpu disabling ETM events.
981       // To avoid overflowing the aux buffer for one cpu, rotate the last cpu disabling ETM events.
982       if (etm_event_cpus_.empty()) {
983         for (const auto& fd : sel.event_fds) {
984           etm_event_cpus_.insert(fd->Cpu());
985         }
986         if (etm_event_cpus_.empty()) {
987           continue;
988         }
989         etm_event_cpus_it_ = etm_event_cpus_.begin();
990       }
991       int last_disabled_cpu = *etm_event_cpus_it_;
992       if (++etm_event_cpus_it_ == etm_event_cpus_.end()) {
993         etm_event_cpus_it_ = etm_event_cpus_.begin();
994       }
995 
996       for (auto& fd : sel.event_fds) {
997         if (fd->Cpu() != last_disabled_cpu) {
998           if (!fd->SetEnableEvent(false)) {
999             return false;
1000           }
1001         }
1002       }
1003       for (auto& fd : sel.event_fds) {
1004         if (fd->Cpu() == last_disabled_cpu) {
1005           if (!fd->SetEnableEvent(false)) {
1006             return false;
1007           }
1008         }
1009       }
1010     }
1011   }
1012   return true;
1013 }
1014 
1015 }  // namespace simpleperf
1016