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