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_fd.h" 18 19 #include <fcntl.h> 20 #include <poll.h> 21 #include <stdio.h> 22 #include <string.h> 23 #include <sys/ioctl.h> 24 #include <sys/mman.h> 25 #include <sys/syscall.h> 26 #include <sys/types.h> 27 #include <atomic> 28 #include <memory> 29 30 #include <android-base/file.h> 31 #include <android-base/logging.h> 32 #include <android-base/stringprintf.h> 33 34 #include "event_type.h" 35 #include "perf_event.h" 36 #include "utils.h" 37 38 std::vector<char> EventFd::data_process_buffer_; 39 40 static int perf_event_open(perf_event_attr* attr, pid_t pid, int cpu, int group_fd, 41 unsigned long flags) { 42 return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags); 43 } 44 45 std::unique_ptr<EventFd> EventFd::OpenEventFile(const perf_event_attr& attr, pid_t tid, int cpu, 46 bool report_error) { 47 perf_event_attr perf_attr = attr; 48 std::string event_name = "unknown event"; 49 const EventType* event_type = FindEventTypeByConfig(perf_attr.type, perf_attr.config); 50 if (event_type != nullptr) { 51 event_name = event_type->name; 52 } 53 int perf_event_fd = perf_event_open(&perf_attr, tid, cpu, -1, 0); 54 if (perf_event_fd == -1) { 55 if (report_error) { 56 PLOG(ERROR) << "open perf_event_file (event " << event_name << ", tid " << tid << ", cpu " 57 << cpu << ") failed"; 58 } else { 59 PLOG(DEBUG) << "open perf_event_file (event " << event_name << ", tid " << tid << ", cpu " 60 << cpu << ") failed"; 61 } 62 return nullptr; 63 } 64 if (fcntl(perf_event_fd, F_SETFD, FD_CLOEXEC) == -1) { 65 if (report_error) { 66 PLOG(ERROR) << "fcntl(FD_CLOEXEC) for perf_event_file (event " << event_name << ", tid " 67 << tid << ", cpu " << cpu << ") failed"; 68 } else { 69 PLOG(DEBUG) << "fcntl(FD_CLOEXEC) for perf_event_file (event " << event_name << ", tid " 70 << tid << ", cpu " << cpu << ") failed"; 71 } 72 return nullptr; 73 } 74 return std::unique_ptr<EventFd>(new EventFd(perf_event_fd, event_name, tid, cpu)); 75 } 76 77 EventFd::~EventFd() { 78 if (mmap_addr_ != nullptr) { 79 munmap(mmap_addr_, mmap_len_); 80 } 81 close(perf_event_fd_); 82 } 83 84 std::string EventFd::Name() const { 85 return android::base::StringPrintf("perf_event_file(event %s, tid %d, cpu %d)", 86 event_name_.c_str(), tid_, cpu_); 87 } 88 89 uint64_t EventFd::Id() const { 90 if (id_ == 0) { 91 PerfCounter counter; 92 if (ReadCounter(&counter)) { 93 id_ = counter.id; 94 } 95 } 96 return id_; 97 } 98 99 bool EventFd::ReadCounter(PerfCounter* counter) const { 100 CHECK(counter != nullptr); 101 if (!android::base::ReadFully(perf_event_fd_, counter, sizeof(*counter))) { 102 PLOG(ERROR) << "ReadCounter from " << Name() << " failed"; 103 return false; 104 } 105 return true; 106 } 107 108 bool EventFd::MmapContent(size_t mmap_pages) { 109 CHECK(IsPowerOfTwo(mmap_pages)); 110 size_t page_size = sysconf(_SC_PAGE_SIZE); 111 size_t mmap_len = (mmap_pages + 1) * page_size; 112 void* mmap_addr = mmap(nullptr, mmap_len, PROT_READ | PROT_WRITE, MAP_SHARED, perf_event_fd_, 0); 113 if (mmap_addr == MAP_FAILED) { 114 PLOG(ERROR) << "mmap() failed for " << Name(); 115 return false; 116 } 117 mmap_addr_ = mmap_addr; 118 mmap_len_ = mmap_len; 119 mmap_metadata_page_ = reinterpret_cast<perf_event_mmap_page*>(mmap_addr_); 120 mmap_data_buffer_ = reinterpret_cast<char*>(mmap_addr_) + page_size; 121 mmap_data_buffer_size_ = mmap_len_ - page_size; 122 if (data_process_buffer_.size() < mmap_data_buffer_size_) { 123 data_process_buffer_.resize(mmap_data_buffer_size_); 124 } 125 return true; 126 } 127 128 size_t EventFd::GetAvailableMmapData(char** pdata) { 129 // The mmap_data_buffer is used as a ring buffer like below. The kernel continuously writes 130 // records to the buffer, and the user continuously read records out. 131 // _________________________________________ 132 // buffer | can write | can read | can write | 133 // ^ ^ 134 // read_head write_head 135 // 136 // So the user can read records in [read_head, write_head), and the kernel can write records 137 // in [write_head, read_head). The kernel is responsible for updating write_head, and the user 138 // is responsible for updating read_head. 139 140 size_t buf_mask = mmap_data_buffer_size_ - 1; 141 size_t write_head = static_cast<size_t>(mmap_metadata_page_->data_head & buf_mask); 142 size_t read_head = static_cast<size_t>(mmap_metadata_page_->data_tail & buf_mask); 143 144 if (read_head == write_head) { 145 // No available data. 146 return 0; 147 } 148 149 // Make sure we can see the data after the fence. 150 std::atomic_thread_fence(std::memory_order_acquire); 151 152 // Copy records from mapped buffer to data_process_buffer. Note that records can be wrapped 153 // at the end of the mapped buffer. 154 char* to = data_process_buffer_.data(); 155 if (read_head < write_head) { 156 char* from = mmap_data_buffer_ + read_head; 157 size_t n = write_head - read_head; 158 memcpy(to, from, n); 159 to += n; 160 } else { 161 char* from = mmap_data_buffer_ + read_head; 162 size_t n = mmap_data_buffer_size_ - read_head; 163 memcpy(to, from, n); 164 to += n; 165 from = mmap_data_buffer_; 166 n = write_head; 167 memcpy(to, from, n); 168 to += n; 169 } 170 size_t read_bytes = to - data_process_buffer_.data(); 171 *pdata = data_process_buffer_.data(); 172 DiscardMmapData(read_bytes); 173 return read_bytes; 174 } 175 176 void EventFd::DiscardMmapData(size_t discard_size) { 177 mmap_metadata_page_->data_tail += discard_size; 178 } 179 180 void EventFd::PreparePollForMmapData(pollfd* poll_fd) { 181 memset(poll_fd, 0, sizeof(pollfd)); 182 poll_fd->fd = perf_event_fd_; 183 poll_fd->events = POLLIN; 184 } 185 186 bool IsEventAttrSupportedByKernel(perf_event_attr attr) { 187 auto event_fd = EventFd::OpenEventFile(attr, getpid(), -1, false); 188 return event_fd != nullptr; 189 } 190