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