blob: 36db17ca4e20987d227a480794df028171e3a96e [file] [log] [blame]
Yabin Cui67d3abd2015-04-16 15:26:31 -07001/*
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 */
Wei Wangcf69e412016-09-29 16:34:15 -070016#define ATRACE_TAG ATRACE_TAG_ALWAYS
Yabin Cui67d3abd2015-04-16 15:26:31 -070017#include "event_fd.h"
18
Thiébaud Weksteen4848ee02020-10-23 16:06:59 +020019#include <cutils/trace.h>
Yabin Cui67d3abd2015-04-16 15:26:31 -070020#include <fcntl.h>
21#include <stdio.h>
Yabin Cuif469c3d2015-10-07 15:00:46 -070022#include <string.h>
Yabin Cui67d3abd2015-04-16 15:26:31 -070023#include <sys/ioctl.h>
Yabin Cui9759e1b2015-04-28 15:54:13 -070024#include <sys/mman.h>
Yabin Cui67d3abd2015-04-16 15:26:31 -070025#include <sys/syscall.h>
26#include <sys/types.h>
Thiébaud Weksteen4848ee02020-10-23 16:06:59 +020027#include <utils/Trace.h>
Yabin Cuif569b472015-04-30 09:43:26 -070028#include <atomic>
Yabin Cui67d3abd2015-04-16 15:26:31 -070029#include <memory>
30
Elliott Hughes66dd09e2015-12-04 14:00:57 -080031#include <android-base/file.h>
32#include <android-base/logging.h>
33#include <android-base/stringprintf.h>
Yabin Cui67d3abd2015-04-16 15:26:31 -070034
Yabin Cui0720d482017-03-06 17:05:50 -080035#include "environment.h"
Yabin Cuic10a9dc2016-06-15 12:10:33 -070036#include "event_attr.h"
Yabin Cui67d3abd2015-04-16 15:26:31 -070037#include "event_type.h"
Yabin Cui67d3abd2015-04-16 15:26:31 -070038#include "perf_event.h"
39#include "utils.h"
40
Yabin Cuifaa7b922021-01-11 17:35:57 -080041namespace simpleperf {
42
Thiébaud Weksteen4848ee02020-10-23 16:06:59 +020043static int perf_event_open(const perf_event_attr& attr, pid_t pid, int cpu, int group_fd,
44 unsigned long flags) { // NOLINT
Yabin Cuidbbda302016-07-28 12:55:41 -070045 return syscall(__NR_perf_event_open, &attr, pid, cpu, group_fd, flags);
Yabin Cui67d3abd2015-04-16 15:26:31 -070046}
47
Yabin Cui8bcd8f12020-01-23 15:33:35 -080048std::unique_ptr<EventFd> EventFd::OpenEventFile(const perf_event_attr& attr, pid_t tid, int cpu,
Yabin Cuidbbda302016-07-28 12:55:41 -070049 EventFd* group_event_fd,
Yabin Cui8bcd8f12020-01-23 15:33:35 -080050 const std::string& event_name, bool report_error) {
Yabin Cui877751b2016-06-13 18:03:47 -070051 int group_fd = -1;
52 if (group_event_fd != nullptr) {
53 group_fd = group_event_fd->perf_event_fd_;
54 }
Yabin Cui0720d482017-03-06 17:05:50 -080055 perf_event_attr real_attr = attr;
56 if (attr.freq) {
57 uint64_t max_sample_freq;
58 if (GetMaxSampleFrequency(&max_sample_freq) && max_sample_freq < attr.sample_freq) {
Yabin Cui68b83832017-07-19 17:54:57 -070059 static bool warned = false;
60 if (!warned) {
61 warned = true;
Yabin Cuid97a5322017-07-26 12:29:44 -070062 LOG(INFO) << "Adjust sample freq to max allowed sample freq " << max_sample_freq;
Yabin Cui68b83832017-07-19 17:54:57 -070063 }
Yabin Cui0720d482017-03-06 17:05:50 -080064 real_attr.sample_freq = max_sample_freq;
65 }
66 }
67 int perf_event_fd = perf_event_open(real_attr, tid, cpu, group_fd, 0);
Yabin Cui67d3abd2015-04-16 15:26:31 -070068 if (perf_event_fd == -1) {
Yabin Cui42aa1272015-09-18 11:10:55 -070069 if (report_error) {
Thiébaud Weksteen4848ee02020-10-23 16:06:59 +020070 PLOG(ERROR) << "open perf_event_file (event " << event_name << ", tid " << tid << ", cpu "
71 << cpu << ", group_fd " << group_fd << ") failed";
Yabin Cui42aa1272015-09-18 11:10:55 -070072 } else {
Thiébaud Weksteen4848ee02020-10-23 16:06:59 +020073 PLOG(DEBUG) << "open perf_event_file (event " << event_name << ", tid " << tid << ", cpu "
74 << cpu << ", group_fd " << group_fd << ") failed";
Yabin Cui42aa1272015-09-18 11:10:55 -070075 }
Yabin Cui67d3abd2015-04-16 15:26:31 -070076 return nullptr;
77 }
78 if (fcntl(perf_event_fd, F_SETFD, FD_CLOEXEC) == -1) {
Yabin Cui42aa1272015-09-18 11:10:55 -070079 if (report_error) {
Thiébaud Weksteen4848ee02020-10-23 16:06:59 +020080 PLOG(ERROR) << "fcntl(FD_CLOEXEC) for perf_event_file (event " << event_name << ", tid "
81 << tid << ", cpu " << cpu << ", group_fd " << group_fd << ") failed";
Yabin Cui42aa1272015-09-18 11:10:55 -070082 } else {
Thiébaud Weksteen4848ee02020-10-23 16:06:59 +020083 PLOG(DEBUG) << "fcntl(FD_CLOEXEC) for perf_event_file (event " << event_name << ", tid "
84 << tid << ", cpu " << cpu << ", group_fd " << group_fd << ") failed";
Yabin Cui42aa1272015-09-18 11:10:55 -070085 }
Yabin Cui67d3abd2015-04-16 15:26:31 -070086 return nullptr;
87 }
Thiébaud Weksteen4848ee02020-10-23 16:06:59 +020088 return std::unique_ptr<EventFd>(new EventFd(real_attr, perf_event_fd, event_name, tid, cpu));
Yabin Cui67d3abd2015-04-16 15:26:31 -070089}
90
91EventFd::~EventFd() {
Yabin Cui0a072cd2016-07-13 17:06:50 -070092 DestroyMappedBuffer();
Yabin Cui1172d7e2019-07-25 15:12:58 -070093 DestroyAuxBuffer();
Yabin Cui67d3abd2015-04-16 15:26:31 -070094 close(perf_event_fd_);
95}
96
97std::string EventFd::Name() const {
Thiébaud Weksteen4848ee02020-10-23 16:06:59 +020098 return android::base::StringPrintf("perf_event_file(event %s, tid %d, cpu %d)",
99 event_name_.c_str(), tid_, cpu_);
Yabin Cui67d3abd2015-04-16 15:26:31 -0700100}
101
Yabin Cui9759e1b2015-04-28 15:54:13 -0700102uint64_t EventFd::Id() const {
103 if (id_ == 0) {
Yabin Cuid6b4b442021-12-20 21:17:37 -0800104 if (ioctl(perf_event_fd_, PERF_EVENT_IOC_ID, &id_) != 0) {
Yabin Cuide5788c2022-01-21 14:41:48 -0800105 // PERF_EVENT_IOC_ID isn't available in kernel <= 3.10. Fallback to read() in this case.
106 PerfCounter counter;
107 if (InnerReadCounter(&counter)) {
108 id_ = counter.id;
109 } else {
110 PLOG(WARNING) << "failed to get id of event_fd";
111 }
Yabin Cui9759e1b2015-04-28 15:54:13 -0700112 }
113 }
114 return id_;
115}
116
Yabin Cuid9121ce2019-02-07 11:06:16 -0800117bool EventFd::SetEnableEvent(bool enable) {
118 int result = ioctl(perf_event_fd_, enable ? PERF_EVENT_IOC_ENABLE : PERF_EVENT_IOC_DISABLE, 0);
Yabin Cui56335862016-04-18 13:43:20 -0700119 if (result < 0) {
Yabin Cuid9121ce2019-02-07 11:06:16 -0800120 PLOG(ERROR) << "ioctl(" << (enable ? "enable" : "disable") << ")" << Name() << " failed";
Yabin Cui56335862016-04-18 13:43:20 -0700121 return false;
122 }
123 return true;
124}
125
Yabin Cuie8203552019-08-06 10:29:45 -0700126bool EventFd::SetFilter(const std::string& filter) {
127 bool success = ioctl(perf_event_fd_, PERF_EVENT_IOC_SET_FILTER, filter.c_str()) >= 0;
128 if (!success) {
129 PLOG(ERROR) << "failed to set filter";
130 }
131 return success;
132}
133
Yabin Cuib6b43322017-05-04 11:28:09 -0700134bool EventFd::InnerReadCounter(PerfCounter* counter) const {
Yabin Cui323e9452015-04-20 18:07:17 -0700135 CHECK(counter != nullptr);
Yabin Cui9759e1b2015-04-28 15:54:13 -0700136 if (!android::base::ReadFully(perf_event_fd_, counter, sizeof(*counter))) {
Yabin Cui323e9452015-04-20 18:07:17 -0700137 PLOG(ERROR) << "ReadCounter from " << Name() << " failed";
138 return false;
139 }
Yabin Cuib6b43322017-05-04 11:28:09 -0700140 return true;
141}
142
143bool EventFd::ReadCounter(PerfCounter* counter) {
144 if (!InnerReadCounter(counter)) {
145 return false;
146 }
Wei Wangcf69e412016-09-29 16:34:15 -0700147 // Trace is always available to systrace if enabled
148 if (tid_ > 0) {
Thiébaud Weksteen4848ee02020-10-23 16:06:59 +0200149 ATRACE_INT64(
150 android::base::StringPrintf("%s_tid%d_cpu%d", event_name_.c_str(), tid_, cpu_).c_str(),
151 counter->value - last_counter_value_);
Wei Wangcf69e412016-09-29 16:34:15 -0700152 } else {
Thiébaud Weksteen4848ee02020-10-23 16:06:59 +0200153 ATRACE_INT64(android::base::StringPrintf("%s_cpu%d", event_name_.c_str(), cpu_).c_str(),
154 counter->value - last_counter_value_);
Wei Wangcf69e412016-09-29 16:34:15 -0700155 }
Yabin Cuib6b43322017-05-04 11:28:09 -0700156 last_counter_value_ = counter->value;
Yabin Cui323e9452015-04-20 18:07:17 -0700157 return true;
158}
Yabin Cui9759e1b2015-04-28 15:54:13 -0700159
Yabin Cuidbbda302016-07-28 12:55:41 -0700160bool EventFd::CreateMappedBuffer(size_t mmap_pages, bool report_error) {
Yabin Cui9759e1b2015-04-28 15:54:13 -0700161 CHECK(IsPowerOfTwo(mmap_pages));
162 size_t page_size = sysconf(_SC_PAGE_SIZE);
163 size_t mmap_len = (mmap_pages + 1) * page_size;
Thiébaud Weksteen4848ee02020-10-23 16:06:59 +0200164 void* mmap_addr = mmap(nullptr, mmap_len, PROT_READ | PROT_WRITE, MAP_SHARED, perf_event_fd_, 0);
Yabin Cui9759e1b2015-04-28 15:54:13 -0700165 if (mmap_addr == MAP_FAILED) {
Yabin Cui27816c92016-07-07 14:42:54 -0700166 bool is_perm_error = (errno == EPERM);
Yabin Cui0a072cd2016-07-13 17:06:50 -0700167 if (report_error) {
168 PLOG(ERROR) << "mmap(" << mmap_pages << ") failed for " << Name();
169 } else {
170 PLOG(DEBUG) << "mmap(" << mmap_pages << ") failed for " << Name();
171 }
172 if (report_error && is_perm_error) {
Thiébaud Weksteen4848ee02020-10-23 16:06:59 +0200173 LOG(ERROR) << "It seems the kernel doesn't allow allocating enough "
174 << "buffer for dumping samples, consider decreasing mmap pages(-m).";
Yabin Cui27816c92016-07-07 14:42:54 -0700175 }
Yabin Cui9759e1b2015-04-28 15:54:13 -0700176 return false;
177 }
178 mmap_addr_ = mmap_addr;
179 mmap_len_ = mmap_len;
180 mmap_metadata_page_ = reinterpret_cast<perf_event_mmap_page*>(mmap_addr_);
181 mmap_data_buffer_ = reinterpret_cast<char*>(mmap_addr_) + page_size;
182 mmap_data_buffer_size_ = mmap_len_ - page_size;
Yabin Cui61735922016-07-08 13:56:48 -0700183 return true;
184}
185
Yabin Cui0a072cd2016-07-13 17:06:50 -0700186bool EventFd::ShareMappedBuffer(const EventFd& event_fd, bool report_error) {
Yabin Cui61735922016-07-08 13:56:48 -0700187 CHECK(!HasMappedBuffer());
188 CHECK(event_fd.HasMappedBuffer());
Thiébaud Weksteen4848ee02020-10-23 16:06:59 +0200189 int result = ioctl(perf_event_fd_, PERF_EVENT_IOC_SET_OUTPUT, event_fd.perf_event_fd_);
Yabin Cui61735922016-07-08 13:56:48 -0700190 if (result != 0) {
Yabin Cui0a072cd2016-07-13 17:06:50 -0700191 if (report_error) {
Thiébaud Weksteen4848ee02020-10-23 16:06:59 +0200192 PLOG(ERROR) << "failed to share mapped buffer of " << event_fd.perf_event_fd_ << " with "
193 << perf_event_fd_;
Yabin Cui0a072cd2016-07-13 17:06:50 -0700194 }
Yabin Cui61735922016-07-08 13:56:48 -0700195 return false;
196 }
Yabin Cui9759e1b2015-04-28 15:54:13 -0700197 return true;
198}
199
Yabin Cui0a072cd2016-07-13 17:06:50 -0700200void EventFd::DestroyMappedBuffer() {
201 if (HasMappedBuffer()) {
202 munmap(mmap_addr_, mmap_len_);
203 mmap_addr_ = nullptr;
204 mmap_len_ = 0;
205 mmap_metadata_page_ = nullptr;
206 mmap_data_buffer_ = nullptr;
207 mmap_data_buffer_size_ = 0;
208 }
209}
210
Yabin Cui86f0c1b2018-06-21 10:24:55 -0700211std::vector<char> EventFd::GetAvailableMmapData() {
212 size_t data_pos;
213 size_t data_size = GetAvailableMmapDataSize(data_pos);
214 std::vector<char> data(data_size);
215 if (data_size > 0) {
216 size_t copy_size = std::min(data_size, mmap_data_buffer_size_ - data_pos);
217 memcpy(&data[0], mmap_data_buffer_ + data_pos, copy_size);
218 if (copy_size < data_size) {
219 memcpy(&data[copy_size], mmap_data_buffer_, data_size - copy_size);
220 }
221 DiscardMmapData(data_size);
Yabin Cui61735922016-07-08 13:56:48 -0700222 }
Yabin Cui86f0c1b2018-06-21 10:24:55 -0700223 return data;
224}
225
226size_t EventFd::GetAvailableMmapDataSize(size_t& data_pos) {
Yabin Cuidbbda302016-07-28 12:55:41 -0700227 // The mmap_data_buffer is used as a ring buffer between the kernel and
228 // simpleperf. The kernel continuously writes records to the buffer, and
229 // simpleperf continuously read records out.
Yabin Cui9759e1b2015-04-28 15:54:13 -0700230 // _________________________________________
231 // buffer | can write | can read | can write |
232 // ^ ^
233 // read_head write_head
234 //
Yabin Cuidbbda302016-07-28 12:55:41 -0700235 // So simpleperf can read records in [read_head, write_head), and the kernel
236 // can write records in [write_head, read_head). The kernel is responsible
237 // for updating write_head, and simpleperf is responsible for updating
238 // read_head.
Yabin Cui9759e1b2015-04-28 15:54:13 -0700239
Yabin Cui86f0c1b2018-06-21 10:24:55 -0700240 uint64_t write_head = mmap_metadata_page_->data_head;
241 uint64_t read_head = mmap_metadata_page_->data_tail;
Yabin Cui0e111d92019-05-10 16:18:51 -0700242 // The kernel may decrease data_head temporarily (http://b/132446871), making
243 // write_head < read_head. So check it to avoid available data size underflow.
244 if (write_head <= read_head) {
Yabin Cui9759e1b2015-04-28 15:54:13 -0700245 // No available data.
246 return 0;
247 }
Yabin Cui92f80f42017-01-06 15:01:42 -0800248 // rmb() used to ensure reading data after reading data_head.
249 __sync_synchronize();
Yabin Cui86f0c1b2018-06-21 10:24:55 -0700250 data_pos = read_head & (mmap_data_buffer_size_ - 1);
251 return write_head - read_head;
Yabin Cui9759e1b2015-04-28 15:54:13 -0700252}
253
254void EventFd::DiscardMmapData(size_t discard_size) {
Yabin Cui92f80f42017-01-06 15:01:42 -0800255 // mb() used to ensure finish reading data before writing data_tail.
256 __sync_synchronize();
Yabin Cui9759e1b2015-04-28 15:54:13 -0700257 mmap_metadata_page_->data_tail += discard_size;
258}
259
Yabin Cui1172d7e2019-07-25 15:12:58 -0700260bool EventFd::CreateAuxBuffer(size_t aux_buffer_size, bool report_error) {
261 CHECK(HasMappedBuffer());
262 CHECK(IsPowerOfTwo(aux_buffer_size));
263 mmap_metadata_page_->aux_offset = mmap_len_;
264 mmap_metadata_page_->aux_size = aux_buffer_size;
265 mmap_metadata_page_->aux_head = 0;
266 mmap_metadata_page_->aux_tail = 0;
267 void* mmap_addr = mmap(nullptr, aux_buffer_size, PROT_READ | PROT_WRITE, MAP_SHARED,
268 perf_event_fd_, mmap_metadata_page_->aux_offset);
269 if (mmap_addr == MAP_FAILED) {
270 if (report_error) {
271 PLOG(ERROR) << "failed to mmap aux buffer of size " << aux_buffer_size << " for " << Name();
272 } else {
273 PLOG(DEBUG) << "failed to mmap aux buffer of size " << aux_buffer_size << " for " << Name();
274 }
275 return false;
276 }
277 aux_buffer_ = static_cast<char*>(mmap_addr);
278 aux_buffer_size_ = aux_buffer_size;
279 return true;
280}
281
282void EventFd::DestroyAuxBuffer() {
283 if (HasAuxBuffer()) {
284 munmap(aux_buffer_, aux_buffer_size_);
285 aux_buffer_ = nullptr;
286 aux_buffer_size_ = 0;
287 }
288}
289
290uint64_t EventFd::GetAvailableAuxData(char** buf1, size_t* size1, char** buf2, size_t* size2) {
291 // Aux buffer is similar to mapped_data_buffer. See comments in GetAvailableMmapData().
292 uint64_t write_head = mmap_metadata_page_->aux_head;
293 uint64_t read_head = mmap_metadata_page_->aux_tail;
294 if (write_head <= read_head) {
295 *size1 = *size2 = 0;
296 return 0; // No available data.
297 }
298 // rmb() used to ensure reading data after reading aux_head.
299 __sync_synchronize();
300 size_t data_pos = read_head & (aux_buffer_size_ - 1);
301 size_t data_size = write_head - read_head;
302 *buf1 = aux_buffer_ + data_pos;
303 if (data_size <= aux_buffer_size_ - data_pos) {
304 *size1 = data_size;
305 *size2 = 0;
306 } else {
307 *size1 = aux_buffer_size_ - data_pos;
308 *buf2 = aux_buffer_;
309 *size2 = data_size - *size1;
310 }
311 return read_head;
312}
313
314void EventFd::DiscardAuxData(size_t discard_size) {
315 // mb() used to ensure finish reading data before writing aux_tail.
316 __sync_synchronize();
317 mmap_metadata_page_->aux_tail += discard_size;
318}
319
Thiébaud Weksteen4848ee02020-10-23 16:06:59 +0200320bool EventFd::StartPolling(IOEventLoop& loop, const std::function<bool()>& callback) {
Yabin Cui825e56b2016-08-26 18:25:21 -0700321 ioevent_ref_ = loop.AddReadEvent(perf_event_fd_, callback);
322 return ioevent_ref_ != nullptr;
323}
324
Thiébaud Weksteen4848ee02020-10-23 16:06:59 +0200325bool EventFd::StopPolling() {
326 return IOEventLoop::DelEvent(ioevent_ref_);
327}
Yabin Cui825e56b2016-08-26 18:25:21 -0700328
Yabin Cui8bcd8f12020-01-23 15:33:35 -0800329bool IsEventAttrSupported(const perf_event_attr& attr, const std::string& event_name) {
330 return EventFd::OpenEventFile(attr, getpid(), -1, nullptr, event_name, false) != nullptr;
Yabin Cui9fd3cc12015-06-25 17:42:23 -0700331}
Yabin Cuifaa7b922021-01-11 17:35:57 -0800332
333} // namespace simpleperf