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 lost_samples = 0; 94 size_t lost_non_samples = 0; 95 size_t cut_stack_samples = 0; 96 uint64_t aux_data_size = 0; 97 uint64_t lost_aux_data_size = 0; 98 }; 99 100 // Read records from the kernel buffer belong to an event_fd. 101 class KernelRecordReader { 102 public: 103 KernelRecordReader(EventFd* event_fd); 104 GetEventFd()105 EventFd* GetEventFd() const { return event_fd_; } 106 // Get available data in the kernel buffer. Return true if there is some data. 107 bool GetDataFromKernelBuffer(); 108 // Get header of the current record. RecordHeader()109 const perf_event_header& RecordHeader() { return record_header_; } 110 // Get time of the current record. RecordTime()111 uint64_t RecordTime() { return record_time_; } 112 // Read data of the current record. 113 void ReadRecord(size_t pos, size_t size, void* dest); 114 // Move to the next record, return false if there is no more records. 115 bool MoveToNextRecord(const RecordParser& parser); 116 117 private: 118 EventFd* event_fd_; 119 char* buffer_; 120 size_t buffer_mask_; 121 size_t data_pos_ = 0; 122 size_t data_size_ = 0; 123 size_t init_data_size_ = 0; 124 perf_event_header record_header_ = {}; 125 uint64_t record_time_ = 0; 126 }; 127 128 // To reduce sample lost rate when recording dwarf based call graph, RecordReadThread uses a 129 // separate high priority (nice -20) thread to read records from kernel buffers to a RecordBuffer. 130 class RecordReadThread { 131 public: 132 RecordReadThread(size_t record_buffer_size, const perf_event_attr& attr, size_t min_mmap_pages, 133 size_t max_mmap_pages, size_t aux_buffer_size, bool allow_cutting_samples = true, 134 bool exclude_perf = false); 135 ~RecordReadThread(); SetBufferLevels(size_t record_buffer_low_level,size_t record_buffer_critical_level)136 void SetBufferLevels(size_t record_buffer_low_level, size_t record_buffer_critical_level) { 137 record_buffer_low_level_ = record_buffer_low_level; 138 record_buffer_critical_level_ = record_buffer_critical_level; 139 } 140 141 // Below functions are called in the main thread: 142 143 // When there are records in the RecordBuffer, data_callback will be called in the main thread. 144 bool RegisterDataCallback(IOEventLoop& loop, const std::function<bool()>& data_callback); 145 // Create and read kernel buffers for new event fds. 146 bool AddEventFds(const std::vector<EventFd*>& event_fds); 147 // Destroy kernel buffers of existing event fds. 148 bool RemoveEventFds(const std::vector<EventFd*>& event_fds); 149 // Move all available records in kernel buffers to the RecordBuffer. 150 bool SyncKernelBuffer(); 151 // Stop the read thread, no more records will be put into the RecordBuffer. 152 bool StopReadThread(); 153 154 // If available, return the next record in the RecordBuffer, otherwise return nullptr. 155 std::unique_ptr<Record> GetRecord(); 156 GetStat()157 const RecordStat& GetStat() const { return stat_; } 158 159 private: 160 enum Cmd { 161 NO_CMD, 162 CMD_ADD_EVENT_FDS, 163 CMD_REMOVE_EVENT_FDS, 164 CMD_SYNC_KERNEL_BUFFER, 165 CMD_STOP_THREAD, 166 }; 167 168 bool SendCmdToReadThread(Cmd cmd, void* cmd_arg); 169 170 // Below functions are called in the read thread: 171 172 void RunReadThread(); 173 void IncreaseThreadPriority(); 174 Cmd GetCmd(); 175 bool HandleCmd(IOEventLoop& loop); 176 bool HandleAddEventFds(IOEventLoop& loop, const std::vector<EventFd*>& event_fds); 177 bool HandleRemoveEventFds(const std::vector<EventFd*>& event_fds); 178 bool ReadRecordsFromKernelBuffer(); 179 void PushRecordToRecordBuffer(KernelRecordReader* kernel_record_reader); 180 void ReadAuxDataFromKernelBuffer(bool* has_data); 181 bool SendDataNotificationToMainThread(); 182 183 RecordBuffer record_buffer_; 184 // When free size in record buffer is below low level, we cut stack data of sample records to 1K. 185 size_t record_buffer_low_level_; 186 // When free size in record buffer is below critical level, we drop sample records to avoid 187 // losing more important records (like mmap or fork records). 188 size_t record_buffer_critical_level_; 189 RecordParser record_parser_; 190 perf_event_attr attr_; 191 size_t stack_size_in_sample_record_ = 0; 192 size_t min_mmap_pages_; 193 size_t max_mmap_pages_; 194 size_t aux_buffer_size_; 195 196 // Used to pass command notification from the main thread to the read thread. 197 android::base::unique_fd write_cmd_fd_; 198 android::base::unique_fd read_cmd_fd_; 199 std::mutex cmd_mutex_; 200 std::condition_variable cmd_finish_cond_; 201 Cmd cmd_; 202 void* cmd_arg_; 203 bool cmd_result_; 204 205 // Used to send data notification from the read thread to the main thread. 206 android::base::unique_fd write_data_fd_; 207 android::base::unique_fd read_data_fd_; 208 std::atomic_bool has_data_notification_; 209 210 std::unique_ptr<std::thread> read_thread_; 211 std::vector<KernelRecordReader> kernel_record_readers_; 212 pid_t exclude_pid_ = -1; 213 214 std::unordered_set<EventFd*> event_fds_disabled_by_kernel_; 215 216 RecordStat stat_; 217 }; 218 219 } // namespace simpleperf 220