• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "perfetto/base/compiler.h"
29 #include "perfetto/ext/base/unix_socket.h"
30 #include "src/profiling/memory/sampler.h"
31 #include "src/profiling/memory/shared_ring_buffer.h"
32 #include "src/profiling/memory/unhooked_allocator.h"
33 #include "src/profiling/memory/wire_protocol.h"
34 
35 namespace perfetto {
36 namespace profiling {
37 
38 uint64_t GetMaxTries(const ClientConfiguration& client_config);
39 const char* GetThreadStackBase();
40 
41 constexpr uint64_t kInfiniteTries = 0;
42 constexpr uint32_t kClientSockTimeoutMs = 1000;
43 
44 // Profiling client, used to sample and record the malloc/free family of calls,
45 // and communicate the necessary state to a separate profiling daemon process.
46 //
47 // Created and owned by the malloc hooks.
48 //
49 // Methods of this class are thread-safe unless otherwise stated, in which case
50 // the caller needs to synchronize calls behind a mutex or similar.
51 //
52 // Implementation warning: this class should not use any heap, as otherwise its
53 // destruction would enter the possibly-hooked |free|, which can reference the
54 // Client itself. If avoiding the heap is not possible, then look at using
55 // UnhookedAllocator.
56 class Client {
57  public:
58   // Returns a client that is ready for sampling allocations, using the given
59   // socket (which should already be connected to heapprofd).
60   //
61   // Returns a shared_ptr since that is how the client will ultimately be used,
62   // and to take advantage of std::allocate_shared putting the object & the
63   // control block in one block of memory.
64   static std::shared_ptr<Client> CreateAndHandshake(
65       base::UnixSocketRaw sock,
66       UnhookedAllocator<Client> unhooked_allocator);
67 
68   static base::Optional<base::UnixSocketRaw> ConnectToHeapprofd(
69       const std::string& sock_name);
70 
71   bool RecordMalloc(uint64_t sample_size,
72                     uint64_t alloc_size,
73                     uint64_t alloc_address) PERFETTO_WARN_UNUSED_RESULT;
74 
75   // Add address to buffer of deallocations. Flushes the buffer if necessary.
76   bool RecordFree(uint64_t alloc_address) PERFETTO_WARN_UNUSED_RESULT;
77 
78   // Returns the number of bytes to assign to an allocation with the given
79   // |alloc_size|, based on the current sampling rate. A return value of zero
80   // means that the allocation should not be recorded. Not idempotent, each
81   // invocation mutates the sampler state.
82   //
83   // Not thread-safe.
GetSampleSizeLocked(size_t alloc_size)84   size_t GetSampleSizeLocked(size_t alloc_size) {
85     return sampler_.SampleSize(alloc_size);
86   }
87 
88   // Public for std::allocate_shared. Use CreateAndHandshake() to create
89   // instances instead.
90   Client(base::UnixSocketRaw sock,
91          ClientConfiguration client_config,
92          SharedRingBuffer shmem,
93          Sampler sampler,
94          pid_t pid_at_creation,
95          const char* main_thread_stack_base);
96 
97   ~Client();
98 
client_config_for_testing()99   ClientConfiguration client_config_for_testing() { return client_config_; }
100 
101  private:
102   const char* GetStackBase();
103   // Flush the contents of free_batch_. Must hold free_batch_lock_.
104   bool FlushFreesLocked() PERFETTO_WARN_UNUSED_RESULT;
105   bool SendControlSocketByte() PERFETTO_WARN_UNUSED_RESULT;
106   bool SendWireMessageWithRetriesIfBlocking(const WireMessage&)
107       PERFETTO_WARN_UNUSED_RESULT;
108 
109   bool IsPostFork();
110 
111   // This is only valid for non-blocking sockets. This is when
112   // client_config_.block_client is true.
113   bool IsConnected();
114 
115   ClientConfiguration client_config_;
116   uint64_t max_shmem_tries_;
117   // sampler_ operations are not thread-safe.
118   Sampler sampler_;
119   base::UnixSocketRaw sock_;
120 
121   // Protected by free_batch_lock_.
122   FreeBatch free_batch_;
123   std::timed_mutex free_batch_lock_;
124 
125   const char* main_thread_stack_base_{nullptr};
126   std::atomic<uint64_t> sequence_number_{0};
127   SharedRingBuffer shmem_;
128 
129   // Used to detect (during the slow path) the situation where the process has
130   // forked during profiling, and is performing malloc operations in the child.
131   // In this scenario, we want to stop profiling in the child, as otherwise
132   // it'll proceed to write to the same shared buffer & control socket (with
133   // duplicate sequence ids).
134   const pid_t pid_at_creation_;
135   bool detected_fork_ = false;
136   bool postfork_return_value_ = false;
137 };
138 
139 }  // namespace profiling
140 }  // namespace perfetto
141 
142 #endif  // SRC_PROFILING_MEMORY_CLIENT_H_
143