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