• 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("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