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