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