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/macros.h" 17 #include "base/memory/ref_counted.h" 18 #include "base/memory/singleton.h" 19 #include "base/synchronization/lock.h" 20 #include "base/trace_event/memory_allocator_dump.h" 21 #include "base/trace_event/memory_dump_provider_info.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 SequencedTaskRunner; 29 class SingleThreadTaskRunner; 30 class Thread; 31 32 namespace trace_event { 33 34 class MemoryDumpProvider; 35 36 // This is the interface exposed to the rest of the codebase to deal with 37 // memory tracing. The main entry point for clients is represented by 38 // RequestDumpPoint(). The extension by Un(RegisterDumpProvider). 39 class BASE_EXPORT MemoryDumpManager { 40 public: 41 using RequestGlobalDumpFunction = 42 RepeatingCallback<void(MemoryDumpType, MemoryDumpLevelOfDetail)>; 43 44 static constexpr const char* const kTraceCategory = 45 TRACE_DISABLED_BY_DEFAULT("memory-infra"); 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 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 scoped_refptr<SequencedTaskRunner> GetDumpThreadTaskRunner(); 147 148 private: 149 friend std::default_delete<MemoryDumpManager>; // For the testing instance. 150 friend struct DefaultSingletonTraits<MemoryDumpManager>; 151 friend class MemoryDumpManagerTest; 152 FRIEND_TEST_ALL_PREFIXES(MemoryDumpManagerTest, 153 NoStackOverflowWithTooManyMDPs); 154 155 // Holds the state of a process memory dump that needs to be carried over 156 // across task runners in order to fulfill an asynchronous CreateProcessDump() 157 // request. At any time exactly one task runner owns a 158 // ProcessMemoryDumpAsyncState. 159 struct ProcessMemoryDumpAsyncState { 160 ProcessMemoryDumpAsyncState( 161 MemoryDumpRequestArgs req_args, 162 const MemoryDumpProviderInfo::OrderedSet& dump_providers, 163 ProcessMemoryDumpCallback callback, 164 scoped_refptr<SequencedTaskRunner> dump_thread_task_runner); 165 ~ProcessMemoryDumpAsyncState(); 166 167 // A ProcessMemoryDump to collect data from MemoryDumpProviders. 168 std::unique_ptr<ProcessMemoryDump> process_memory_dump; 169 170 // The arguments passed to the initial CreateProcessDump() request. 171 const MemoryDumpRequestArgs req_args; 172 173 // An ordered sequence of dump providers that have to be invoked to complete 174 // the dump. This is a copy of |dump_providers_| at the beginning of a dump 175 // and becomes empty at the end, when all dump providers have been invoked. 176 std::vector<scoped_refptr<MemoryDumpProviderInfo>> pending_dump_providers; 177 178 // Callback passed to the initial call to CreateProcessDump(). 179 ProcessMemoryDumpCallback callback; 180 181 // The thread on which FinishAsyncProcessDump() (and hence |callback|) 182 // should be invoked. This is the thread on which the initial 183 // CreateProcessDump() request was called. 184 const scoped_refptr<SingleThreadTaskRunner> callback_task_runner; 185 186 // The thread on which unbound dump providers should be invoked. 187 // This is essentially |dump_thread_|.task_runner() but needs to be kept 188 // as a separate variable as it needs to be accessed by arbitrary dumpers' 189 // threads outside of the lock_ to avoid races when disabling tracing. 190 // It is immutable for all the duration of a tracing session. 191 const scoped_refptr<SequencedTaskRunner> dump_thread_task_runner; 192 193 private: 194 DISALLOW_COPY_AND_ASSIGN(ProcessMemoryDumpAsyncState); 195 }; 196 197 static const int kMaxConsecutiveFailuresCount; 198 static const char* const kSystemAllocatorPoolName; 199 200 MemoryDumpManager(); 201 virtual ~MemoryDumpManager(); 202 203 static void SetInstanceForTesting(MemoryDumpManager* instance); 204 205 // Lazily initializes dump_thread_ and returns its TaskRunner. 206 scoped_refptr<base::SequencedTaskRunner> GetOrCreateBgTaskRunnerLocked(); 207 208 // Calls InvokeOnMemoryDump() for the each MDP that belongs to the current 209 // task runner and switches to the task runner of the next MDP. Handles 210 // failures in MDP and thread hops, and always calls FinishAsyncProcessDump() 211 // at the end. 212 void ContinueAsyncProcessDump( 213 ProcessMemoryDumpAsyncState* owned_pmd_async_state); 214 215 // Invokes OnMemoryDump() of the given MDP. Should be called on the MDP task 216 // runner. 217 void InvokeOnMemoryDump(MemoryDumpProviderInfo* mdpinfo, 218 ProcessMemoryDump* pmd); 219 220 void FinishAsyncProcessDump( 221 std::unique_ptr<ProcessMemoryDumpAsyncState> pmd_async_state); 222 223 // Helper for RegierDumpProvider* functions. 224 void RegisterDumpProviderInternal( 225 MemoryDumpProvider* mdp, 226 const char* name, 227 scoped_refptr<SequencedTaskRunner> task_runner, 228 const MemoryDumpProvider::Options& options); 229 230 // Helper for the public UnregisterDumpProvider* functions. 231 void UnregisterDumpProviderInternal(MemoryDumpProvider* mdp, 232 bool take_mdp_ownership_and_delete_async); 233 234 bool can_request_global_dumps() const { 235 return !request_dump_function_.is_null(); 236 } 237 238 // An ordered set of registered MemoryDumpProviderInfo(s), sorted by task 239 // runner affinity (MDPs belonging to the same task runners are adjacent). 240 MemoryDumpProviderInfo::OrderedSet dump_providers_; 241 242 // Function provided by the embedder to handle global dump requests. 243 RequestGlobalDumpFunction request_dump_function_; 244 245 // True when current process coordinates the periodic dump triggering. 246 bool is_coordinator_; 247 248 // Protects from concurrent accesses to the local state, eg: to guard against 249 // disabling logging while dumping on another thread. 250 Lock lock_; 251 252 // Thread used for MemoryDumpProviders which don't specify a task runner 253 // affinity. 254 std::unique_ptr<Thread> dump_thread_; 255 256 // The unique id of the child process. This is created only for tracing and is 257 // expected to be valid only when tracing is enabled. 258 uint64_t tracing_process_id_; 259 260 // When true, calling |RegisterMemoryDumpProvider| is a no-op. 261 bool dumper_registrations_ignored_for_testing_; 262 263 DISALLOW_COPY_AND_ASSIGN(MemoryDumpManager); 264 }; 265 266 } // namespace trace_event 267 } // namespace base 268 269 #endif // BASE_TRACE_EVENT_MEMORY_DUMP_MANAGER_H_ 270