1 /* 2 * Copyright (C) 2018 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 #pragma once 18 19 #include <sys/types.h> 20 21 #include <atomic> 22 #include <condition_variable> 23 #include <functional> 24 #include <memory> 25 #include <mutex> 26 #include <thread> 27 #include <unordered_set> 28 29 #include <android-base/macros.h> 30 #include <android-base/unique_fd.h> 31 32 #include "event_fd.h" 33 #include "record.h" 34 35 namespace simpleperf { 36 37 // RecordBuffer is a circular buffer used to cache records in user-space. It allows one read 38 // thread and one write thread. The record read thread writes records to the buffer, and the main 39 // thread reads records from the buffer. 40 class RecordBuffer { 41 public: 42 RecordBuffer(size_t buffer_size); size()43 size_t size() const { return buffer_size_; } BufferEnd()44 char* BufferEnd() const { return buffer_.get() + buffer_size_; } 45 46 // Return the size of writable space in the buffer. 47 size_t GetFreeSize() const; 48 // Allocate a writable space for a record. Return nullptr if there isn't enough space. 49 char* AllocWriteSpace(size_t record_size); 50 // Called after writing a record, let the read thread see the record. 51 void FinishWrite(); 52 53 // Get data of the current record. Return nullptr if there is no records in the buffer. 54 char* GetCurrentRecord(); AddCurrentRecordSize(size_t size)55 void AddCurrentRecordSize(size_t size) { cur_read_record_size_ += size; } 56 // Called after reading a record, the space of the record will be writable. 57 void MoveToNextRecord(); 58 59 private: 60 std::atomic_size_t read_head_; 61 std::atomic_size_t write_head_; 62 size_t cur_write_record_size_ = 0; 63 size_t cur_read_record_size_ = 0; 64 const size_t buffer_size_; 65 std::unique_ptr<char> buffer_; 66 67 DISALLOW_COPY_AND_ASSIGN(RecordBuffer); 68 }; 69 70 // Parse positions of different fields in record data. 71 class RecordParser { 72 public: 73 RecordParser(const perf_event_attr& attr); 74 75 // Return pos of the pid field in the sample record. If not available, return 0. GetPidPosInSampleRecord()76 size_t GetPidPosInSampleRecord() const { return pid_pos_in_sample_records_; } 77 // Return pos of the time field in the record. If not available, return 0. 78 size_t GetTimePos(const perf_event_header& header) const; 79 // Return pos of the user stack size field in the sample record. If not available, return 0. 80 size_t GetStackSizePos(const std::function<void(size_t, size_t, void*)>& read_record_fn) const; 81 82 private: 83 uint64_t sample_type_; 84 uint64_t read_format_; 85 uint64_t sample_regs_count_; 86 size_t pid_pos_in_sample_records_ = 0; 87 size_t time_pos_in_sample_records_ = 0; 88 size_t time_rpos_in_non_sample_records_ = 0; 89 size_t read_pos_in_sample_records_ = 0; 90 }; 91 92 struct RecordStat { 93 size_t kernelspace_lost_records = 0; 94 size_t userspace_lost_samples = 0; 95 size_t userspace_lost_non_samples = 0; 96 size_t userspace_cut_stack_samples = 0; 97 uint64_t aux_data_size = 0; 98 uint64_t lost_aux_data_size = 0; 99 }; 100 101 // Read records from the kernel buffer belong to an event_fd. 102 class KernelRecordReader { 103 public: 104 KernelRecordReader(EventFd* event_fd); 105 GetEventFd()106 EventFd* GetEventFd() const { return event_fd_; } 107 // Get available data in the kernel buffer. Return true if there is some data. 108 bool GetDataFromKernelBuffer(); 109 // Get header of the current record. RecordHeader()110 const perf_event_header& RecordHeader() { return record_header_; } 111 // Get time of the current record. RecordTime()112 uint64_t RecordTime() { return record_time_; } 113 // Read data of the current record. 114 void ReadRecord(size_t pos, size_t size, void* dest); 115 // Move to the next record, return false if there is no more records. 116 bool MoveToNextRecord(const RecordParser& parser); 117 118 private: 119 EventFd* event_fd_; 120 char* buffer_; 121 size_t buffer_mask_; 122 size_t data_pos_ = 0; 123 size_t data_size_ = 0; 124 size_t init_data_size_ = 0; 125 perf_event_header record_header_ = {}; 126 uint64_t record_time_ = 0; 127 }; 128 129 // To reduce sample lost rate when recording dwarf based call graph, RecordReadThread uses a 130 // separate high priority (nice -20) thread to read records from kernel buffers to a RecordBuffer. 131 class RecordReadThread { 132 public: 133 RecordReadThread(size_t record_buffer_size, const perf_event_attr& attr, size_t min_mmap_pages, 134 size_t max_mmap_pages, size_t aux_buffer_size, bool allow_cutting_samples = true, 135 bool exclude_perf = false); 136 ~RecordReadThread(); SetBufferLevels(size_t record_buffer_low_level,size_t record_buffer_critical_level)137 void SetBufferLevels(size_t record_buffer_low_level, size_t record_buffer_critical_level) { 138 record_buffer_low_level_ = record_buffer_low_level; 139 record_buffer_critical_level_ = record_buffer_critical_level; 140 } 141 142 // Below functions are called in the main thread: 143 144 // When there are records in the RecordBuffer, data_callback will be called in the main thread. 145 bool RegisterDataCallback(IOEventLoop& loop, const std::function<bool()>& data_callback); 146 // Create and read kernel buffers for new event fds. 147 bool AddEventFds(const std::vector<EventFd*>& event_fds); 148 // Destroy kernel buffers of existing event fds. 149 bool RemoveEventFds(const std::vector<EventFd*>& event_fds); 150 // Move all available records in kernel buffers to the RecordBuffer. 151 bool SyncKernelBuffer(); 152 // Stop the read thread, no more records will be put into the RecordBuffer. 153 bool StopReadThread(); 154 155 // If available, return the next record in the RecordBuffer, otherwise return nullptr. 156 std::unique_ptr<Record> GetRecord(); 157 GetStat()158 const RecordStat& GetStat() const { return stat_; } 159 160 private: 161 enum Cmd { 162 NO_CMD, 163 CMD_ADD_EVENT_FDS, 164 CMD_REMOVE_EVENT_FDS, 165 CMD_SYNC_KERNEL_BUFFER, 166 CMD_STOP_THREAD, 167 }; 168 169 bool SendCmdToReadThread(Cmd cmd, void* cmd_arg); 170 171 // Below functions are called in the read thread: 172 173 void RunReadThread(); 174 void IncreaseThreadPriority(); 175 Cmd GetCmd(); 176 bool HandleCmd(IOEventLoop& loop); 177 bool HandleAddEventFds(IOEventLoop& loop, const std::vector<EventFd*>& event_fds); 178 bool HandleRemoveEventFds(const std::vector<EventFd*>& event_fds); 179 bool ReadRecordsFromKernelBuffer(); 180 void PushRecordToRecordBuffer(KernelRecordReader* kernel_record_reader); 181 void ReadAuxDataFromKernelBuffer(bool* has_data); 182 bool SendDataNotificationToMainThread(); 183 184 RecordBuffer record_buffer_; 185 // When free size in record buffer is below low level, we cut stack data of sample records to 1K. 186 size_t record_buffer_low_level_; 187 // When free size in record buffer is below critical level, we drop sample records to avoid 188 // losing more important records (like mmap or fork records). 189 size_t record_buffer_critical_level_; 190 RecordParser record_parser_; 191 perf_event_attr attr_; 192 size_t stack_size_in_sample_record_ = 0; 193 size_t min_mmap_pages_; 194 size_t max_mmap_pages_; 195 size_t aux_buffer_size_; 196 197 // Used to pass command notification from the main thread to the read thread. 198 android::base::unique_fd write_cmd_fd_; 199 android::base::unique_fd read_cmd_fd_; 200 std::mutex cmd_mutex_; 201 std::condition_variable cmd_finish_cond_; 202 Cmd cmd_; 203 void* cmd_arg_; 204 bool cmd_result_; 205 206 // Used to send data notification from the read thread to the main thread. 207 android::base::unique_fd write_data_fd_; 208 android::base::unique_fd read_data_fd_; 209 std::atomic_bool has_data_notification_; 210 211 std::unique_ptr<std::thread> read_thread_; 212 std::vector<KernelRecordReader> kernel_record_readers_; 213 pid_t exclude_pid_ = -1; 214 215 std::unordered_set<EventFd*> event_fds_disabled_by_kernel_; 216 217 RecordStat stat_; 218 }; 219 220 } // namespace simpleperf 221