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