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 <unordered_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/trace_event/memory_allocator_dump.h" 22 #include "base/trace_event/memory_dump_provider_info.h" 23 #include "base/trace_event/memory_dump_request_args.h" 24 #include "base/trace_event/process_memory_dump.h" 25 #include "base/trace_event/trace_event.h" 26 27 // Forward declare |MemoryDumpManagerDelegateImplTest| so that we can make it a 28 // friend of |MemoryDumpManager| and give it access to |SetInstanceForTesting|. 29 namespace memory_instrumentation { 30 31 class MemoryDumpManagerDelegateImplTest; 32 33 } // namespace memory_instrumentation 34 35 namespace base { 36 37 class SingleThreadTaskRunner; 38 class Thread; 39 40 namespace trace_event { 41 42 class MemoryDumpManagerDelegate; 43 class MemoryDumpProvider; 44 class MemoryDumpSessionState; 45 class MemoryDumpScheduler; 46 47 // This is the interface exposed to the rest of the codebase to deal with 48 // memory tracing. The main entry point for clients is represented by 49 // RequestDumpPoint(). The extension by Un(RegisterDumpProvider). 50 class BASE_EXPORT MemoryDumpManager : public TraceLog::EnabledStateObserver { 51 public: 52 static const char* const kTraceCategory; 53 static const char* const kLogPrefix; 54 55 // This value is returned as the tracing id of the child processes by 56 // GetTracingProcessId() when tracing is not enabled. 57 static const uint64_t kInvalidTracingProcessId; 58 59 static MemoryDumpManager* GetInstance(); 60 61 // Invoked once per process to listen to trace begin / end events. 62 // Initialization can happen after (Un)RegisterMemoryDumpProvider() calls 63 // and the MemoryDumpManager guarantees to support this. 64 // On the other side, the MemoryDumpManager will not be fully operational 65 // (i.e. will NACK any RequestGlobalMemoryDump()) until initialized. 66 // Arguments: 67 // delegate: inversion-of-control interface for embedder-specific behaviors 68 // (multiprocess handshaking). See the lifetime and thread-safety 69 // requirements in the |MemoryDumpManagerDelegate| docstring. 70 void Initialize(std::unique_ptr<MemoryDumpManagerDelegate> delegate); 71 72 // (Un)Registers a MemoryDumpProvider instance. 73 // Args: 74 // - mdp: the MemoryDumpProvider instance to be registered. MemoryDumpManager 75 // does NOT take memory ownership of |mdp|, which is expected to either 76 // be a singleton or unregister itself. 77 // - name: a friendly name (duplicates allowed). Used for debugging and 78 // run-time profiling of memory-infra internals. Must be a long-lived 79 // C string. 80 // - task_runner: either a SingleThreadTaskRunner or SequencedTaskRunner. All 81 // the calls to |mdp| will be run on the given |task_runner|. If passed 82 // null |mdp| should be able to handle calls on arbitrary threads. 83 // - options: extra optional arguments. See memory_dump_provider.h. 84 void RegisterDumpProvider(MemoryDumpProvider* mdp, 85 const char* name, 86 scoped_refptr<SingleThreadTaskRunner> task_runner); 87 void RegisterDumpProvider(MemoryDumpProvider* mdp, 88 const char* name, 89 scoped_refptr<SingleThreadTaskRunner> task_runner, 90 MemoryDumpProvider::Options options); 91 void RegisterDumpProviderWithSequencedTaskRunner( 92 MemoryDumpProvider* mdp, 93 const char* name, 94 scoped_refptr<SequencedTaskRunner> task_runner, 95 MemoryDumpProvider::Options options); 96 void UnregisterDumpProvider(MemoryDumpProvider* mdp); 97 98 // Unregisters an unbound dump provider and takes care about its deletion 99 // asynchronously. Can be used only for for dump providers with no 100 // task-runner affinity. 101 // This method takes ownership of the dump provider and guarantees that: 102 // - The |mdp| will be deleted at some point in the near future. 103 // - Its deletion will not happen concurrently with the OnMemoryDump() call. 104 // Note that OnMemoryDump() and PollFastMemoryTotal() calls can still happen 105 // after this method returns. 106 void UnregisterAndDeleteDumpProviderSoon( 107 std::unique_ptr<MemoryDumpProvider> mdp); 108 109 // Requests a memory dump. The dump might happen or not depending on the 110 // filters and categories specified when enabling tracing. 111 // The optional |callback| is executed asynchronously, on an arbitrary thread, 112 // to notify about the completion of the global dump (i.e. after all the 113 // processes have dumped) and its success (true iff all the dumps were 114 // successful). 115 void RequestGlobalDump(MemoryDumpType dump_type, 116 MemoryDumpLevelOfDetail level_of_detail, 117 const MemoryDumpCallback& callback); 118 119 // Same as above (still asynchronous), but without callback. 120 void RequestGlobalDump(MemoryDumpType dump_type, 121 MemoryDumpLevelOfDetail level_of_detail); 122 123 // TraceLog::EnabledStateObserver implementation. 124 void OnTraceLogEnabled() override; 125 void OnTraceLogDisabled() override; 126 127 // Enable heap profiling if kEnableHeapProfiling is specified. 128 void EnableHeapProfilingIfNeeded(); 129 130 // Returns true if the dump mode is allowed for current tracing session. 131 bool IsDumpModeAllowed(MemoryDumpLevelOfDetail dump_mode); 132 133 // Lets tests see if a dump provider is registered. 134 bool IsDumpProviderRegisteredForTesting(MemoryDumpProvider*); 135 136 // Returns the MemoryDumpSessionState object, which is shared by all the 137 // ProcessMemoryDump and MemoryAllocatorDump instances through all the tracing 138 // session lifetime. 139 const scoped_refptr<MemoryDumpSessionState>& session_state_for_testing() 140 const { 141 return session_state_; 142 } 143 144 // Returns a unique id for identifying the processes. The id can be 145 // retrieved by child processes only when tracing is enabled. This is 146 // intended to express cross-process sharing of memory dumps on the 147 // child-process side, without having to know its own child process id. 148 uint64_t GetTracingProcessId() const { return tracing_process_id_; } 149 void set_tracing_process_id(uint64_t tracing_process_id) { 150 tracing_process_id_ = tracing_process_id; 151 } 152 153 // Returns the name for a the allocated_objects dump. Use this to declare 154 // suballocator dumps from other dump providers. 155 // It will return nullptr if there is no dump provider for the system 156 // allocator registered (which is currently the case for Mac OS). 157 const char* system_allocator_pool_name() const { 158 return kSystemAllocatorPoolName; 159 }; 160 161 // When set to true, calling |RegisterMemoryDumpProvider| is a no-op. 162 void set_dumper_registrations_ignored_for_testing(bool ignored) { 163 dumper_registrations_ignored_for_testing_ = ignored; 164 } 165 166 private: 167 friend std::default_delete<MemoryDumpManager>; // For the testing instance. 168 friend struct DefaultSingletonTraits<MemoryDumpManager>; 169 friend class MemoryDumpManagerDelegate; 170 friend class MemoryDumpManagerTest; 171 friend class MemoryDumpScheduler; 172 friend class memory_instrumentation::MemoryDumpManagerDelegateImplTest; 173 174 // Holds the state of a process memory dump that needs to be carried over 175 // across task runners in order to fulfil an asynchronous CreateProcessDump() 176 // request. At any time exactly one task runner owns a 177 // ProcessMemoryDumpAsyncState. 178 struct ProcessMemoryDumpAsyncState { 179 ProcessMemoryDumpAsyncState( 180 MemoryDumpRequestArgs req_args, 181 const MemoryDumpProviderInfo::OrderedSet& dump_providers, 182 scoped_refptr<MemoryDumpSessionState> session_state, 183 MemoryDumpCallback callback, 184 scoped_refptr<SingleThreadTaskRunner> dump_thread_task_runner); 185 ~ProcessMemoryDumpAsyncState(); 186 187 // Gets or creates the memory dump container for the given target process. 188 ProcessMemoryDump* GetOrCreateMemoryDumpContainerForProcess( 189 ProcessId pid, 190 const MemoryDumpArgs& dump_args); 191 192 // A map of ProcessId -> ProcessMemoryDump, one for each target process 193 // being dumped from the current process. Typically each process dumps only 194 // for itself, unless dump providers specify a different |target_process| in 195 // MemoryDumpProvider::Options. 196 std::map<ProcessId, std::unique_ptr<ProcessMemoryDump>> process_dumps; 197 198 // The arguments passed to the initial CreateProcessDump() request. 199 const MemoryDumpRequestArgs req_args; 200 201 // An ordered sequence of dump providers that have to be invoked to complete 202 // the dump. This is a copy of |dump_providers_| at the beginning of a dump 203 // and becomes empty at the end, when all dump providers have been invoked. 204 std::vector<scoped_refptr<MemoryDumpProviderInfo>> pending_dump_providers; 205 206 // The trace-global session state. 207 scoped_refptr<MemoryDumpSessionState> session_state; 208 209 // Callback passed to the initial call to CreateProcessDump(). 210 MemoryDumpCallback callback; 211 212 // The |success| field that will be passed as argument to the |callback|. 213 bool dump_successful; 214 215 // The thread on which FinalizeDumpAndAddToTrace() (and hence |callback|) 216 // should be invoked. This is the thread on which the initial 217 // CreateProcessDump() request was called. 218 const scoped_refptr<SingleThreadTaskRunner> callback_task_runner; 219 220 // The thread on which unbound dump providers should be invoked. 221 // This is essentially |dump_thread_|.task_runner() but needs to be kept 222 // as a separate variable as it needs to be accessed by arbitrary dumpers' 223 // threads outside of the lock_ to avoid races when disabling tracing. 224 // It is immutable for all the duration of a tracing session. 225 const scoped_refptr<SingleThreadTaskRunner> dump_thread_task_runner; 226 227 private: 228 DISALLOW_COPY_AND_ASSIGN(ProcessMemoryDumpAsyncState); 229 }; 230 231 static const int kMaxConsecutiveFailuresCount; 232 static const char* const kSystemAllocatorPoolName; 233 234 MemoryDumpManager(); 235 ~MemoryDumpManager() override; 236 237 static void SetInstanceForTesting(MemoryDumpManager* instance); 238 static uint32_t GetDumpsSumKb(const std::string&, const ProcessMemoryDump*); 239 static void FinalizeDumpAndAddToTrace( 240 std::unique_ptr<ProcessMemoryDumpAsyncState> pmd_async_state); 241 242 // Internal, used only by MemoryDumpManagerDelegate. 243 // Creates a memory dump for the current process and appends it to the trace. 244 // |callback| will be invoked asynchronously upon completion on the same 245 // thread on which CreateProcessDump() was called. 246 void CreateProcessDump(const MemoryDumpRequestArgs& args, 247 const MemoryDumpCallback& callback); 248 249 // Calls InvokeOnMemoryDump() for the next MDP on the task runner specified by 250 // the MDP while registration. On failure to do so, skips and continues to 251 // next MDP. 252 void SetupNextMemoryDump( 253 std::unique_ptr<ProcessMemoryDumpAsyncState> pmd_async_state); 254 255 // Invokes OnMemoryDump() of the next MDP and calls SetupNextMemoryDump() at 256 // the end to continue the ProcessMemoryDump. Should be called on the MDP task 257 // runner. 258 void InvokeOnMemoryDump(ProcessMemoryDumpAsyncState* owned_pmd_async_state); 259 260 // Records a quick total memory usage in |memory_total|. This is used to track 261 // and detect peaks in the memory usage of the process without having to 262 // record all data from dump providers. This value is approximate to trade-off 263 // speed, and not consistent with the rest of the memory-infra metrics. Must 264 // be called on the dump thread. 265 // Returns true if |memory_total| was updated by polling at least 1 MDP. 266 bool PollFastMemoryTotal(uint64_t* memory_total); 267 268 // Helper for RegierDumpProvider* functions. 269 void RegisterDumpProviderInternal( 270 MemoryDumpProvider* mdp, 271 const char* name, 272 scoped_refptr<SequencedTaskRunner> task_runner, 273 const MemoryDumpProvider::Options& options); 274 275 // Helper for the public UnregisterDumpProvider* functions. 276 void UnregisterDumpProviderInternal(MemoryDumpProvider* mdp, 277 bool take_mdp_ownership_and_delete_async); 278 279 // Adds / removes provider that supports polling to 280 // |dump_providers_for_polling_|. 281 void RegisterPollingMDPOnDumpThread( 282 scoped_refptr<MemoryDumpProviderInfo> mdpinfo); 283 void UnregisterPollingMDPOnDumpThread( 284 scoped_refptr<MemoryDumpProviderInfo> mdpinfo); 285 286 // An ordererd set of registered MemoryDumpProviderInfo(s), sorted by task 287 // runner affinity (MDPs belonging to the same task runners are adjacent). 288 MemoryDumpProviderInfo::OrderedSet dump_providers_; 289 290 // A copy of mdpinfo list that support polling. It must be accessed only on 291 // the dump thread if dump thread exists. 292 MemoryDumpProviderInfo::OrderedSet dump_providers_for_polling_; 293 294 // Shared among all the PMDs to keep state scoped to the tracing session. 295 scoped_refptr<MemoryDumpSessionState> session_state_; 296 297 // The list of names of dump providers that are blacklisted from strict thread 298 // affinity check on unregistration. 299 std::unordered_set<StringPiece, StringPieceHash> 300 strict_thread_check_blacklist_; 301 302 std::unique_ptr<MemoryDumpManagerDelegate> delegate_; 303 304 // Protects from concurrent accesses to the |dump_providers_*| and |delegate_| 305 // to guard against disabling logging while dumping on another thread. 306 Lock lock_; 307 308 // Optimization to avoid attempting any memory dump (i.e. to not walk an empty 309 // dump_providers_enabled_ list) when tracing is not enabled. 310 subtle::AtomicWord memory_tracing_enabled_; 311 312 // Thread used for MemoryDumpProviders which don't specify a task runner 313 // affinity. 314 std::unique_ptr<Thread> dump_thread_; 315 316 // The unique id of the child process. This is created only for tracing and is 317 // expected to be valid only when tracing is enabled. 318 uint64_t tracing_process_id_; 319 320 // When true, calling |RegisterMemoryDumpProvider| is a no-op. 321 bool dumper_registrations_ignored_for_testing_; 322 323 // Whether new memory dump providers should be told to enable heap profiling. 324 bool heap_profiling_enabled_; 325 326 DISALLOW_COPY_AND_ASSIGN(MemoryDumpManager); 327 }; 328 329 // The delegate is supposed to be long lived (read: a Singleton) and thread 330 // safe (i.e. should expect calls from any thread and handle thread hopping). 331 class BASE_EXPORT MemoryDumpManagerDelegate { 332 public: 333 MemoryDumpManagerDelegate() {} 334 virtual ~MemoryDumpManagerDelegate() {} 335 336 virtual void RequestGlobalMemoryDump(const MemoryDumpRequestArgs& args, 337 const MemoryDumpCallback& callback) = 0; 338 339 virtual bool IsCoordinator() const = 0; 340 341 protected: 342 void CreateProcessDump(const MemoryDumpRequestArgs& args, 343 const MemoryDumpCallback& callback) { 344 MemoryDumpManager::GetInstance()->CreateProcessDump(args, callback); 345 } 346 347 private: 348 DISALLOW_COPY_AND_ASSIGN(MemoryDumpManagerDelegate); 349 }; 350 351 } // namespace trace_event 352 } // namespace base 353 354 #endif // BASE_TRACE_EVENT_MEMORY_DUMP_MANAGER_H_ 355