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