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 44 // This value is returned as the tracing id of the child processes by 45 // GetTracingProcessId() when tracing is not enabled. 46 static const uint64_t kInvalidTracingProcessId; 47 48 static MemoryDumpManager* GetInstance(); 49 50 // Invoked once per process to listen to trace begin / end events. 51 // Initialization can happen after (Un)RegisterMemoryDumpProvider() calls 52 // and the MemoryDumpManager guarantees to support this. 53 // On the other side, the MemoryDumpManager will not be fully operational 54 // (i.e. will NACK any RequestGlobalMemoryDump()) until initialized. 55 // Arguments: 56 // is_coordinator: if true this MemoryDumpManager instance will act as a 57 // coordinator and schedule periodic dumps (if enabled via TraceConfig); 58 // false when the MemoryDumpManager is initialized in a slave process. 59 // delegate: inversion-of-control interface for embedder-specific behaviors 60 // (multiprocess handshaking). See the lifetime and thread-safety 61 // requirements in the |MemoryDumpManagerDelegate| docstring. 62 void Initialize(MemoryDumpManagerDelegate* delegate, bool is_coordinator); 63 64 // (Un)Registers a MemoryDumpProvider instance. 65 // Args: 66 // - mdp: the MemoryDumpProvider instance to be registered. MemoryDumpManager 67 // does NOT take memory ownership of |mdp|, which is expected to either 68 // be a singleton or unregister itself. 69 // - name: a friendly name (duplicates allowed). Used for debugging and 70 // run-time profiling of memory-infra internals. Must be a long-lived 71 // C string. 72 // - task_runner: if non-null, all the calls to |mdp| will be 73 // issued on the given thread. Otherwise, |mdp| should be able to 74 // handle calls on arbitrary threads. 75 // - options: extra optional arguments. See memory_dump_provider.h. 76 void RegisterDumpProvider( 77 MemoryDumpProvider* mdp, 78 const char* name, 79 const scoped_refptr<SingleThreadTaskRunner>& task_runner); 80 void RegisterDumpProvider( 81 MemoryDumpProvider* mdp, 82 const char* name, 83 const scoped_refptr<SingleThreadTaskRunner>& task_runner, 84 const MemoryDumpProvider::Options& options); 85 void UnregisterDumpProvider(MemoryDumpProvider* mdp); 86 87 // Unregisters an unbound dump provider and takes care about its deletion 88 // asynchronously. Can be used only for for dump providers with no 89 // task-runner affinity. 90 // This method takes ownership of the dump provider and guarantees that: 91 // - The |mdp| will be deleted at some point in the near future. 92 // - Its deletion will not happen concurrently with the OnMemoryDump() call. 93 // Note that OnMemoryDump() calls can still happen after this method returns. 94 void UnregisterAndDeleteDumpProviderSoon(scoped_ptr<MemoryDumpProvider> mdp); 95 96 // Requests a memory dump. The dump might happen or not depending on the 97 // filters and categories specified when enabling tracing. 98 // The optional |callback| is executed asynchronously, on an arbitrary thread, 99 // to notify about the completion of the global dump (i.e. after all the 100 // processes have dumped) and its success (true iff all the dumps were 101 // successful). 102 void RequestGlobalDump(MemoryDumpType dump_type, 103 MemoryDumpLevelOfDetail level_of_detail, 104 const MemoryDumpCallback& callback); 105 106 // Same as above (still asynchronous), but without callback. 107 void RequestGlobalDump(MemoryDumpType dump_type, 108 MemoryDumpLevelOfDetail level_of_detail); 109 110 // TraceLog::EnabledStateObserver implementation. 111 void OnTraceLogEnabled() override; 112 void OnTraceLogDisabled() override; 113 114 // Returns the MemoryDumpSessionState object, which is shared by all the 115 // ProcessMemoryDump and MemoryAllocatorDump instances through all the tracing 116 // session lifetime. session_state()117 const scoped_refptr<MemoryDumpSessionState>& session_state() const { 118 return session_state_; 119 } 120 121 // Returns a unique id for identifying the processes. The id can be 122 // retrieved by child processes only when tracing is enabled. This is 123 // intended to express cross-process sharing of memory dumps on the 124 // child-process side, without having to know its own child process id. 125 uint64_t GetTracingProcessId() const; 126 127 // Returns the name for a the allocated_objects dump. Use this to declare 128 // suballocator dumps from other dump providers. 129 // It will return nullptr if there is no dump provider for the system 130 // allocator registered (which is currently the case for Mac OS). system_allocator_pool_name()131 const char* system_allocator_pool_name() const { 132 return kSystemAllocatorPoolName; 133 }; 134 135 // When set to true, calling |RegisterMemoryDumpProvider| is a no-op. set_dumper_registrations_ignored_for_testing(bool ignored)136 void set_dumper_registrations_ignored_for_testing(bool ignored) { 137 dumper_registrations_ignored_for_testing_ = ignored; 138 } 139 140 private: 141 friend std::default_delete<MemoryDumpManager>; // For the testing instance. 142 friend struct DefaultSingletonTraits<MemoryDumpManager>; 143 friend class MemoryDumpManagerDelegate; 144 friend class MemoryDumpManagerTest; 145 146 // Descriptor used to hold information about registered MDPs. 147 // Some important considerations about lifetime of this object: 148 // - In nominal conditions, all the MemoryDumpProviderInfo instances live in 149 // the |dump_providers_| collection (% unregistration while dumping). 150 // - Upon each dump they (actually their scoped_refptr-s) are copied into 151 // the ProcessMemoryDumpAsyncState. This is to allow removal (see below). 152 // - When the MDP.OnMemoryDump() is invoked, the corresponding MDPInfo copy 153 // inside ProcessMemoryDumpAsyncState is removed. 154 // - In most cases, the MDPInfo is destroyed within UnregisterDumpProvider(). 155 // - If UnregisterDumpProvider() is called while a dump is in progress, the 156 // MDPInfo is destroyed in the epilogue of ContinueAsyncProcessDump(), when 157 // the copy inside ProcessMemoryDumpAsyncState is erase()-d. 158 // - The non-const fields of MemoryDumpProviderInfo are safe to access only 159 // in the |task_runner| thread, unless the thread has been destroyed. 160 struct MemoryDumpProviderInfo 161 : public RefCountedThreadSafe<MemoryDumpProviderInfo> { 162 // Define a total order based on the thread (i.e. |task_runner|) affinity, 163 // so that all MDP belonging to the same thread are adjacent in the set. 164 struct Comparator { 165 bool operator()(const scoped_refptr<MemoryDumpProviderInfo>& a, 166 const scoped_refptr<MemoryDumpProviderInfo>& b) const; 167 }; 168 using OrderedSet = 169 std::set<scoped_refptr<MemoryDumpProviderInfo>, Comparator>; 170 171 MemoryDumpProviderInfo( 172 MemoryDumpProvider* dump_provider, 173 const char* name, 174 const scoped_refptr<SingleThreadTaskRunner>& task_runner, 175 const MemoryDumpProvider::Options& options); 176 177 MemoryDumpProvider* const dump_provider; 178 179 // Used to transfer ownership for UnregisterAndDeleteDumpProviderSoon(). 180 // nullptr in all other cases. 181 scoped_ptr<MemoryDumpProvider> owned_dump_provider; 182 183 // Human readable name, for debugging and testing. Not necessarily unique. 184 const char* const name; 185 186 // The task_runner affinity. Can be nullptr, in which case the dump provider 187 // will be invoked on |dump_thread_|. 188 const scoped_refptr<SingleThreadTaskRunner> task_runner; 189 190 // The |options| arg passed to RegisterDumpProvider(). 191 const MemoryDumpProvider::Options options; 192 193 // For fail-safe logic (auto-disable failing MDPs). 194 int consecutive_failures; 195 196 // Flagged either by the auto-disable logic or during unregistration. 197 bool disabled; 198 199 private: 200 friend class base::RefCountedThreadSafe<MemoryDumpProviderInfo>; 201 ~MemoryDumpProviderInfo(); 202 203 DISALLOW_COPY_AND_ASSIGN(MemoryDumpProviderInfo); 204 }; 205 206 // Holds the state of a process memory dump that needs to be carried over 207 // across threads in order to fulfil an asynchronous CreateProcessDump() 208 // request. At any time exactly one thread owns a ProcessMemoryDumpAsyncState. 209 struct ProcessMemoryDumpAsyncState { 210 ProcessMemoryDumpAsyncState( 211 MemoryDumpRequestArgs req_args, 212 const MemoryDumpProviderInfo::OrderedSet& dump_providers, 213 const scoped_refptr<MemoryDumpSessionState>& session_state, 214 MemoryDumpCallback callback, 215 const scoped_refptr<SingleThreadTaskRunner>& dump_thread_task_runner); 216 ~ProcessMemoryDumpAsyncState(); 217 218 // Gets or creates the memory dump container for the given target process. 219 ProcessMemoryDump* GetOrCreateMemoryDumpContainerForProcess(ProcessId pid); 220 221 // A map of ProcessId -> ProcessMemoryDump, one for each target process 222 // being dumped from the current process. Typically each process dumps only 223 // for itself, unless dump providers specify a different |target_process| in 224 // MemoryDumpProvider::Options. 225 std::map<ProcessId, scoped_ptr<ProcessMemoryDump>> process_dumps; 226 227 // The arguments passed to the initial CreateProcessDump() request. 228 const MemoryDumpRequestArgs req_args; 229 230 // An ordered sequence of dump providers that have to be invoked to complete 231 // the dump. This is a copy of |dump_providers_| at the beginning of a dump 232 // and becomes empty at the end, when all dump providers have been invoked. 233 std::vector<scoped_refptr<MemoryDumpProviderInfo>> pending_dump_providers; 234 235 // The trace-global session state. 236 scoped_refptr<MemoryDumpSessionState> session_state; 237 238 // Callback passed to the initial call to CreateProcessDump(). 239 MemoryDumpCallback callback; 240 241 // The thread on which FinalizeDumpAndAddToTrace() (and hence |callback|) 242 // should be invoked. This is the thread on which the initial 243 // CreateProcessDump() request was called. 244 const scoped_refptr<SingleThreadTaskRunner> callback_task_runner; 245 246 // The thread on which unbound dump providers should be invoked. 247 // This is essentially |dump_thread_|.task_runner() but needs to be kept 248 // as a separate variable as it needs to be accessed by arbitrary dumpers' 249 // threads outside of the lock_ to avoid races when disabling tracing. 250 // It is immutable for all the duration of a tracing session. 251 const scoped_refptr<SingleThreadTaskRunner> dump_thread_task_runner; 252 253 private: 254 DISALLOW_COPY_AND_ASSIGN(ProcessMemoryDumpAsyncState); 255 }; 256 257 static const int kMaxConsecutiveFailuresCount; 258 static const char* const kSystemAllocatorPoolName; 259 260 MemoryDumpManager(); 261 ~MemoryDumpManager() override; 262 263 static void SetInstanceForTesting(MemoryDumpManager* instance); 264 static void FinalizeDumpAndAddToTrace( 265 scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state); 266 267 // Internal, used only by MemoryDumpManagerDelegate. 268 // Creates a memory dump for the current process and appends it to the trace. 269 // |callback| will be invoked asynchronously upon completion on the same 270 // thread on which CreateProcessDump() was called. 271 void CreateProcessDump(const MemoryDumpRequestArgs& args, 272 const MemoryDumpCallback& callback); 273 274 // Continues the ProcessMemoryDump started by CreateProcessDump(), hopping 275 // across threads as needed as specified by MDPs in RegisterDumpProvider(). 276 void ContinueAsyncProcessDump( 277 ProcessMemoryDumpAsyncState* owned_pmd_async_state); 278 279 // Helper for the public UnregisterDumpProvider* functions. 280 void UnregisterDumpProviderInternal(MemoryDumpProvider* mdp, 281 bool take_mdp_ownership_and_delete_async); 282 283 // An ordererd set of registered MemoryDumpProviderInfo(s), sorted by thread 284 // affinity (MDPs belonging to the same thread are adjacent). 285 MemoryDumpProviderInfo::OrderedSet dump_providers_; 286 287 // Shared among all the PMDs to keep state scoped to the tracing session. 288 scoped_refptr<MemoryDumpSessionState> session_state_; 289 290 MemoryDumpManagerDelegate* delegate_; // Not owned. 291 292 // When true, this instance is in charge of coordinating periodic dumps. 293 bool is_coordinator_; 294 295 // Protects from concurrent accesses to the |dump_providers_*| and |delegate_| 296 // to guard against disabling logging while dumping on another thread. 297 Lock lock_; 298 299 // Optimization to avoid attempting any memory dump (i.e. to not walk an empty 300 // dump_providers_enabled_ list) when tracing is not enabled. 301 subtle::AtomicWord memory_tracing_enabled_; 302 303 // For time-triggered periodic dumps. 304 RepeatingTimer periodic_dump_timer_; 305 306 // Thread used for MemoryDumpProviders which don't specify a thread affinity. 307 scoped_ptr<Thread> dump_thread_; 308 309 // The unique id of the child process. This is created only for tracing and is 310 // expected to be valid only when tracing is enabled. 311 uint64_t tracing_process_id_; 312 313 // When true, calling |RegisterMemoryDumpProvider| is a no-op. 314 bool dumper_registrations_ignored_for_testing_; 315 316 // Whether new memory dump providers should be told to enable heap profiling. 317 bool heap_profiling_enabled_; 318 319 DISALLOW_COPY_AND_ASSIGN(MemoryDumpManager); 320 }; 321 322 // The delegate is supposed to be long lived (read: a Singleton) and thread 323 // safe (i.e. should expect calls from any thread and handle thread hopping). 324 class BASE_EXPORT MemoryDumpManagerDelegate { 325 public: 326 virtual void RequestGlobalMemoryDump(const MemoryDumpRequestArgs& args, 327 const MemoryDumpCallback& callback) = 0; 328 329 // Returns tracing process id of the current process. This is used by 330 // MemoryDumpManager::GetTracingProcessId. 331 virtual uint64_t GetTracingProcessId() const = 0; 332 333 protected: 334 MemoryDumpManagerDelegate() {} 335 virtual ~MemoryDumpManagerDelegate() {} 336 337 void CreateProcessDump(const MemoryDumpRequestArgs& args, 338 const MemoryDumpCallback& callback) { 339 MemoryDumpManager::GetInstance()->CreateProcessDump(args, callback); 340 } 341 342 private: 343 DISALLOW_COPY_AND_ASSIGN(MemoryDumpManagerDelegate); 344 }; 345 346 } // namespace trace_event 347 } // namespace base 348 349 #endif // BASE_TRACE_EVENT_MEMORY_DUMP_MANAGER_H_ 350