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