1 // Copyright 2015 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef BASE_TRACE_EVENT_MEMORY_DUMP_MANAGER_H_ 6 #define BASE_TRACE_EVENT_MEMORY_DUMP_MANAGER_H_ 7 8 #include <stdint.h> 9 10 #include <map> 11 #include <memory> 12 #include <set> 13 #include <vector> 14 15 #include "base/atomicops.h" 16 #include "base/containers/hash_tables.h" 17 #include "base/macros.h" 18 #include "base/memory/ref_counted.h" 19 #include "base/memory/singleton.h" 20 #include "base/synchronization/lock.h" 21 #include "base/timer/timer.h" 22 #include "base/trace_event/memory_dump_request_args.h" 23 #include "base/trace_event/process_memory_dump.h" 24 #include "base/trace_event/trace_event.h" 25 26 namespace base { 27 28 class SingleThreadTaskRunner; 29 class Thread; 30 31 namespace trace_event { 32 33 class MemoryDumpManagerDelegate; 34 class MemoryDumpProvider; 35 class MemoryDumpSessionState; 36 37 // This is the interface exposed to the rest of the codebase to deal with 38 // memory tracing. The main entry point for clients is represented by 39 // RequestDumpPoint(). The extension by Un(RegisterDumpProvider). 40 class BASE_EXPORT MemoryDumpManager : public TraceLog::EnabledStateObserver { 41 public: 42 static const char* const kTraceCategory; 43 static const char* const kLogPrefix; 44 45 // This value is returned as the tracing id of the child processes by 46 // GetTracingProcessId() when tracing is not enabled. 47 static const uint64_t kInvalidTracingProcessId; 48 49 static MemoryDumpManager* GetInstance(); 50 51 // Invoked once per process to listen to trace begin / end events. 52 // Initialization can happen after (Un)RegisterMemoryDumpProvider() calls 53 // and the MemoryDumpManager guarantees to support this. 54 // On the other side, the MemoryDumpManager will not be fully operational 55 // (i.e. will NACK any RequestGlobalMemoryDump()) until initialized. 56 // Arguments: 57 // is_coordinator: if true this MemoryDumpManager instance will act as a 58 // coordinator and schedule periodic dumps (if enabled via TraceConfig); 59 // false when the MemoryDumpManager is initialized in a slave process. 60 // delegate: inversion-of-control interface for embedder-specific behaviors 61 // (multiprocess handshaking). See the lifetime and thread-safety 62 // requirements in the |MemoryDumpManagerDelegate| docstring. 63 void Initialize(MemoryDumpManagerDelegate* delegate, bool is_coordinator); 64 65 // (Un)Registers a MemoryDumpProvider instance. 66 // Args: 67 // - mdp: the MemoryDumpProvider instance to be registered. MemoryDumpManager 68 // does NOT take memory ownership of |mdp|, which is expected to either 69 // be a singleton or unregister itself. 70 // - name: a friendly name (duplicates allowed). Used for debugging and 71 // run-time profiling of memory-infra internals. Must be a long-lived 72 // C string. 73 // - task_runner: either a SingleThreadTaskRunner or SequencedTaskRunner. All 74 // the calls to |mdp| will be run on the given |task_runner|. If passed 75 // null |mdp| should be able to handle calls on arbitrary threads. 76 // - options: extra optional arguments. See memory_dump_provider.h. 77 void RegisterDumpProvider(MemoryDumpProvider* mdp, 78 const char* name, 79 scoped_refptr<SingleThreadTaskRunner> task_runner); 80 void RegisterDumpProvider(MemoryDumpProvider* mdp, 81 const char* name, 82 scoped_refptr<SingleThreadTaskRunner> task_runner, 83 MemoryDumpProvider::Options options); 84 void RegisterDumpProviderWithSequencedTaskRunner( 85 MemoryDumpProvider* mdp, 86 const char* name, 87 scoped_refptr<SequencedTaskRunner> task_runner, 88 MemoryDumpProvider::Options options); 89 void UnregisterDumpProvider(MemoryDumpProvider* mdp); 90 91 // Unregisters an unbound dump provider and takes care about its deletion 92 // asynchronously. Can be used only for for dump providers with no 93 // task-runner affinity. 94 // This method takes ownership of the dump provider and guarantees that: 95 // - The |mdp| will be deleted at some point in the near future. 96 // - Its deletion will not happen concurrently with the OnMemoryDump() call. 97 // Note that OnMemoryDump() calls can still happen after this method returns. 98 void UnregisterAndDeleteDumpProviderSoon( 99 std::unique_ptr<MemoryDumpProvider> mdp); 100 101 // Requests a memory dump. The dump might happen or not depending on the 102 // filters and categories specified when enabling tracing. 103 // The optional |callback| is executed asynchronously, on an arbitrary thread, 104 // to notify about the completion of the global dump (i.e. after all the 105 // processes have dumped) and its success (true iff all the dumps were 106 // successful). 107 void RequestGlobalDump(MemoryDumpType dump_type, 108 MemoryDumpLevelOfDetail level_of_detail, 109 const MemoryDumpCallback& callback); 110 111 // Same as above (still asynchronous), but without callback. 112 void RequestGlobalDump(MemoryDumpType dump_type, 113 MemoryDumpLevelOfDetail level_of_detail); 114 115 // TraceLog::EnabledStateObserver implementation. 116 void OnTraceLogEnabled() override; 117 void OnTraceLogDisabled() override; 118 119 // Returns true if the dump mode is allowed for current tracing session. 120 bool IsDumpModeAllowed(MemoryDumpLevelOfDetail dump_mode); 121 122 // Returns the MemoryDumpSessionState object, which is shared by all the 123 // ProcessMemoryDump and MemoryAllocatorDump instances through all the tracing 124 // session lifetime. session_state_for_testing()125 const scoped_refptr<MemoryDumpSessionState>& session_state_for_testing() 126 const { 127 return session_state_; 128 } 129 130 // Returns a unique id for identifying the processes. The id can be 131 // retrieved by child processes only when tracing is enabled. This is 132 // intended to express cross-process sharing of memory dumps on the 133 // child-process side, without having to know its own child process id. 134 uint64_t GetTracingProcessId() const; 135 136 // Returns the name for a the allocated_objects dump. Use this to declare 137 // suballocator dumps from other dump providers. 138 // It will return nullptr if there is no dump provider for the system 139 // allocator registered (which is currently the case for Mac OS). system_allocator_pool_name()140 const char* system_allocator_pool_name() const { 141 return kSystemAllocatorPoolName; 142 }; 143 144 // When set to true, calling |RegisterMemoryDumpProvider| is a no-op. set_dumper_registrations_ignored_for_testing(bool ignored)145 void set_dumper_registrations_ignored_for_testing(bool ignored) { 146 dumper_registrations_ignored_for_testing_ = ignored; 147 } 148 149 private: 150 friend std::default_delete<MemoryDumpManager>; // For the testing instance. 151 friend struct DefaultSingletonTraits<MemoryDumpManager>; 152 friend class MemoryDumpManagerDelegate; 153 friend class MemoryDumpManagerTest; 154 155 // Descriptor used to hold information about registered MDPs. 156 // Some important considerations about lifetime of this object: 157 // - In nominal conditions, all the MemoryDumpProviderInfo instances live in 158 // the |dump_providers_| collection (% unregistration while dumping). 159 // - Upon each dump they (actually their scoped_refptr-s) are copied into 160 // the ProcessMemoryDumpAsyncState. This is to allow removal (see below). 161 // - When the MDP.OnMemoryDump() is invoked, the corresponding MDPInfo copy 162 // inside ProcessMemoryDumpAsyncState is removed. 163 // - In most cases, the MDPInfo is destroyed within UnregisterDumpProvider(). 164 // - If UnregisterDumpProvider() is called while a dump is in progress, the 165 // MDPInfo is destroyed in SetupNextMemoryDump() or InvokeOnMemoryDump(), 166 // when the copy inside ProcessMemoryDumpAsyncState is erase()-d. 167 // - The non-const fields of MemoryDumpProviderInfo are safe to access only 168 // on tasks running in the |task_runner|, unless the thread has been 169 // destroyed. 170 struct MemoryDumpProviderInfo 171 : public RefCountedThreadSafe<MemoryDumpProviderInfo> { 172 // Define a total order based on the |task_runner| affinity, so that MDPs 173 // belonging to the same SequencedTaskRunner are adjacent in the set. 174 struct Comparator { 175 bool operator()(const scoped_refptr<MemoryDumpProviderInfo>& a, 176 const scoped_refptr<MemoryDumpProviderInfo>& b) const; 177 }; 178 using OrderedSet = 179 std::set<scoped_refptr<MemoryDumpProviderInfo>, Comparator>; 180 181 MemoryDumpProviderInfo(MemoryDumpProvider* dump_provider, 182 const char* name, 183 scoped_refptr<SequencedTaskRunner> task_runner, 184 const MemoryDumpProvider::Options& options, 185 bool whitelisted_for_background_mode); 186 187 MemoryDumpProvider* const dump_provider; 188 189 // Used to transfer ownership for UnregisterAndDeleteDumpProviderSoon(). 190 // nullptr in all other cases. 191 std::unique_ptr<MemoryDumpProvider> owned_dump_provider; 192 193 // Human readable name, for debugging and testing. Not necessarily unique. 194 const char* const name; 195 196 // The task runner affinity. Can be nullptr, in which case the dump provider 197 // will be invoked on |dump_thread_|. 198 const scoped_refptr<SequencedTaskRunner> task_runner; 199 200 // The |options| arg passed to RegisterDumpProvider(). 201 const MemoryDumpProvider::Options options; 202 203 // For fail-safe logic (auto-disable failing MDPs). 204 int consecutive_failures; 205 206 // Flagged either by the auto-disable logic or during unregistration. 207 bool disabled; 208 209 // True if the dump provider is whitelisted for background mode. 210 const bool whitelisted_for_background_mode; 211 212 private: 213 friend class base::RefCountedThreadSafe<MemoryDumpProviderInfo>; 214 ~MemoryDumpProviderInfo(); 215 216 DISALLOW_COPY_AND_ASSIGN(MemoryDumpProviderInfo); 217 }; 218 219 // Holds the state of a process memory dump that needs to be carried over 220 // across task runners in order to fulfil an asynchronous CreateProcessDump() 221 // request. At any time exactly one task runner owns a 222 // ProcessMemoryDumpAsyncState. 223 struct ProcessMemoryDumpAsyncState { 224 ProcessMemoryDumpAsyncState( 225 MemoryDumpRequestArgs req_args, 226 const MemoryDumpProviderInfo::OrderedSet& dump_providers, 227 scoped_refptr<MemoryDumpSessionState> session_state, 228 MemoryDumpCallback callback, 229 scoped_refptr<SingleThreadTaskRunner> dump_thread_task_runner); 230 ~ProcessMemoryDumpAsyncState(); 231 232 // Gets or creates the memory dump container for the given target process. 233 ProcessMemoryDump* GetOrCreateMemoryDumpContainerForProcess( 234 ProcessId pid, 235 const MemoryDumpArgs& dump_args); 236 237 // A map of ProcessId -> ProcessMemoryDump, one for each target process 238 // being dumped from the current process. Typically each process dumps only 239 // for itself, unless dump providers specify a different |target_process| in 240 // MemoryDumpProvider::Options. 241 std::map<ProcessId, std::unique_ptr<ProcessMemoryDump>> process_dumps; 242 243 // The arguments passed to the initial CreateProcessDump() request. 244 const MemoryDumpRequestArgs req_args; 245 246 // An ordered sequence of dump providers that have to be invoked to complete 247 // the dump. This is a copy of |dump_providers_| at the beginning of a dump 248 // and becomes empty at the end, when all dump providers have been invoked. 249 std::vector<scoped_refptr<MemoryDumpProviderInfo>> pending_dump_providers; 250 251 // The trace-global session state. 252 scoped_refptr<MemoryDumpSessionState> session_state; 253 254 // Callback passed to the initial call to CreateProcessDump(). 255 MemoryDumpCallback callback; 256 257 // The |success| field that will be passed as argument to the |callback|. 258 bool dump_successful; 259 260 // The thread on which FinalizeDumpAndAddToTrace() (and hence |callback|) 261 // should be invoked. This is the thread on which the initial 262 // CreateProcessDump() request was called. 263 const scoped_refptr<SingleThreadTaskRunner> callback_task_runner; 264 265 // The thread on which unbound dump providers should be invoked. 266 // This is essentially |dump_thread_|.task_runner() but needs to be kept 267 // as a separate variable as it needs to be accessed by arbitrary dumpers' 268 // threads outside of the lock_ to avoid races when disabling tracing. 269 // It is immutable for all the duration of a tracing session. 270 const scoped_refptr<SingleThreadTaskRunner> dump_thread_task_runner; 271 272 private: 273 DISALLOW_COPY_AND_ASSIGN(ProcessMemoryDumpAsyncState); 274 }; 275 276 // Sets up periodic memory dump timers to start global dump requests based on 277 // the dump triggers from trace config. 278 class BASE_EXPORT PeriodicGlobalDumpTimer { 279 public: 280 PeriodicGlobalDumpTimer(); 281 ~PeriodicGlobalDumpTimer(); 282 283 void Start(const std::vector<TraceConfig::MemoryDumpConfig::Trigger>& 284 triggers_list); 285 void Stop(); 286 287 bool IsRunning(); 288 289 private: 290 // Periodically called by the timer. 291 void RequestPeriodicGlobalDump(); 292 293 RepeatingTimer timer_; 294 uint32_t periodic_dumps_count_; 295 uint32_t light_dump_rate_; 296 uint32_t heavy_dump_rate_; 297 298 DISALLOW_COPY_AND_ASSIGN(PeriodicGlobalDumpTimer); 299 }; 300 301 static const int kMaxConsecutiveFailuresCount; 302 static const char* const kSystemAllocatorPoolName; 303 304 MemoryDumpManager(); 305 ~MemoryDumpManager() override; 306 307 static void SetInstanceForTesting(MemoryDumpManager* instance); 308 static void FinalizeDumpAndAddToTrace( 309 std::unique_ptr<ProcessMemoryDumpAsyncState> pmd_async_state); 310 311 // Enable heap profiling if kEnableHeapProfiling is specified. 312 void EnableHeapProfilingIfNeeded(); 313 314 // Internal, used only by MemoryDumpManagerDelegate. 315 // Creates a memory dump for the current process and appends it to the trace. 316 // |callback| will be invoked asynchronously upon completion on the same 317 // thread on which CreateProcessDump() was called. 318 void CreateProcessDump(const MemoryDumpRequestArgs& args, 319 const MemoryDumpCallback& callback); 320 321 // Calls InvokeOnMemoryDump() for the next MDP on the task runner specified by 322 // the MDP while registration. On failure to do so, skips and continues to 323 // next MDP. 324 void SetupNextMemoryDump( 325 std::unique_ptr<ProcessMemoryDumpAsyncState> pmd_async_state); 326 327 // Invokes OnMemoryDump() of the next MDP and calls SetupNextMemoryDump() at 328 // the end to continue the ProcessMemoryDump. Should be called on the MDP task 329 // runner. 330 void InvokeOnMemoryDump(ProcessMemoryDumpAsyncState* owned_pmd_async_state); 331 332 // Helper for RegierDumpProvider* functions. 333 void RegisterDumpProviderInternal( 334 MemoryDumpProvider* mdp, 335 const char* name, 336 scoped_refptr<SequencedTaskRunner> task_runner, 337 const MemoryDumpProvider::Options& options); 338 339 // Helper for the public UnregisterDumpProvider* functions. 340 void UnregisterDumpProviderInternal(MemoryDumpProvider* mdp, 341 bool take_mdp_ownership_and_delete_async); 342 343 // An ordererd set of registered MemoryDumpProviderInfo(s), sorted by task 344 // runner affinity (MDPs belonging to the same task runners are adjacent). 345 MemoryDumpProviderInfo::OrderedSet dump_providers_; 346 347 // Shared among all the PMDs to keep state scoped to the tracing session. 348 scoped_refptr<MemoryDumpSessionState> session_state_; 349 350 MemoryDumpManagerDelegate* delegate_; // Not owned. 351 352 // When true, this instance is in charge of coordinating periodic dumps. 353 bool is_coordinator_; 354 355 // Protects from concurrent accesses to the |dump_providers_*| and |delegate_| 356 // to guard against disabling logging while dumping on another thread. 357 Lock lock_; 358 359 // Optimization to avoid attempting any memory dump (i.e. to not walk an empty 360 // dump_providers_enabled_ list) when tracing is not enabled. 361 subtle::AtomicWord memory_tracing_enabled_; 362 363 // For time-triggered periodic dumps. 364 PeriodicGlobalDumpTimer periodic_dump_timer_; 365 366 // Thread used for MemoryDumpProviders which don't specify a task runner 367 // affinity. 368 std::unique_ptr<Thread> dump_thread_; 369 370 // The unique id of the child process. This is created only for tracing and is 371 // expected to be valid only when tracing is enabled. 372 uint64_t tracing_process_id_; 373 374 // When true, calling |RegisterMemoryDumpProvider| is a no-op. 375 bool dumper_registrations_ignored_for_testing_; 376 377 // Whether new memory dump providers should be told to enable heap profiling. 378 bool heap_profiling_enabled_; 379 380 DISALLOW_COPY_AND_ASSIGN(MemoryDumpManager); 381 }; 382 383 // The delegate is supposed to be long lived (read: a Singleton) and thread 384 // safe (i.e. should expect calls from any thread and handle thread hopping). 385 class BASE_EXPORT MemoryDumpManagerDelegate { 386 public: 387 virtual void RequestGlobalMemoryDump(const MemoryDumpRequestArgs& args, 388 const MemoryDumpCallback& callback) = 0; 389 390 // Returns tracing process id of the current process. This is used by 391 // MemoryDumpManager::GetTracingProcessId. 392 virtual uint64_t GetTracingProcessId() const = 0; 393 394 protected: 395 MemoryDumpManagerDelegate() {} 396 virtual ~MemoryDumpManagerDelegate() {} 397 398 void CreateProcessDump(const MemoryDumpRequestArgs& args, 399 const MemoryDumpCallback& callback) { 400 MemoryDumpManager::GetInstance()->CreateProcessDump(args, callback); 401 } 402 403 private: 404 DISALLOW_COPY_AND_ASSIGN(MemoryDumpManagerDelegate); 405 }; 406 407 } // namespace trace_event 408 } // namespace base 409 410 #endif // BASE_TRACE_EVENT_MEMORY_DUMP_MANAGER_H_ 411