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