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