xref: /aosp_15_r20/external/cronet/base/trace_event/memory_dump_manager.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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