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 
23 #include <android-base/logging.h>
24 
25 #include "environment.h"
26 #include "ETMRecorder.h"
27 #include "event_attr.h"
28 #include "event_type.h"
29 #include "IOEventLoop.h"
30 #include "perf_regs.h"
31 #include "utils.h"
32 #include "RecordReadThread.h"
33 
34 using namespace simpleperf;
35 
IsBranchSamplingSupported()36 bool IsBranchSamplingSupported() {
37   const EventType* type = FindEventTypeByName("cpu-cycles");
38   if (type == nullptr) {
39     return false;
40   }
41   perf_event_attr attr = CreateDefaultPerfEventAttr(*type);
42   attr.sample_type |= PERF_SAMPLE_BRANCH_STACK;
43   attr.branch_sample_type = PERF_SAMPLE_BRANCH_ANY;
44   return IsEventAttrSupported(attr);
45 }
46 
IsDwarfCallChainSamplingSupported()47 bool IsDwarfCallChainSamplingSupported() {
48   const EventType* type = FindEventTypeByName("cpu-cycles");
49   if (type == nullptr) {
50     return false;
51   }
52   perf_event_attr attr = CreateDefaultPerfEventAttr(*type);
53   attr.sample_type |=
54       PERF_SAMPLE_CALLCHAIN | PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER;
55   attr.exclude_callchain_user = 1;
56   attr.sample_regs_user = GetSupportedRegMask(GetBuildArch());
57   attr.sample_stack_user = 8192;
58   return IsEventAttrSupported(attr);
59 }
60 
IsDumpingRegsForTracepointEventsSupported()61 bool IsDumpingRegsForTracepointEventsSupported() {
62   const EventType* event_type = FindEventTypeByName("sched:sched_switch", false);
63   if (event_type == nullptr) {
64     return false;
65   }
66   std::atomic<bool> done(false);
67   std::atomic<pid_t> thread_id(0);
68   std::thread thread([&]() {
69     thread_id = gettid();
70     while (!done) {
71       usleep(1);
72     }
73     usleep(1);  // Make a sched out to generate one sample.
74   });
75   while (thread_id == 0) {
76     usleep(1);
77   }
78   perf_event_attr attr = CreateDefaultPerfEventAttr(*event_type);
79   attr.freq = 0;
80   attr.sample_period = 1;
81   std::unique_ptr<EventFd> event_fd =
82       EventFd::OpenEventFile(attr, thread_id, -1, nullptr);
83   if (event_fd == nullptr) {
84     return false;
85   }
86   if (!event_fd->CreateMappedBuffer(4, true)) {
87     return false;
88   }
89   done = true;
90   thread.join();
91 
92   std::vector<char> buffer = event_fd->GetAvailableMmapData();
93   std::vector<std::unique_ptr<Record>> records =
94       ReadRecordsFromBuffer(attr, buffer.data(), buffer.size());
95   for (auto& r : records) {
96     if (r->type() == PERF_RECORD_SAMPLE) {
97       auto& record = *static_cast<SampleRecord*>(r.get());
98       if (record.ip_data.ip != 0) {
99         return true;
100       }
101     }
102   }
103   return false;
104 }
105 
IsSettingClockIdSupported()106 bool IsSettingClockIdSupported() {
107   // Do the real check only once and keep the result in a static variable.
108   static int is_supported = -1;
109   if (is_supported == -1) {
110     const EventType* type = FindEventTypeByName("cpu-cycles");
111     if (type == nullptr) {
112       is_supported = 0;
113     } else {
114       // Check if the kernel supports setting clockid, which was added in kernel 4.0. Just check
115       // with one clockid is enough. Because all needed clockids were supported before kernel 4.0.
116       perf_event_attr attr = CreateDefaultPerfEventAttr(*type);
117       attr.use_clockid = 1;
118       attr.clockid = CLOCK_MONOTONIC;
119       is_supported = IsEventAttrSupported(attr) ? 1 : 0;
120     }
121   }
122   return is_supported;
123 }
124 
IsMmap2Supported()125 bool IsMmap2Supported() {
126   const EventType* type = FindEventTypeByName("cpu-cycles");
127   if (type == nullptr) {
128     return false;
129   }
130   perf_event_attr attr = CreateDefaultPerfEventAttr(*type);
131   attr.mmap2 = 1;
132   return IsEventAttrSupported(attr);
133 }
134 
EventSelectionSet(bool for_stat_cmd)135 EventSelectionSet::EventSelectionSet(bool for_stat_cmd)
136     : for_stat_cmd_(for_stat_cmd), loop_(new IOEventLoop) {}
137 
~EventSelectionSet()138 EventSelectionSet::~EventSelectionSet() {}
139 
BuildAndCheckEventSelection(const std::string & event_name,bool first_event,EventSelection * selection)140 bool EventSelectionSet::BuildAndCheckEventSelection(const std::string& event_name, bool first_event,
141                                                     EventSelection* selection) {
142   std::unique_ptr<EventTypeAndModifier> event_type = ParseEventType(event_name);
143   if (event_type == nullptr) {
144     return false;
145   }
146   if (for_stat_cmd_) {
147     if (event_type->event_type.name == "cpu-clock" ||
148         event_type->event_type.name == "task-clock") {
149       if (event_type->exclude_user || event_type->exclude_kernel) {
150         LOG(ERROR) << "Modifier u and modifier k used in event type "
151                    << event_type->event_type.name
152                    << " are not supported by the kernel.";
153         return false;
154       }
155     }
156   }
157   selection->event_type_modifier = *event_type;
158   selection->event_attr = CreateDefaultPerfEventAttr(event_type->event_type);
159   selection->event_attr.exclude_user = event_type->exclude_user;
160   selection->event_attr.exclude_kernel = event_type->exclude_kernel;
161   selection->event_attr.exclude_hv = event_type->exclude_hv;
162   selection->event_attr.exclude_host = event_type->exclude_host;
163   selection->event_attr.exclude_guest = event_type->exclude_guest;
164   selection->event_attr.precise_ip = event_type->precise_ip;
165   if (IsEtmEventType(event_type->event_type.type)) {
166     auto& etm_recorder = ETMRecorder::GetInstance();
167     if (!etm_recorder.CheckEtmSupport()) {
168       return false;
169     }
170     ETMRecorder::GetInstance().SetEtmPerfEventAttr(&selection->event_attr);
171   }
172   bool set_default_sample_freq = false;
173   if (!for_stat_cmd_) {
174     if (event_type->event_type.type == PERF_TYPE_TRACEPOINT) {
175       selection->event_attr.freq = 0;
176       selection->event_attr.sample_period = DEFAULT_SAMPLE_PERIOD_FOR_TRACEPOINT_EVENT;
177     } else {
178       selection->event_attr.freq = 1;
179       // Set default sample freq here may print msg "Adjust sample freq to max allowed sample
180       // freq". But this is misleading. Because default sample freq may not be the final sample
181       // freq we use. So use minimum sample freq (1) here.
182       selection->event_attr.sample_freq = 1;
183       set_default_sample_freq = true;
184     }
185     // We only need to dump mmap and comm records for the first event type. Because all event types
186     // are monitoring the same processes.
187     if (first_event) {
188       selection->event_attr.mmap = 1;
189       selection->event_attr.comm = 1;
190       if (IsMmap2Supported()) {
191         selection->event_attr.mmap2 = 1;
192       }
193     }
194   }
195   if (!IsEventAttrSupported(selection->event_attr)) {
196     LOG(ERROR) << "Event type '" << event_type->name
197                << "' is not supported on the device";
198     return false;
199   }
200   if (set_default_sample_freq) {
201     selection->event_attr.sample_freq = DEFAULT_SAMPLE_FREQ_FOR_NONTRACEPOINT_EVENT;
202   }
203 
204   selection->event_fds.clear();
205 
206   for (const auto& group : groups_) {
207     for (const auto& sel : group) {
208       if (sel.event_type_modifier.name == selection->event_type_modifier.name) {
209         LOG(ERROR) << "Event type '" << sel.event_type_modifier.name
210                    << "' appears more than once";
211         return false;
212       }
213     }
214   }
215   return true;
216 }
217 
AddEventType(const std::string & event_name,size_t * group_id)218 bool EventSelectionSet::AddEventType(const std::string& event_name, size_t* group_id) {
219   return AddEventGroup(std::vector<std::string>(1, event_name), group_id);
220 }
221 
AddEventGroup(const std::vector<std::string> & event_names,size_t * group_id)222 bool EventSelectionSet::AddEventGroup(
223     const std::vector<std::string>& event_names, size_t* group_id) {
224   EventSelectionGroup group;
225   bool first_event = groups_.empty();
226   for (const auto& event_name : event_names) {
227     EventSelection selection;
228     if (!BuildAndCheckEventSelection(event_name, first_event, &selection)) {
229       return false;
230     }
231     if (IsEtmEventType(selection.event_attr.type)) {
232       has_aux_trace_ = true;
233     }
234     first_event = false;
235     group.push_back(std::move(selection));
236   }
237   groups_.push_back(std::move(group));
238   UnionSampleType();
239   if (group_id != nullptr) {
240     *group_id = groups_.size() - 1;
241   }
242   return true;
243 }
244 
GetEvents() const245 std::vector<const EventType*> EventSelectionSet::GetEvents() const {
246   std::vector<const EventType*> result;
247   for (const auto& group : groups_) {
248     for (const auto& selection : group) {
249       result.push_back(&selection.event_type_modifier.event_type);
250     }
251   }
252   return result;
253 }
254 
GetTracepointEvents() const255 std::vector<const EventType*> EventSelectionSet::GetTracepointEvents() const {
256   std::vector<const EventType*> result;
257   for (const auto& group : groups_) {
258     for (const auto& selection : group) {
259       if (selection.event_type_modifier.event_type.type ==
260           PERF_TYPE_TRACEPOINT) {
261         result.push_back(&selection.event_type_modifier.event_type);
262       }
263     }
264   }
265   return result;
266 }
267 
ExcludeKernel() const268 bool EventSelectionSet::ExcludeKernel() const {
269   for (const auto& group : groups_) {
270     for (const auto& selection : group) {
271       if (!selection.event_type_modifier.exclude_kernel) {
272         return false;
273       }
274     }
275   }
276   return true;
277 }
278 
HasInplaceSampler() const279 bool EventSelectionSet::HasInplaceSampler() const {
280   for (const auto& group : groups_) {
281     for (const auto& sel : group) {
282       if (sel.event_attr.type == SIMPLEPERF_TYPE_USER_SPACE_SAMPLERS &&
283           sel.event_attr.config == SIMPLEPERF_CONFIG_INPLACE_SAMPLER) {
284         return true;
285       }
286     }
287   }
288   return false;
289 }
290 
GetEventAttrWithId() const291 std::vector<EventAttrWithId> EventSelectionSet::GetEventAttrWithId() const {
292   std::vector<EventAttrWithId> result;
293   for (const auto& group : groups_) {
294     for (const auto& selection : group) {
295       EventAttrWithId attr_id;
296       attr_id.attr = &selection.event_attr;
297       for (const auto& fd : selection.event_fds) {
298         attr_id.ids.push_back(fd->Id());
299       }
300       if (!selection.inplace_samplers.empty()) {
301         attr_id.ids.push_back(selection.inplace_samplers[0]->Id());
302       }
303       result.push_back(attr_id);
304     }
305   }
306   return result;
307 }
308 
309 // Union the sample type of different event attrs can make reading sample
310 // records in perf.data easier.
UnionSampleType()311 void EventSelectionSet::UnionSampleType() {
312   uint64_t sample_type = 0;
313   for (const auto& group : groups_) {
314     for (const auto& selection : group) {
315       sample_type |= selection.event_attr.sample_type;
316     }
317   }
318   for (auto& group : groups_) {
319     for (auto& selection : group) {
320       selection.event_attr.sample_type = sample_type;
321     }
322   }
323 }
324 
SetEnableOnExec(bool enable)325 void EventSelectionSet::SetEnableOnExec(bool enable) {
326   for (auto& group : groups_) {
327     for (auto& selection : group) {
328       // If sampling is enabled on exec, then it is disabled at startup,
329       // otherwise it should be enabled at startup. Don't use
330       // ioctl(PERF_EVENT_IOC_ENABLE) to enable it after perf_event_open().
331       // Because some android kernels can't handle ioctl() well when cpu-hotplug
332       // happens. See http://b/25193162.
333       if (enable) {
334         selection.event_attr.enable_on_exec = 1;
335         selection.event_attr.disabled = 1;
336       } else {
337         selection.event_attr.enable_on_exec = 0;
338         selection.event_attr.disabled = 0;
339       }
340     }
341   }
342 }
343 
GetEnableOnExec()344 bool EventSelectionSet::GetEnableOnExec() {
345   for (const auto& group : groups_) {
346     for (const auto& selection : group) {
347       if (selection.event_attr.enable_on_exec == 0) {
348         return false;
349       }
350     }
351   }
352   return true;
353 }
354 
SampleIdAll()355 void EventSelectionSet::SampleIdAll() {
356   for (auto& group : groups_) {
357     for (auto& selection : group) {
358       selection.event_attr.sample_id_all = 1;
359     }
360   }
361 }
362 
SetSampleSpeed(size_t group_id,const SampleSpeed & speed)363 void EventSelectionSet::SetSampleSpeed(size_t group_id, const SampleSpeed& speed) {
364   CHECK_LT(group_id, groups_.size());
365   for (auto& selection : groups_[group_id]) {
366     if (speed.UseFreq()) {
367       selection.event_attr.freq = 1;
368       selection.event_attr.sample_freq = speed.sample_freq;
369     } else {
370       selection.event_attr.freq = 0;
371       selection.event_attr.sample_period = speed.sample_period;
372     }
373   }
374 }
375 
SetBranchSampling(uint64_t branch_sample_type)376 bool EventSelectionSet::SetBranchSampling(uint64_t branch_sample_type) {
377   if (branch_sample_type != 0 &&
378       (branch_sample_type &
379        (PERF_SAMPLE_BRANCH_ANY | PERF_SAMPLE_BRANCH_ANY_CALL |
380         PERF_SAMPLE_BRANCH_ANY_RETURN | PERF_SAMPLE_BRANCH_IND_CALL)) == 0) {
381     LOG(ERROR) << "Invalid branch_sample_type: 0x" << std::hex
382                << branch_sample_type;
383     return false;
384   }
385   if (branch_sample_type != 0 && !IsBranchSamplingSupported()) {
386     LOG(ERROR) << "branch stack sampling is not supported on this device.";
387     return false;
388   }
389   for (auto& group : groups_) {
390     for (auto& selection : group) {
391       perf_event_attr& attr = selection.event_attr;
392       if (branch_sample_type != 0) {
393         attr.sample_type |= PERF_SAMPLE_BRANCH_STACK;
394       } else {
395         attr.sample_type &= ~PERF_SAMPLE_BRANCH_STACK;
396       }
397       attr.branch_sample_type = branch_sample_type;
398     }
399   }
400   return true;
401 }
402 
EnableFpCallChainSampling()403 void EventSelectionSet::EnableFpCallChainSampling() {
404   for (auto& group : groups_) {
405     for (auto& selection : group) {
406       selection.event_attr.sample_type |= PERF_SAMPLE_CALLCHAIN;
407     }
408   }
409 }
410 
EnableDwarfCallChainSampling(uint32_t dump_stack_size)411 bool EventSelectionSet::EnableDwarfCallChainSampling(uint32_t dump_stack_size) {
412   if (!IsDwarfCallChainSamplingSupported()) {
413     LOG(ERROR) << "dwarf callchain sampling is not supported on this device.";
414     return false;
415   }
416   for (auto& group : groups_) {
417     for (auto& selection : group) {
418       selection.event_attr.sample_type |= PERF_SAMPLE_CALLCHAIN |
419                                           PERF_SAMPLE_REGS_USER |
420                                           PERF_SAMPLE_STACK_USER;
421       selection.event_attr.exclude_callchain_user = 1;
422       selection.event_attr.sample_regs_user =
423           GetSupportedRegMask(GetMachineArch());
424       selection.event_attr.sample_stack_user = dump_stack_size;
425     }
426   }
427   return true;
428 }
429 
SetInherit(bool enable)430 void EventSelectionSet::SetInherit(bool enable) {
431   for (auto& group : groups_) {
432     for (auto& selection : group) {
433       selection.event_attr.inherit = (enable ? 1 : 0);
434     }
435   }
436 }
437 
SetClockId(int clock_id)438 void EventSelectionSet::SetClockId(int clock_id) {
439   for (auto& group : groups_) {
440     for (auto& selection : group) {
441       selection.event_attr.use_clockid = 1;
442       selection.event_attr.clockid = clock_id;
443     }
444   }
445 }
446 
NeedKernelSymbol() const447 bool EventSelectionSet::NeedKernelSymbol() const {
448   for (const auto& group : groups_) {
449     for (const auto& selection : group) {
450       if (!selection.event_type_modifier.exclude_kernel) {
451         return true;
452       }
453     }
454   }
455   return false;
456 }
457 
SetRecordNotExecutableMaps(bool record)458 void EventSelectionSet::SetRecordNotExecutableMaps(bool record) {
459   // We only need to dump non-executable mmap records for the first event type.
460   groups_[0][0].event_attr.mmap_data = record ? 1 : 0;
461 }
462 
RecordNotExecutableMaps() const463 bool EventSelectionSet::RecordNotExecutableMaps() const {
464   return groups_[0][0].event_attr.mmap_data == 1;
465 }
466 
CheckIfCpusOnline(const std::vector<int> & cpus)467 static bool CheckIfCpusOnline(const std::vector<int>& cpus) {
468   std::vector<int> online_cpus = GetOnlineCpus();
469   for (const auto& cpu : cpus) {
470     if (std::find(online_cpus.begin(), online_cpus.end(), cpu) ==
471         online_cpus.end()) {
472       LOG(ERROR) << "cpu " << cpu << " is not online.";
473       return false;
474     }
475   }
476   return true;
477 }
478 
OpenEventFilesOnGroup(EventSelectionGroup & group,pid_t tid,int cpu,std::string * failed_event_type)479 bool EventSelectionSet::OpenEventFilesOnGroup(EventSelectionGroup& group,
480                                               pid_t tid, int cpu,
481                                               std::string* failed_event_type) {
482   std::vector<std::unique_ptr<EventFd>> event_fds;
483   // Given a tid and cpu, events on the same group should be all opened
484   // successfully or all failed to open.
485   EventFd* group_fd = nullptr;
486   for (auto& selection : group) {
487     std::unique_ptr<EventFd> event_fd =
488         EventFd::OpenEventFile(selection.event_attr, tid, cpu, group_fd, false);
489     if (!event_fd) {
490         *failed_event_type = selection.event_type_modifier.name;
491         return false;
492     }
493     LOG(VERBOSE) << "OpenEventFile for " << event_fd->Name();
494     event_fds.push_back(std::move(event_fd));
495     if (group_fd == nullptr) {
496       group_fd = event_fds.back().get();
497     }
498   }
499   for (size_t i = 0; i < group.size(); ++i) {
500     group[i].event_fds.push_back(std::move(event_fds[i]));
501   }
502   return true;
503 }
504 
PrepareThreads(const std::set<pid_t> & processes,const std::set<pid_t> & threads)505 static std::map<pid_t, std::set<pid_t>> PrepareThreads(const std::set<pid_t>& processes,
506                                                        const std::set<pid_t>& threads) {
507   std::map<pid_t, std::set<pid_t>> result;
508   for (auto& pid : processes) {
509     std::vector<pid_t> tids = GetThreadsInProcess(pid);
510     std::set<pid_t>& threads_in_process = result[pid];
511     threads_in_process.insert(tids.begin(), tids.end());
512   }
513   for (auto& tid : threads) {
514     // tid = -1 means monitoring all threads.
515     if (tid == -1) {
516       result[-1].insert(-1);
517     } else {
518       pid_t pid;
519       if (GetProcessForThread(tid, &pid)) {
520         result[pid].insert(tid);
521       }
522     }
523   }
524   return result;
525 }
526 
OpenEventFiles(const std::vector<int> & on_cpus)527 bool EventSelectionSet::OpenEventFiles(const std::vector<int>& on_cpus) {
528   std::vector<int> cpus = on_cpus;
529   if (!cpus.empty()) {
530     // cpus = {-1} means open an event file for all cpus.
531     if (!(cpus.size() == 1 && cpus[0] == -1) && !CheckIfCpusOnline(cpus)) {
532       return false;
533     }
534   } else {
535     cpus = GetOnlineCpus();
536   }
537   std::map<pid_t, std::set<pid_t>> process_map = PrepareThreads(processes_, threads_);
538   for (auto& group : groups_) {
539     if (IsUserSpaceSamplerGroup(group)) {
540       if (!OpenUserSpaceSamplersOnGroup(group, process_map)) {
541         return false;
542       }
543     } else {
544       for (const auto& pair : process_map) {
545         size_t success_count = 0;
546         std::string failed_event_type;
547         for (const auto& tid : pair.second) {
548           for (const auto& cpu : cpus) {
549             if (OpenEventFilesOnGroup(group, tid, cpu, &failed_event_type)) {
550               success_count++;
551             }
552           }
553         }
554         // We can't guarantee to open perf event file successfully for each thread on each cpu.
555         // Because threads may exit between PrepareThreads() and OpenEventFilesOnGroup(), and
556         // cpus may be offlined between GetOnlineCpus() and OpenEventFilesOnGroup().
557         // So we only check that we can at least monitor one thread for each process.
558         if (success_count == 0) {
559           PLOG(ERROR) << "failed to open perf event file for event_type "
560                       << failed_event_type << " for "
561                       << (pair.first == -1 ? "all threads"
562                                            : "threads in process " + std::to_string(pair.first));
563           return false;
564         }
565       }
566     }
567   }
568   return ApplyFilters();
569 }
570 
IsUserSpaceSamplerGroup(EventSelectionGroup & group)571 bool EventSelectionSet::IsUserSpaceSamplerGroup(EventSelectionGroup& group) {
572   return group.size() == 1 && group[0].event_attr.type == SIMPLEPERF_TYPE_USER_SPACE_SAMPLERS;
573 }
574 
OpenUserSpaceSamplersOnGroup(EventSelectionGroup & group,const std::map<pid_t,std::set<pid_t>> & process_map)575 bool EventSelectionSet::OpenUserSpaceSamplersOnGroup(EventSelectionGroup& group,
576     const std::map<pid_t, std::set<pid_t>>& process_map) {
577   CHECK_EQ(group.size(), 1u);
578   for (auto& selection : group) {
579     if (selection.event_attr.type == SIMPLEPERF_TYPE_USER_SPACE_SAMPLERS &&
580         selection.event_attr.config == SIMPLEPERF_CONFIG_INPLACE_SAMPLER) {
581       for (auto& pair : process_map) {
582         std::unique_ptr<InplaceSamplerClient> sampler = InplaceSamplerClient::Create(
583             selection.event_attr, pair.first, pair.second);
584         if (sampler == nullptr) {
585           return false;
586         }
587         selection.inplace_samplers.push_back(std::move(sampler));
588       }
589     }
590   }
591   return true;
592 }
593 
ApplyFilters()594 bool EventSelectionSet::ApplyFilters() {
595   if (include_filters_.empty()) {
596     return true;
597   }
598   if (!has_aux_trace_) {
599     LOG(ERROR) << "include filters only take effect in cs-etm instruction tracing";
600     return false;
601   }
602   size_t supported_pairs = ETMRecorder::GetInstance().GetAddrFilterPairs();
603   if (supported_pairs < include_filters_.size()) {
604     LOG(ERROR) << "filter binary count is " << include_filters_.size()
605                << ", bigger than maximum supported filters on device, which is " << supported_pairs;
606     return false;
607   }
608   std::string filter_str;
609   for (auto& binary : include_filters_) {
610     std::string path;
611     if (!android::base::Realpath(binary, &path)) {
612       PLOG(ERROR) << "failed to find include filter binary: " << binary;
613       return false;
614     }
615     uint64_t file_size = GetFileSize(path);
616     if (!filter_str.empty()) {
617       filter_str += ',';
618     }
619     android::base::StringAppendF(&filter_str, "filter 0/%" PRIu64 "@%s", file_size, path.c_str());
620   }
621   for (auto& group : groups_) {
622     for (auto& selection : group) {
623       if (IsEtmEventType(selection.event_type_modifier.event_type.type)) {
624         for (auto& event_fd : selection.event_fds) {
625           if (!event_fd->SetFilter(filter_str)) {
626             return false;
627           }
628         }
629       }
630     }
631   }
632   return true;
633 }
634 
ReadCounter(EventFd * event_fd,CounterInfo * counter)635 static bool ReadCounter(EventFd* event_fd, CounterInfo* counter) {
636   if (!event_fd->ReadCounter(&counter->counter)) {
637     return false;
638   }
639   counter->tid = event_fd->ThreadId();
640   counter->cpu = event_fd->Cpu();
641   return true;
642 }
643 
ReadCounters(std::vector<CountersInfo> * counters)644 bool EventSelectionSet::ReadCounters(std::vector<CountersInfo>* counters) {
645   counters->clear();
646   for (size_t i = 0; i < groups_.size(); ++i) {
647     for (auto& selection : groups_[i]) {
648       CountersInfo counters_info;
649       counters_info.group_id = i;
650       counters_info.event_name = selection.event_type_modifier.event_type.name;
651       counters_info.event_modifier = selection.event_type_modifier.modifier;
652       counters_info.counters = selection.hotplugged_counters;
653       for (auto& event_fd : selection.event_fds) {
654         CounterInfo counter;
655         if (!ReadCounter(event_fd.get(), &counter)) {
656           return false;
657         }
658         counters_info.counters.push_back(counter);
659       }
660       counters->push_back(counters_info);
661     }
662   }
663   return true;
664 }
665 
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)666 bool EventSelectionSet::MmapEventFiles(size_t min_mmap_pages, size_t max_mmap_pages,
667                                        size_t aux_buffer_size, size_t record_buffer_size,
668                                        bool allow_cutting_samples) {
669   record_read_thread_.reset(
670       new simpleperf::RecordReadThread(record_buffer_size, groups_[0][0].event_attr, min_mmap_pages,
671                                        max_mmap_pages, aux_buffer_size, allow_cutting_samples));
672   return true;
673 }
674 
PrepareToReadMmapEventData(const std::function<bool (Record *)> & callback)675 bool EventSelectionSet::PrepareToReadMmapEventData(const std::function<bool(Record*)>& callback) {
676   // Prepare record callback function.
677   record_callback_ = callback;
678   if (!record_read_thread_->RegisterDataCallback(*loop_,
679                                                  [this]() { return ReadMmapEventData(true); })) {
680     return false;
681   }
682   std::vector<EventFd*> event_fds;
683   for (auto& group : groups_) {
684     for (auto& selection : group) {
685       for (auto& event_fd : selection.event_fds) {
686         event_fds.push_back(event_fd.get());
687       }
688     }
689   }
690   return record_read_thread_->AddEventFds(event_fds);
691 }
692 
SyncKernelBuffer()693 bool EventSelectionSet::SyncKernelBuffer() {
694   return record_read_thread_->SyncKernelBuffer();
695 }
696 
697 // Read records from the RecordBuffer. If with_time_limit is false, read until the RecordBuffer is
698 // empty, otherwise stop after 100 ms or when the record buffer is empty.
ReadMmapEventData(bool with_time_limit)699 bool EventSelectionSet::ReadMmapEventData(bool with_time_limit) {
700   uint64_t start_time_in_ns;
701   if (with_time_limit) {
702     start_time_in_ns = GetSystemClock();
703   }
704   std::unique_ptr<Record> r;
705   while ((r = record_read_thread_->GetRecord()) != nullptr) {
706     if (!record_callback_(r.get())) {
707       return false;
708     }
709     if (with_time_limit && (GetSystemClock() - start_time_in_ns) >= 1e8) {
710       break;
711     }
712   }
713   return true;
714 }
715 
FinishReadMmapEventData()716 bool EventSelectionSet::FinishReadMmapEventData() {
717   // Stop the read thread, so we don't get more records beyond current time.
718   if (!SyncKernelBuffer() || !record_read_thread_->StopReadThread()) {
719     return false;
720   }
721   if (!ReadMmapEventData(false)) {
722     return false;
723   }
724   if (!HasInplaceSampler()) {
725     return true;
726   }
727   // Inplace sampler server uses a buffer to cache samples before sending them, so we need to
728   // explicitly ask it to send the cached samples.
729   loop_.reset(new IOEventLoop);
730   size_t inplace_sampler_count = 0;
731   auto close_callback = [&]() {
732     if (--inplace_sampler_count == 0) {
733       return loop_->ExitLoop();
734     }
735     return true;
736   };
737   for (auto& group : groups_) {
738     for (auto& sel : group) {
739       for (auto& sampler : sel.inplace_samplers) {
740         if (!sampler->IsClosed()) {
741           if (!sampler->StopProfiling(*loop_, close_callback)) {
742             return false;
743           }
744           inplace_sampler_count++;
745         }
746       }
747     }
748   }
749   if (inplace_sampler_count == 0) {
750     return true;
751   }
752 
753   // Set a timeout to exit the loop.
754   timeval tv;
755   tv.tv_sec = 1;
756   tv.tv_usec = 0;
757   if (!loop_->AddPeriodicEvent(tv, [&]() { return loop_->ExitLoop(); })) {
758     return false;
759   }
760   return loop_->RunLoop();
761 }
762 
HandleCpuHotplugEvents(const std::vector<int> & monitored_cpus,double check_interval_in_sec)763 bool EventSelectionSet::HandleCpuHotplugEvents(const std::vector<int>& monitored_cpus,
764                                                double check_interval_in_sec) {
765   monitored_cpus_.insert(monitored_cpus.begin(), monitored_cpus.end());
766   online_cpus_ = GetOnlineCpus();
767   if (!loop_->AddPeriodicEvent(SecondToTimeval(check_interval_in_sec),
768                                [&]() { return DetectCpuHotplugEvents(); })) {
769     return false;
770   }
771   return true;
772 }
773 
DetectCpuHotplugEvents()774 bool EventSelectionSet::DetectCpuHotplugEvents() {
775   std::vector<int> new_cpus = GetOnlineCpus();
776   for (const auto& cpu : online_cpus_) {
777     if (std::find(new_cpus.begin(), new_cpus.end(), cpu) == new_cpus.end()) {
778       if (monitored_cpus_.empty() ||
779           monitored_cpus_.find(cpu) != monitored_cpus_.end()) {
780         LOG(INFO) << "Cpu " << cpu << " is offlined";
781         if (!HandleCpuOfflineEvent(cpu)) {
782           return false;
783         }
784       }
785     }
786   }
787   for (const auto& cpu : new_cpus) {
788     if (std::find(online_cpus_.begin(), online_cpus_.end(), cpu) ==
789         online_cpus_.end()) {
790       if (monitored_cpus_.empty() ||
791           monitored_cpus_.find(cpu) != monitored_cpus_.end()) {
792         LOG(INFO) << "Cpu " << cpu << " is onlined";
793         if (!HandleCpuOnlineEvent(cpu)) {
794           return false;
795         }
796       }
797     }
798   }
799   online_cpus_ = new_cpus;
800   return true;
801 }
802 
HandleCpuOfflineEvent(int cpu)803 bool EventSelectionSet::HandleCpuOfflineEvent(int cpu) {
804   if (!for_stat_cmd_) {
805     // Read mmap data here, so we won't lose the existing records of the
806     // offlined cpu.
807     if (!ReadMmapEventData(true)) {
808       return false;
809     }
810   }
811   if (record_read_thread_) {
812     std::vector<EventFd*> remove_fds;
813     for (auto& group : groups_) {
814       for (auto& selection : group) {
815         for (auto& fd : selection.event_fds) {
816           if (fd->Cpu() == cpu) {
817             remove_fds.push_back(fd.get());
818           }
819         }
820       }
821     }
822     if (!record_read_thread_->RemoveEventFds(remove_fds)) {
823       return false;
824     }
825   }
826   for (auto& group : groups_) {
827     for (auto& selection : group) {
828       for (auto it = selection.event_fds.begin(); it != selection.event_fds.end();) {
829         if ((*it)->Cpu() == cpu) {
830           if (for_stat_cmd_) {
831             CounterInfo counter;
832             if (!ReadCounter(it->get(), &counter)) {
833               return false;
834             }
835             selection.hotplugged_counters.push_back(counter);
836           }
837           it = selection.event_fds.erase(it);
838         } else {
839           ++it;
840         }
841       }
842     }
843   }
844   return true;
845 }
846 
HandleCpuOnlineEvent(int cpu)847 bool EventSelectionSet::HandleCpuOnlineEvent(int cpu) {
848   // We need to start profiling when opening new event files.
849   SetEnableOnExec(false);
850   std::map<pid_t, std::set<pid_t>> process_map = PrepareThreads(processes_, threads_);
851   for (auto& group : groups_) {
852     if (IsUserSpaceSamplerGroup(group)) {
853       continue;
854     }
855     for (const auto& pair : process_map) {
856       for (const auto& tid : pair.second) {
857         std::string failed_event_type;
858         if (!OpenEventFilesOnGroup(group, tid, cpu, &failed_event_type)) {
859           // If failed to open event files, maybe the cpu has been offlined.
860           PLOG(WARNING) << "failed to open perf event file for event_type "
861                         << failed_event_type << " for "
862                         << (tid == -1 ? "all threads" : "thread " + std::to_string(tid))
863                         << " on cpu " << cpu;
864         }
865       }
866     }
867   }
868   if (record_read_thread_) {
869     // Prepare mapped buffer.
870     if (!CreateMappedBufferForCpu(cpu)) {
871       return false;
872     }
873     // Send a EventIdRecord.
874     std::vector<uint64_t> event_id_data;
875     uint64_t attr_id = 0;
876     for (const auto& group : groups_) {
877       for (const auto& selection : group) {
878         for (const auto& event_fd : selection.event_fds) {
879           if (event_fd->Cpu() == cpu) {
880             event_id_data.push_back(attr_id);
881             event_id_data.push_back(event_fd->Id());
882           }
883         }
884         ++attr_id;
885       }
886     }
887     EventIdRecord r(event_id_data);
888     if (!record_callback_(&r)) {
889       return false;
890     }
891   }
892   return true;
893 }
894 
CreateMappedBufferForCpu(int cpu)895 bool EventSelectionSet::CreateMappedBufferForCpu(int cpu) {
896   std::vector<EventFd*> event_fds;
897   for (auto& group : groups_) {
898     for (auto& selection : group) {
899       for (auto& fd : selection.event_fds) {
900         if (fd->Cpu() == cpu) {
901           event_fds.push_back(fd.get());
902         }
903       }
904     }
905   }
906   return record_read_thread_->AddEventFds(event_fds);
907 }
908 
StopWhenNoMoreTargets(double check_interval_in_sec)909 bool EventSelectionSet::StopWhenNoMoreTargets(double check_interval_in_sec) {
910   return loop_->AddPeriodicEvent(SecondToTimeval(check_interval_in_sec),
911                                  [&]() { return CheckMonitoredTargets(); });
912 }
913 
CheckMonitoredTargets()914 bool EventSelectionSet::CheckMonitoredTargets() {
915   if (!HasSampler()) {
916     return loop_->ExitLoop();
917   }
918   for (const auto& tid : threads_) {
919     if (IsThreadAlive(tid)) {
920       return true;
921     }
922   }
923   for (const auto& pid : processes_) {
924     if (IsThreadAlive(pid)) {
925       return true;
926     }
927   }
928   return loop_->ExitLoop();
929 }
930 
HasSampler()931 bool EventSelectionSet::HasSampler() {
932   for (auto& group : groups_) {
933     for (auto& sel : group) {
934       if (!sel.event_fds.empty()) {
935         return true;
936       }
937       for (auto& sampler : sel.inplace_samplers) {
938         if (!sampler->IsClosed()) {
939           return true;
940         }
941       }
942     }
943   }
944   return false;
945 }
946 
SetEnableEvents(bool enable)947 bool EventSelectionSet::SetEnableEvents(bool enable) {
948   for (auto& group : groups_) {
949     for (auto& sel : group) {
950       for (auto& fd : sel.event_fds) {
951         if (!fd->SetEnableEvent(enable)) {
952           return false;
953         }
954       }
955     }
956   }
957   return true;
958 }
959