xref: /aosp_15_r20/external/perfetto/src/profiling/memory/client.h (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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 #ifndef SRC_PROFILING_MEMORY_CLIENT_H_
18 #define SRC_PROFILING_MEMORY_CLIENT_H_
19 
20 #include <stddef.h>
21 #include <sys/types.h>
22 
23 #include <atomic>
24 #include <condition_variable>
25 #include <mutex>
26 #include <vector>
27 
28 #include <unwindstack/Arch.h>
29 
30 #include "perfetto/base/build_config.h"
31 #include "perfetto/base/compiler.h"
32 #include "perfetto/ext/base/unix_socket.h"
33 #include "src/profiling/memory/sampler.h"
34 #include "src/profiling/memory/shared_ring_buffer.h"
35 #include "src/profiling/memory/unhooked_allocator.h"
36 #include "src/profiling/memory/wire_protocol.h"
37 
38 namespace perfetto {
39 namespace profiling {
40 
41 struct StackRange {
42   const char* begin;
43   // One past the highest address part of the stack.
44   const char* end;
45 };
46 
47 StackRange GetThreadStackRange();
48 StackRange GetSigAltStackRange();
49 StackRange GetMainThreadStackRange();
50 
51 constexpr uint64_t kInfiniteTries = 0;
52 constexpr uint32_t kClientSockTimeoutMs = 1000;
53 
54 uint64_t GetMaxTries(const ClientConfiguration& client_config);
55 
56 // Profiling client, used to sample and record the malloc/free family of calls,
57 // and communicate the necessary state to a separate profiling daemon process.
58 //
59 // Created and owned by the malloc hooks.
60 //
61 // Methods of this class are thread-safe unless otherwise stated, in which case
62 // the caller needs to synchronize calls behind a mutex or similar.
63 //
64 // Implementation warning: this class should not use any heap, as otherwise its
65 // destruction would enter the possibly-hooked |free|, which can reference the
66 // Client itself. If avoiding the heap is not possible, then look at using
67 // UnhookedAllocator.
68 class Client {
69  public:
70   // Returns a client that is ready for sampling allocations, using the given
71   // socket (which should already be connected to heapprofd).
72   //
73   // Returns a shared_ptr since that is how the client will ultimately be used,
74   // and to take advantage of std::allocate_shared putting the object & the
75   // control block in one block of memory.
76   static std::shared_ptr<Client> CreateAndHandshake(
77       base::UnixSocketRaw sock,
78       UnhookedAllocator<Client> unhooked_allocator);
79 
80   static std::optional<base::UnixSocketRaw> ConnectToHeapprofd(
81       const std::string& sock_name);
82 
83   bool RecordMalloc(uint32_t heap_id,
84                     uint64_t sample_size,
85                     uint64_t alloc_size,
86                     uint64_t alloc_address) PERFETTO_WARN_UNUSED_RESULT;
87 
88   // Add address to buffer of deallocations. Flushes the buffer if necessary.
89   bool RecordFree(uint32_t heap_id,
90                   uint64_t alloc_address) PERFETTO_WARN_UNUSED_RESULT;
91   bool RecordHeapInfo(uint32_t heap_id,
92                       const char* heap_name,
93                       uint64_t interval);
94 
AddClientSpinlockBlockedUs(size_t n)95   void AddClientSpinlockBlockedUs(size_t n) {
96     shmem_.AddClientSpinlockBlockedUs(n);
97   }
98 
99   // Public for std::allocate_shared. Use CreateAndHandshake() to create
100   // instances instead.
101   Client(base::UnixSocketRaw sock,
102          ClientConfiguration client_config,
103          SharedRingBuffer shmem,
104          pid_t pid_at_creation,
105          StackRange main_thread_stack_range);
106 
107   ~Client();
108 
client_config()109   const ClientConfiguration& client_config() { return client_config_; }
adaptive_sampling_shmem_threshold()110   uint64_t adaptive_sampling_shmem_threshold() {
111     return client_config_.adaptive_sampling_shmem_threshold;
112   }
adaptive_sampling_max_sampling_interval_bytes()113   uint64_t adaptive_sampling_max_sampling_interval_bytes() {
114     return client_config_.adaptive_sampling_max_sampling_interval_bytes;
115   }
write_avail()116   uint64_t write_avail() { return shmem_.write_avail(); }
117 
118   bool IsConnected();
119 
120  private:
121 #if PERFETTO_BUILDFLAG(PERFETTO_ARCH_CPU_RISCV) && \
122     !PERFETTO_HAS_BUILTIN_STACK_ADDRESS()
123   // For specific architectures, such as riscv, different calling conventions
124   // make a difference in the meaning of the frame pointer. (see comments in
125   // client.cc) So, we want to use other method to get the stack address for
126   // specific architectures such as riscv.
127   ssize_t GetStackRegister(unwindstack::ArchEnum arch);
128   uintptr_t GetStackAddress(char* reg_data, unwindstack::ArchEnum arch);
129 #endif
130   const char* GetStackEnd(const char* stacktop);
131   bool SendControlSocketByte() PERFETTO_WARN_UNUSED_RESULT;
132   int64_t SendWireMessageWithRetriesIfBlocking(const WireMessage&)
133       PERFETTO_WARN_UNUSED_RESULT;
134 
135   bool IsPostFork();
136 
137   ClientConfiguration client_config_;
138   uint64_t max_shmem_tries_;
139   base::UnixSocketRaw sock_;
140 
141   StackRange main_thread_stack_range_{nullptr, nullptr};
142   std::atomic<uint64_t>
143       sequence_number_[base::ArraySize(ClientConfiguration{}.heaps)] = {};
144   SharedRingBuffer shmem_;
145 
146   // Used to detect (during the slow path) the situation where the process has
147   // forked during profiling, and is performing malloc operations in the child.
148   // In this scenario, we want to stop profiling in the child, as otherwise
149   // it'll proceed to write to the same shared buffer & control socket (with
150   // duplicate sequence ids).
151   const pid_t pid_at_creation_;
152   bool detected_fork_ = false;
153   bool postfork_return_value_ = false;
154 };
155 
156 }  // namespace profiling
157 }  // namespace perfetto
158 
159 #endif  // SRC_PROFILING_MEMORY_CLIENT_H_
160