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