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_HEAPPROFD_PRODUCER_H_ 18 #define SRC_PROFILING_MEMORY_HEAPPROFD_PRODUCER_H_ 19 20 #include <array> 21 #include <functional> 22 #include <map> 23 #include <vector> 24 25 #include <inttypes.h> 26 27 #include "perfetto/base/task_runner.h" 28 #include "perfetto/ext/base/optional.h" 29 #include "perfetto/ext/base/unix_socket.h" 30 #include "perfetto/ext/base/unix_task_runner.h" 31 32 #include "perfetto/ext/tracing/core/basic_types.h" 33 #include "perfetto/ext/tracing/core/producer.h" 34 #include "perfetto/ext/tracing/core/trace_writer.h" 35 #include "perfetto/ext/tracing/core/tracing_service.h" 36 #include "perfetto/tracing/core/data_source_config.h" 37 38 #include "perfetto/tracing/core/forward_decls.h" 39 #include "src/profiling/common/interning_output.h" 40 #include "src/profiling/common/proc_utils.h" 41 #include "src/profiling/common/profiler_guardrails.h" 42 #include "src/profiling/memory/bookkeeping.h" 43 #include "src/profiling/memory/bookkeeping_dump.h" 44 #include "src/profiling/memory/log_histogram.h" 45 #include "src/profiling/memory/shared_ring_buffer.h" 46 #include "src/profiling/memory/system_property.h" 47 #include "src/profiling/memory/unwinding.h" 48 #include "src/profiling/memory/unwound_messages.h" 49 50 #include "protos/perfetto/config/profiling/heapprofd_config.gen.h" 51 52 namespace perfetto { 53 namespace profiling { 54 55 using HeapprofdConfig = protos::gen::HeapprofdConfig; 56 57 struct Process { 58 pid_t pid; 59 std::string cmdline; 60 }; 61 62 // TODO(rsavitski): central daemon can do less work if it knows that the global 63 // operating mode is fork-based, as it then will not be interacting with the 64 // clients. This can be implemented as an additional mode here. 65 enum class HeapprofdMode { kCentral, kChild }; 66 67 bool HeapprofdConfigToClientConfiguration( 68 const HeapprofdConfig& heapprofd_config, 69 ClientConfiguration* cli_config); 70 71 // Heap profiling producer. Can be instantiated in two modes, central and 72 // child (also referred to as fork mode). 73 // 74 // The central mode producer is instantiated by the system heapprofd daemon. Its 75 // primary responsibility is activating profiling (via system properties and 76 // signals) in targets identified by profiling configs. On debug platform 77 // builds, the central producer can also handle the out-of-process unwinding & 78 // writing of the profiles for all client processes. 79 // 80 // An alternative model is where the central heapprofd triggers the profiling in 81 // the target process, but the latter fork-execs a private heapprofd binary to 82 // handle unwinding only for that process. The forked heapprofd instantiates 83 // this producer in the "child" mode. In this scenario, the profiled process 84 // never talks to the system daemon. 85 // 86 // TODO(fmayer||rsavitski): cover interesting invariants/structure of the 87 // implementation (e.g. number of data sources in child mode), including 88 // threading structure. 89 class HeapprofdProducer : public Producer, public UnwindingWorker::Delegate { 90 public: 91 friend class SocketDelegate; 92 93 // TODO(fmayer): Split into two delegates for the listening socket in kCentral 94 // and for the per-client sockets to make this easier to understand? 95 // Alternatively, find a better name for this. 96 class SocketDelegate : public base::UnixSocket::EventListener { 97 public: SocketDelegate(HeapprofdProducer * producer)98 explicit SocketDelegate(HeapprofdProducer* producer) 99 : producer_(producer) {} 100 101 void OnDisconnect(base::UnixSocket* self) override; 102 void OnNewIncomingConnection( 103 base::UnixSocket* self, 104 std::unique_ptr<base::UnixSocket> new_connection) override; 105 void OnDataAvailable(base::UnixSocket* self) override; 106 107 private: 108 HeapprofdProducer* producer_; 109 }; 110 111 HeapprofdProducer(HeapprofdMode mode, 112 base::TaskRunner* task_runner, 113 bool exit_when_done); 114 ~HeapprofdProducer() override; 115 116 // Producer Impl: 117 void OnConnect() override; 118 void OnDisconnect() override; 119 void SetupDataSource(DataSourceInstanceID, const DataSourceConfig&) override; 120 void StartDataSource(DataSourceInstanceID, const DataSourceConfig&) override; 121 void StopDataSource(DataSourceInstanceID) override; 122 void OnTracingSetup() override; 123 void Flush(FlushRequestID, 124 const DataSourceInstanceID* data_source_ids, 125 size_t num_data_sources) override; ClearIncrementalState(const DataSourceInstanceID *,size_t)126 void ClearIncrementalState(const DataSourceInstanceID* /*data_source_ids*/, 127 size_t /*num_data_sources*/) override {} 128 129 // TODO(fmayer): Refactor once/if we have generic reconnect logic. 130 void ConnectWithRetries(const char* socket_name); 131 void DumpAll(); 132 133 // UnwindingWorker::Delegate impl: 134 void PostAllocRecord(UnwindingWorker*, std::unique_ptr<AllocRecord>) override; 135 void PostFreeRecord(UnwindingWorker*, std::vector<FreeRecord>) override; 136 void PostHeapNameRecord(UnwindingWorker*, HeapNameRecord) override; 137 void PostSocketDisconnected(UnwindingWorker*, 138 DataSourceInstanceID, 139 pid_t, 140 SharedRingBuffer::Stats) override; 141 142 void HandleAllocRecord(AllocRecord*); 143 void HandleFreeRecord(FreeRecord); 144 void HandleHeapNameRecord(HeapNameRecord); 145 void HandleSocketDisconnected(DataSourceInstanceID, 146 pid_t, 147 SharedRingBuffer::Stats); 148 149 // Valid only if mode_ == kChild. 150 void SetTargetProcess(pid_t target_pid, std::string target_cmdline); 151 void SetDataSourceCallback(std::function<void()> fn); 152 153 // Exposed for testing. 154 void SetProducerEndpoint( 155 std::unique_ptr<TracingService::ProducerEndpoint> endpoint); 156 socket_delegate()157 base::UnixSocket::EventListener& socket_delegate() { 158 return socket_delegate_; 159 } 160 161 // Adopts the (connected) sockets inherited from the target process, invoking 162 // the on-connection callback. 163 // Specific to mode_ == kChild 164 void AdoptSocket(base::ScopedFile fd); 165 166 void TerminateWhenDone(); 167 168 private: 169 // State of the connection to tracing service (traced). 170 enum State { 171 kNotStarted = 0, 172 kNotConnected, 173 kConnecting, 174 kConnected, 175 }; 176 177 struct ProcessState { 178 struct HeapInfo { HeapInfoProcessState::HeapInfo179 HeapInfo(GlobalCallstackTrie* cs, bool dam) : heap_tracker(cs, dam) {} 180 181 HeapTracker heap_tracker; 182 std::string heap_name; 183 uint64_t sampling_interval = 0u; 184 uint64_t orig_sampling_interval = 0u; 185 }; ProcessStateProcessState186 ProcessState(GlobalCallstackTrie* c, bool d) 187 : callsites(c), dump_at_max_mode(d) {} 188 bool disconnected = false; 189 SharedRingBuffer::ErrorState error_state = 190 SharedRingBuffer::ErrorState::kNoError; 191 bool buffer_corrupted = false; 192 193 uint64_t heap_samples = 0; 194 uint64_t map_reparses = 0; 195 uint64_t unwinding_errors = 0; 196 197 uint64_t total_unwinding_time_us = 0; 198 uint64_t client_spinlock_blocked_us = 0; 199 GlobalCallstackTrie* callsites; 200 bool dump_at_max_mode; 201 LogHistogram unwinding_time_us; 202 std::map<uint32_t, HeapInfo> heap_infos; 203 GetHeapInfoProcessState204 HeapInfo& GetHeapInfo(uint32_t heap_id) { 205 auto it = heap_infos.find(heap_id); 206 if (it == heap_infos.end()) { 207 std::tie(it, std::ignore) = heap_infos.emplace( 208 std::piecewise_construct, std::forward_as_tuple(heap_id), 209 std::forward_as_tuple(callsites, dump_at_max_mode)); 210 } 211 return it->second; 212 } 213 GetHeapTrackerProcessState214 HeapTracker& GetHeapTracker(uint32_t heap_id) { 215 return GetHeapInfo(heap_id).heap_tracker; 216 } 217 }; 218 219 struct DataSource { DataSourceDataSource220 explicit DataSource(std::unique_ptr<TraceWriter> tw) 221 : trace_writer(std::move(tw)) { 222 // Make MSAN happy. 223 memset(&client_configuration, 0, sizeof(client_configuration)); 224 } 225 226 DataSourceInstanceID id; 227 std::unique_ptr<TraceWriter> trace_writer; 228 DataSourceConfig ds_config; 229 HeapprofdConfig config; 230 ClientConfiguration client_configuration; 231 std::vector<SystemProperties::Handle> properties; 232 std::set<pid_t> signaled_pids; 233 std::set<pid_t> rejected_pids; 234 std::map<pid_t, ProcessState> process_states; 235 std::vector<std::string> normalized_cmdlines; 236 InterningOutputTracker intern_state; 237 bool shutting_down = false; 238 bool started = false; 239 bool hit_guardrail = false; 240 bool was_stopped = false; 241 uint32_t stop_timeout_ms; 242 GuardrailConfig guardrail_config; 243 }; 244 245 struct PendingProcess { 246 std::unique_ptr<base::UnixSocket> sock; 247 DataSourceInstanceID data_source_instance_id; 248 SharedRingBuffer shmem; 249 }; 250 251 void HandleClientConnection(std::unique_ptr<base::UnixSocket> new_connection, 252 Process process); 253 254 void ConnectService(); 255 void Restart(); 256 void ResetConnectionBackoff(); 257 void IncreaseConnectionBackoff(); 258 259 void CheckDataSourceMemoryTask(); 260 void CheckDataSourceCpuTask(); 261 262 void FinishDataSourceFlush(FlushRequestID flush_id); 263 void DumpProcessesInDataSource(DataSource* ds); 264 void DumpProcessState(DataSource* ds, pid_t pid, ProcessState* process); 265 static void SetStats(protos::pbzero::ProfilePacket::ProcessStats* stats, 266 const ProcessState& process_state); 267 268 void DoContinuousDump(DataSourceInstanceID id, uint32_t dump_interval); 269 270 UnwindingWorker& UnwinderForPID(pid_t); 271 bool IsPidProfiled(pid_t); 272 DataSource* GetDataSourceForProcess(const Process& proc); 273 void RecordOtherSourcesAsRejected(DataSource* active_ds, const Process& proc); 274 275 void SetStartupProperties(DataSource* data_source); 276 void SignalRunningProcesses(DataSource* data_source); 277 278 // Specific to mode_ == kChild 279 void TerminateProcess(int exit_status); 280 // Specific to mode_ == kChild 281 void ActiveDataSourceWatchdogCheck(); 282 283 void ShutdownDataSource(DataSource* ds); 284 bool MaybeFinishDataSource(DataSource* ds); 285 286 void WriteRejectedConcurrentSession(BufferID buffer_id, pid_t pid); 287 288 // Class state: 289 290 // Task runner is owned by the main thread. 291 base::TaskRunner* const task_runner_; 292 const HeapprofdMode mode_; 293 // TODO(fmayer): Refactor to make this boolean unnecessary. 294 // Whether to terminate this producer after the first data-source has 295 // finished. 296 bool exit_when_done_; 297 298 // State of connection to the tracing service. 299 State state_ = kNotStarted; 300 uint32_t connection_backoff_ms_ = 0; 301 const char* producer_sock_name_ = nullptr; 302 303 // Client processes that have connected, but with which we have not yet 304 // finished the handshake. 305 std::map<pid_t, PendingProcess> pending_processes_; 306 307 // Must outlive data_sources_ - owns at least the shared memory referenced by 308 // TraceWriters. 309 std::unique_ptr<TracingService::ProducerEndpoint> endpoint_; 310 311 // Must outlive data_sources_ - HeapTracker references the trie. 312 GlobalCallstackTrie callsites_; 313 314 // Must outlive data_sources_ - DataSource can hold 315 // SystemProperties::Handle-s. 316 // Specific to mode_ == kCentral 317 SystemProperties properties_; 318 319 std::map<FlushRequestID, size_t> flushes_in_progress_; 320 std::map<DataSourceInstanceID, DataSource> data_sources_; 321 std::vector<UnwindingWorker> unwinding_workers_; 322 323 // Specific to mode_ == kChild 324 Process target_process_{base::kInvalidPid, ""}; 325 base::Optional<std::function<void()>> data_source_callback_; 326 327 SocketDelegate socket_delegate_; 328 329 base::WeakPtrFactory<HeapprofdProducer> weak_factory_; // Keep last. 330 }; 331 332 } // namespace profiling 333 } // namespace perfetto 334 335 #endif // SRC_PROFILING_MEMORY_HEAPPROFD_PRODUCER_H_ 336