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 <base/logging.h>
20 
21 #include "environment.h"
22 #include "event_attr.h"
23 #include "event_type.h"
24 
AddEventType(const EventType & event_type)25 void EventSelectionSet::AddEventType(const EventType& event_type) {
26   EventSelection selection;
27   selection.event_type = &event_type;
28   selection.event_attr = CreateDefaultPerfEventAttr(event_type);
29   selections_.push_back(std::move(selection));
30 }
31 
EnableOnExec()32 void EventSelectionSet::EnableOnExec() {
33   for (auto& selection : selections_) {
34     selection.event_attr.enable_on_exec = 1;
35   }
36 }
37 
SampleIdAll()38 void EventSelectionSet::SampleIdAll() {
39   for (auto& selection : selections_) {
40     selection.event_attr.sample_id_all = 1;
41   }
42 }
43 
SetSampleFreq(uint64_t sample_freq)44 void EventSelectionSet::SetSampleFreq(uint64_t sample_freq) {
45   for (auto& selection : selections_) {
46     perf_event_attr& attr = selection.event_attr;
47     attr.freq = 1;
48     attr.sample_freq = sample_freq;
49   }
50 }
51 
SetSamplePeriod(uint64_t sample_period)52 void EventSelectionSet::SetSamplePeriod(uint64_t sample_period) {
53   for (auto& selection : selections_) {
54     perf_event_attr& attr = selection.event_attr;
55     attr.freq = 0;
56     attr.sample_period = sample_period;
57   }
58 }
59 
OpenEventFilesForAllCpus()60 bool EventSelectionSet::OpenEventFilesForAllCpus() {
61   std::vector<int> cpus = GetOnlineCpus();
62   if (cpus.empty()) {
63     return false;
64   }
65   for (auto& selection : selections_) {
66     for (auto& cpu : cpus) {
67       auto event_fd = EventFd::OpenEventFileForCpu(selection.event_attr, cpu);
68       if (event_fd != nullptr) {
69         selection.event_fds.push_back(std::move(event_fd));
70       }
71     }
72     // As the online cpus can be enabled or disabled at runtime, we may not open event file for
73     // all cpus successfully. But we should open at least one cpu successfully.
74     if (selection.event_fds.empty()) {
75       LOG(ERROR) << "failed to open perf event file for event_type " << selection.event_type->name
76                  << " on all cpus";
77       return false;
78     }
79   }
80   return true;
81 }
82 
OpenEventFilesForProcess(pid_t pid)83 bool EventSelectionSet::OpenEventFilesForProcess(pid_t pid) {
84   for (auto& selection : selections_) {
85     auto event_fd = EventFd::OpenEventFileForProcess(selection.event_attr, pid);
86     if (event_fd == nullptr) {
87       PLOG(ERROR) << "failed to open perf event file for event type " << selection.event_type->name
88                   << " on pid " << pid;
89       return false;
90     }
91     selection.event_fds.push_back(std::move(event_fd));
92   }
93   return true;
94 }
95 
EnableEvents()96 bool EventSelectionSet::EnableEvents() {
97   for (auto& selection : selections_) {
98     for (auto& event_fd : selection.event_fds) {
99       if (!event_fd->EnableEvent()) {
100         return false;
101       }
102     }
103   }
104   return true;
105 }
106 
ReadCounters(std::map<const EventType *,std::vector<PerfCounter>> * counters_map)107 bool EventSelectionSet::ReadCounters(
108     std::map<const EventType*, std::vector<PerfCounter>>* counters_map) {
109   for (auto& selection : selections_) {
110     std::vector<PerfCounter> counters;
111     for (auto& event_fd : selection.event_fds) {
112       PerfCounter counter;
113       if (!event_fd->ReadCounter(&counter)) {
114         return false;
115       }
116       counters.push_back(counter);
117     }
118     counters_map->insert(std::make_pair(selection.event_type, counters));
119   }
120   return true;
121 }
122 
PreparePollForEventFiles(std::vector<pollfd> * pollfds)123 void EventSelectionSet::PreparePollForEventFiles(std::vector<pollfd>* pollfds) {
124   for (auto& selection : selections_) {
125     for (auto& event_fd : selection.event_fds) {
126       pollfd poll_fd;
127       event_fd->PreparePollForMmapData(&poll_fd);
128       pollfds->push_back(poll_fd);
129     }
130   }
131 }
132 
MmapEventFiles(size_t mmap_pages)133 bool EventSelectionSet::MmapEventFiles(size_t mmap_pages) {
134   for (auto& selection : selections_) {
135     for (auto& event_fd : selection.event_fds) {
136       if (!event_fd->MmapContent(mmap_pages)) {
137         return false;
138       }
139     }
140   }
141   return true;
142 }
143 
ReadMmapEventDataForFd(std::unique_ptr<EventFd> & event_fd,std::function<bool (const char *,size_t)> callback,bool * have_data)144 static bool ReadMmapEventDataForFd(std::unique_ptr<EventFd>& event_fd,
145                                    std::function<bool(const char*, size_t)> callback,
146                                    bool* have_data) {
147   *have_data = false;
148   while (true) {
149     char* data;
150     size_t size = event_fd->GetAvailableMmapData(&data);
151     if (size == 0) {
152       break;
153     }
154     if (!callback(data, size)) {
155       return false;
156     }
157     *have_data = true;
158     event_fd->DiscardMmapData(size);
159   }
160   return true;
161 }
162 
ReadMmapEventData(std::function<bool (const char *,size_t)> callback)163 bool EventSelectionSet::ReadMmapEventData(std::function<bool(const char*, size_t)> callback) {
164   for (auto& selection : selections_) {
165     for (auto& event_fd : selection.event_fds) {
166       while (true) {
167         bool have_data;
168         if (!ReadMmapEventDataForFd(event_fd, callback, &have_data)) {
169           return false;
170         }
171         if (!have_data) {
172           break;
173         }
174       }
175     }
176   }
177   return true;
178 }
179 
FindEventFileNameById(uint64_t id)180 std::string EventSelectionSet::FindEventFileNameById(uint64_t id) {
181   for (auto& selection : selections_) {
182     for (auto& event_fd : selection.event_fds) {
183       if (event_fd->Id() == id) {
184         return event_fd->Name();
185       }
186     }
187   }
188   return "";
189 }
190 
FindSelectionByType(const EventType & event_type)191 EventSelectionSet::EventSelection* EventSelectionSet::FindSelectionByType(
192     const EventType& event_type) {
193   for (auto& selection : selections_) {
194     if (strcmp(selection.event_type->name, event_type.name) == 0) {
195       return &selection;
196     }
197   }
198   return nullptr;
199 }
200 
FindEventAttrByType(const EventType & event_type)201 const perf_event_attr& EventSelectionSet::FindEventAttrByType(const EventType& event_type) {
202   return FindSelectionByType(event_type)->event_attr;
203 }
204 
FindEventFdsByType(const EventType & event_type)205 const std::vector<std::unique_ptr<EventFd>>& EventSelectionSet::FindEventFdsByType(
206     const EventType& event_type) {
207   return FindSelectionByType(event_type)->event_fds;
208 }
209