1 // Copyright 2015 The Chromium Authors 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/base_export.h" 16 #include "base/gtest_prod_util.h" 17 #include "base/memory/singleton.h" 18 #include "base/synchronization/lock.h" 19 #include "base/trace_event/memory_allocator_dump.h" 20 #include "base/trace_event/memory_dump_provider_info.h" 21 #include "base/trace_event/memory_dump_request_args.h" 22 #include "base/trace_event/process_memory_dump.h" 23 #include "base/trace_event/trace_event.h" 24 25 namespace base { 26 27 class SequencedTaskRunner; 28 class SingleThreadTaskRunner; 29 class Thread; 30 31 namespace trace_event { 32 33 class MemoryDumpProvider; 34 35 // This is the interface exposed to the rest of the codebase to deal with 36 // memory tracing. The main entry point for clients is represented by 37 // RequestDumpPoint(). The extension by Un(RegisterDumpProvider). 38 class BASE_EXPORT MemoryDumpManager { 39 public: 40 using RequestGlobalDumpFunction = 41 RepeatingCallback<void(MemoryDumpType, MemoryDumpLevelOfDetail)>; 42 43 static constexpr const char* const kTraceCategory = 44 TRACE_DISABLED_BY_DEFAULT("memory-infra"); 45 46 // This value is returned as the tracing id of the child processes by 47 // GetTracingProcessId() when tracing is not enabled. 48 static const uint64_t kInvalidTracingProcessId; 49 50 static MemoryDumpManager* GetInstance(); 51 static std::unique_ptr<MemoryDumpManager> CreateInstanceForTesting(); 52 53 // Resets the initialization. When destroying and recreating the manager in 54 // multi threaded environment is hard, this method can be used to reset the 55 // state to begin new initialization. 56 void ResetForTesting(); 57 58 MemoryDumpManager(const MemoryDumpManager&) = delete; 59 MemoryDumpManager& operator=(const MemoryDumpManager&) = delete; 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 // (any CreateProcessDump() will return a failure) until initialized. 66 // Arguments: 67 // is_coordinator: True when current process coordinates the periodic dump 68 // triggering. 69 // request_dump_function: Function to invoke a global dump. Global dump 70 // involves embedder-specific behaviors like multiprocess handshaking. 71 // TODO(primiano): this is only required to trigger global dumps from 72 // the scheduler. Should be removed once they are both moved out of base. 73 void Initialize(RequestGlobalDumpFunction request_dump_function, 74 bool is_coordinator); 75 76 // (Un)Registers a MemoryDumpProvider instance. 77 // Args: 78 // - mdp: the MemoryDumpProvider instance to be registered. MemoryDumpManager 79 // does NOT take memory ownership of |mdp|, which is expected to either 80 // be a singleton or unregister itself. 81 // - name: a friendly name (duplicates allowed). Used for debugging and 82 // run-time profiling of memory-infra internals. Must be a long-lived 83 // C string. 84 // - task_runner: either a SingleThreadTaskRunner or SequencedTaskRunner. All 85 // the calls to |mdp| will be run on the given |task_runner|. If passed 86 // null |mdp| should be able to handle calls on arbitrary threads. 87 // - options: extra optional arguments. See memory_dump_provider.h. 88 void RegisterDumpProvider(MemoryDumpProvider* mdp, 89 const char* name, 90 scoped_refptr<SingleThreadTaskRunner> task_runner); 91 void RegisterDumpProvider(MemoryDumpProvider* mdp, 92 const char* name, 93 scoped_refptr<SingleThreadTaskRunner> task_runner, 94 MemoryDumpProvider::Options options); 95 void RegisterDumpProviderWithSequencedTaskRunner( 96 MemoryDumpProvider* mdp, 97 const char* name, 98 scoped_refptr<SequencedTaskRunner> task_runner, 99 MemoryDumpProvider::Options options); 100 void UnregisterDumpProvider(MemoryDumpProvider* mdp); 101 102 // Unregisters an unbound dump provider and takes care about its deletion 103 // asynchronously. Can be used only for for dump providers with no 104 // task-runner affinity. 105 // This method takes ownership of the dump provider and guarantees that: 106 // - The |mdp| will be deleted at some point in the near future. 107 // - Its deletion will not happen concurrently with the OnMemoryDump() call. 108 // Note that OnMemoryDump() calls can still happen after this method returns. 109 void UnregisterAndDeleteDumpProviderSoon( 110 std::unique_ptr<MemoryDumpProvider> mdp); 111 112 // Prepare MemoryDumpManager for CreateProcessDump() calls for tracing-related 113 // modes (i.e. |level_of_detail| != SUMMARY_ONLY). 114 // Also initializes the scheduler with the given config. 115 void SetupForTracing(const TraceConfig::MemoryDumpConfig&); 116 117 // Tear-down tracing related state. 118 // Non-tracing modes (e.g. SUMMARY_ONLY) will continue to work. 119 void TeardownForTracing(); 120 121 // Creates a memory dump for the current process and appends it to the trace. 122 // |callback| will be invoked asynchronously upon completion on the same 123 // thread on which CreateProcessDump() was called. This method should only be 124 // used by the memory-infra service while creating a global memory dump. 125 void CreateProcessDump(const MemoryDumpRequestArgs& args, 126 ProcessMemoryDumpCallback callback); 127 128 // Lets tests see if a dump provider is registered. 129 bool IsDumpProviderRegisteredForTesting(MemoryDumpProvider*); 130 131 // Returns a unique id for identifying the processes. The id can be 132 // retrieved by child processes only when tracing is enabled. This is 133 // intended to express cross-process sharing of memory dumps on the 134 // child-process side, without having to know its own child process id. GetTracingProcessId()135 uint64_t GetTracingProcessId() const { return tracing_process_id_; } set_tracing_process_id(uint64_t tracing_process_id)136 void set_tracing_process_id(uint64_t tracing_process_id) { 137 tracing_process_id_ = tracing_process_id; 138 } 139 140 // Returns the name for a the allocated_objects dump. Use this to declare 141 // suballocator dumps from other dump providers. 142 // It will return nullptr if there is no dump provider for the system 143 // allocator registered (which is currently the case for Mac OS). system_allocator_pool_name()144 const char* system_allocator_pool_name() const { 145 return kSystemAllocatorPoolName; 146 } 147 148 // When set to true, calling |RegisterMemoryDumpProvider| is a no-op. set_dumper_registrations_ignored_for_testing(bool ignored)149 void set_dumper_registrations_ignored_for_testing(bool ignored) { 150 dumper_registrations_ignored_for_testing_ = ignored; 151 } 152 IsInitialized()153 bool IsInitialized() { 154 AutoLock lock(lock_); 155 return can_request_global_dumps(); 156 } 157 158 scoped_refptr<SequencedTaskRunner> GetDumpThreadTaskRunner(); 159 160 private: 161 friend std::default_delete<MemoryDumpManager>; // For the testing instance. 162 friend struct DefaultSingletonTraits<MemoryDumpManager>; 163 friend class MemoryDumpManagerTest; 164 FRIEND_TEST_ALL_PREFIXES(MemoryDumpManagerTest, 165 NoStackOverflowWithTooManyMDPs); 166 167 // Holds the state of a process memory dump that needs to be carried over 168 // across task runners in order to fulfill an asynchronous CreateProcessDump() 169 // request. At any time exactly one task runner owns a 170 // ProcessMemoryDumpAsyncState. 171 struct ProcessMemoryDumpAsyncState { 172 ProcessMemoryDumpAsyncState( 173 MemoryDumpRequestArgs req_args, 174 const MemoryDumpProviderInfo::OrderedSet& dump_providers, 175 ProcessMemoryDumpCallback callback, 176 scoped_refptr<SequencedTaskRunner> dump_thread_task_runner); 177 ProcessMemoryDumpAsyncState(const ProcessMemoryDumpAsyncState&) = delete; 178 ProcessMemoryDumpAsyncState& operator=(const ProcessMemoryDumpAsyncState&) = 179 delete; 180 ~ProcessMemoryDumpAsyncState(); 181 182 // A ProcessMemoryDump to collect data from MemoryDumpProviders. 183 std::unique_ptr<ProcessMemoryDump> process_memory_dump; 184 185 // The arguments passed to the initial CreateProcessDump() request. 186 const MemoryDumpRequestArgs req_args; 187 188 // An ordered sequence of dump providers that have to be invoked to complete 189 // the dump. This is a copy of |dump_providers_| at the beginning of a dump 190 // and becomes empty at the end, when all dump providers have been invoked. 191 std::vector<scoped_refptr<MemoryDumpProviderInfo>> pending_dump_providers; 192 193 // Callback passed to the initial call to CreateProcessDump(). 194 ProcessMemoryDumpCallback callback; 195 196 // The thread on which FinishAsyncProcessDump() (and hence |callback|) 197 // should be invoked. This is the thread on which the initial 198 // CreateProcessDump() request was called. 199 const scoped_refptr<SingleThreadTaskRunner> callback_task_runner; 200 201 // The thread on which unbound dump providers should be invoked. 202 // This is essentially |dump_thread_|.task_runner() but needs to be kept 203 // as a separate variable as it needs to be accessed by arbitrary dumpers' 204 // threads outside of the lock_ to avoid races when disabling tracing. 205 // It is immutable for all the duration of a tracing session. 206 const scoped_refptr<SequencedTaskRunner> dump_thread_task_runner; 207 }; 208 209 static const int kMaxConsecutiveFailuresCount; 210 static const char* const kSystemAllocatorPoolName; 211 212 MemoryDumpManager(); 213 virtual ~MemoryDumpManager(); 214 215 static void SetInstanceForTesting(MemoryDumpManager* instance); 216 217 // Lazily initializes dump_thread_ and returns its TaskRunner. 218 scoped_refptr<base::SequencedTaskRunner> GetOrCreateBgTaskRunnerLocked() 219 EXCLUSIVE_LOCKS_REQUIRED(lock_); 220 221 // Calls InvokeOnMemoryDump() for the each MDP that belongs to the current 222 // task runner and switches to the task runner of the next MDP. Handles 223 // failures in MDP and thread hops, and always calls FinishAsyncProcessDump() 224 // at the end. 225 void ContinueAsyncProcessDump( 226 ProcessMemoryDumpAsyncState* owned_pmd_async_state); 227 228 // Invokes OnMemoryDump() of the given MDP. Should be called on the MDP task 229 // runner. 230 void InvokeOnMemoryDump(MemoryDumpProviderInfo* mdpinfo, 231 ProcessMemoryDump* pmd); 232 233 void FinishAsyncProcessDump( 234 std::unique_ptr<ProcessMemoryDumpAsyncState> pmd_async_state); 235 236 // Helper for RegierDumpProvider* functions. 237 void RegisterDumpProviderInternal( 238 MemoryDumpProvider* mdp, 239 const char* name, 240 scoped_refptr<SequencedTaskRunner> task_runner, 241 const MemoryDumpProvider::Options& options); 242 243 // Helper for the public UnregisterDumpProvider* functions. 244 void UnregisterDumpProviderInternal(MemoryDumpProvider* mdp, 245 bool take_mdp_ownership_and_delete_async); 246 247 bool can_request_global_dumps() const { 248 return !request_dump_function_.is_null(); 249 } 250 251 // An ordered set of registered MemoryDumpProviderInfo(s), sorted by task 252 // runner affinity (MDPs belonging to the same task runners are adjacent). 253 MemoryDumpProviderInfo::OrderedSet dump_providers_ GUARDED_BY(lock_); 254 255 // Function provided by the embedder to handle global dump requests. 256 RequestGlobalDumpFunction request_dump_function_; 257 258 // True when current process coordinates the periodic dump triggering. 259 bool is_coordinator_ GUARDED_BY(lock_) = false; 260 261 // Protects from concurrent accesses to the local state, eg: to guard against 262 // disabling logging while dumping on another thread. 263 Lock lock_; 264 265 // Thread used for MemoryDumpProviders which don't specify a task runner 266 // affinity. 267 std::unique_ptr<Thread> dump_thread_ GUARDED_BY(lock_); 268 269 // The unique id of the child process. This is created only for tracing and is 270 // expected to be valid only when tracing is enabled. 271 uint64_t tracing_process_id_ = kInvalidTracingProcessId; 272 273 // When true, calling |RegisterMemoryDumpProvider| is a no-op. 274 bool dumper_registrations_ignored_for_testing_ = false; 275 }; 276 277 } // namespace trace_event 278 } // namespace base 279 280 #endif // BASE_TRACE_EVENT_MEMORY_DUMP_MANAGER_H_ 281