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 <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/timer/timer.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 SingleThreadTaskRunner;
29 class Thread;
30 
31 namespace trace_event {
32 
33 class MemoryDumpManagerDelegate;
34 class MemoryDumpProvider;
35 class MemoryDumpSessionState;
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 : public TraceLog::EnabledStateObserver {
41  public:
42   static const char* const kTraceCategory;
43 
44   // This value is returned as the tracing id of the child processes by
45   // GetTracingProcessId() when tracing is not enabled.
46   static const uint64_t kInvalidTracingProcessId;
47 
48   static MemoryDumpManager* GetInstance();
49 
50   // Invoked once per process to listen to trace begin / end events.
51   // Initialization can happen after (Un)RegisterMemoryDumpProvider() calls
52   // and the MemoryDumpManager guarantees to support this.
53   // On the other side, the MemoryDumpManager will not be fully operational
54   // (i.e. will NACK any RequestGlobalMemoryDump()) until initialized.
55   // Arguments:
56   //  is_coordinator: if true this MemoryDumpManager instance will act as a
57   //      coordinator and schedule periodic dumps (if enabled via TraceConfig);
58   //      false when the MemoryDumpManager is initialized in a slave process.
59   //  delegate: inversion-of-control interface for embedder-specific behaviors
60   //      (multiprocess handshaking). See the lifetime and thread-safety
61   //      requirements in the |MemoryDumpManagerDelegate| docstring.
62   void Initialize(MemoryDumpManagerDelegate* delegate, bool is_coordinator);
63 
64   // (Un)Registers a MemoryDumpProvider instance.
65   // Args:
66   //  - mdp: the MemoryDumpProvider instance to be registered. MemoryDumpManager
67   //      does NOT take memory ownership of |mdp|, which is expected to either
68   //      be a singleton or unregister itself.
69   //  - name: a friendly name (duplicates allowed). Used for debugging and
70   //      run-time profiling of memory-infra internals. Must be a long-lived
71   //      C string.
72   //  - task_runner: if non-null, all the calls to |mdp| will be
73   //      issued on the given thread. Otherwise, |mdp| should be able to
74   //      handle calls on arbitrary threads.
75   //  - options: extra optional arguments. See memory_dump_provider.h.
76   void RegisterDumpProvider(
77       MemoryDumpProvider* mdp,
78       const char* name,
79       const scoped_refptr<SingleThreadTaskRunner>& task_runner);
80   void RegisterDumpProvider(
81       MemoryDumpProvider* mdp,
82       const char* name,
83       const scoped_refptr<SingleThreadTaskRunner>& task_runner,
84       const MemoryDumpProvider::Options& options);
85   void UnregisterDumpProvider(MemoryDumpProvider* mdp);
86 
87   // Unregisters an unbound dump provider and takes care about its deletion
88   // asynchronously. Can be used only for for dump providers with no
89   // task-runner affinity.
90   // This method takes ownership of the dump provider and guarantees that:
91   //  - The |mdp| will be deleted at some point in the near future.
92   //  - Its deletion will not happen concurrently with the OnMemoryDump() call.
93   // Note that OnMemoryDump() calls can still happen after this method returns.
94   void UnregisterAndDeleteDumpProviderSoon(scoped_ptr<MemoryDumpProvider> mdp);
95 
96   // Requests a memory dump. The dump might happen or not depending on the
97   // filters and categories specified when enabling tracing.
98   // The optional |callback| is executed asynchronously, on an arbitrary thread,
99   // to notify about the completion of the global dump (i.e. after all the
100   // processes have dumped) and its success (true iff all the dumps were
101   // successful).
102   void RequestGlobalDump(MemoryDumpType dump_type,
103                          MemoryDumpLevelOfDetail level_of_detail,
104                          const MemoryDumpCallback& callback);
105 
106   // Same as above (still asynchronous), but without callback.
107   void RequestGlobalDump(MemoryDumpType dump_type,
108                          MemoryDumpLevelOfDetail level_of_detail);
109 
110   // TraceLog::EnabledStateObserver implementation.
111   void OnTraceLogEnabled() override;
112   void OnTraceLogDisabled() override;
113 
114   // Returns the MemoryDumpSessionState object, which is shared by all the
115   // ProcessMemoryDump and MemoryAllocatorDump instances through all the tracing
116   // session lifetime.
session_state()117   const scoped_refptr<MemoryDumpSessionState>& session_state() const {
118     return session_state_;
119   }
120 
121   // Returns a unique id for identifying the processes. The id can be
122   // retrieved by child processes only when tracing is enabled. This is
123   // intended to express cross-process sharing of memory dumps on the
124   // child-process side, without having to know its own child process id.
125   uint64_t GetTracingProcessId() const;
126 
127   // Returns the name for a the allocated_objects dump. Use this to declare
128   // suballocator dumps from other dump providers.
129   // It will return nullptr if there is no dump provider for the system
130   // allocator registered (which is currently the case for Mac OS).
system_allocator_pool_name()131   const char* system_allocator_pool_name() const {
132     return kSystemAllocatorPoolName;
133   };
134 
135   // When set to true, calling |RegisterMemoryDumpProvider| is a no-op.
set_dumper_registrations_ignored_for_testing(bool ignored)136   void set_dumper_registrations_ignored_for_testing(bool ignored) {
137     dumper_registrations_ignored_for_testing_ = ignored;
138   }
139 
140  private:
141   friend std::default_delete<MemoryDumpManager>;  // For the testing instance.
142   friend struct DefaultSingletonTraits<MemoryDumpManager>;
143   friend class MemoryDumpManagerDelegate;
144   friend class MemoryDumpManagerTest;
145 
146   // Descriptor used to hold information about registered MDPs.
147   // Some important considerations about lifetime of this object:
148   // - In nominal conditions, all the MemoryDumpProviderInfo instances live in
149   //   the |dump_providers_| collection (% unregistration while dumping).
150   // - Upon each dump they (actually their scoped_refptr-s) are copied into
151   //   the ProcessMemoryDumpAsyncState. This is to allow removal (see below).
152   // - When the MDP.OnMemoryDump() is invoked, the corresponding MDPInfo copy
153   //   inside ProcessMemoryDumpAsyncState is removed.
154   // - In most cases, the MDPInfo is destroyed within UnregisterDumpProvider().
155   // - If UnregisterDumpProvider() is called while a dump is in progress, the
156   //   MDPInfo is destroyed in the epilogue of ContinueAsyncProcessDump(), when
157   //   the copy inside ProcessMemoryDumpAsyncState is erase()-d.
158   // - The non-const fields of MemoryDumpProviderInfo are safe to access only
159   //   in the |task_runner| thread, unless the thread has been destroyed.
160   struct MemoryDumpProviderInfo
161       : public RefCountedThreadSafe<MemoryDumpProviderInfo> {
162     // Define a total order based on the thread (i.e. |task_runner|) affinity,
163     // so that all MDP belonging to the same thread are adjacent in the set.
164     struct Comparator {
165       bool operator()(const scoped_refptr<MemoryDumpProviderInfo>& a,
166                       const scoped_refptr<MemoryDumpProviderInfo>& b) const;
167     };
168     using OrderedSet =
169         std::set<scoped_refptr<MemoryDumpProviderInfo>, Comparator>;
170 
171     MemoryDumpProviderInfo(
172         MemoryDumpProvider* dump_provider,
173         const char* name,
174         const scoped_refptr<SingleThreadTaskRunner>& task_runner,
175         const MemoryDumpProvider::Options& options);
176 
177     MemoryDumpProvider* const dump_provider;
178 
179     // Used to transfer ownership for UnregisterAndDeleteDumpProviderSoon().
180     // nullptr in all other cases.
181     scoped_ptr<MemoryDumpProvider> owned_dump_provider;
182 
183     // Human readable name, for debugging and testing. Not necessarily unique.
184     const char* const name;
185 
186     // The task_runner affinity. Can be nullptr, in which case the dump provider
187     // will be invoked on |dump_thread_|.
188     const scoped_refptr<SingleThreadTaskRunner> task_runner;
189 
190     // The |options| arg passed to RegisterDumpProvider().
191     const MemoryDumpProvider::Options options;
192 
193     // For fail-safe logic (auto-disable failing MDPs).
194     int consecutive_failures;
195 
196     // Flagged either by the auto-disable logic or during unregistration.
197     bool disabled;
198 
199    private:
200     friend class base::RefCountedThreadSafe<MemoryDumpProviderInfo>;
201     ~MemoryDumpProviderInfo();
202 
203     DISALLOW_COPY_AND_ASSIGN(MemoryDumpProviderInfo);
204   };
205 
206   // Holds the state of a process memory dump that needs to be carried over
207   // across threads in order to fulfil an asynchronous CreateProcessDump()
208   // request. At any time exactly one thread owns a ProcessMemoryDumpAsyncState.
209   struct ProcessMemoryDumpAsyncState {
210     ProcessMemoryDumpAsyncState(
211         MemoryDumpRequestArgs req_args,
212         const MemoryDumpProviderInfo::OrderedSet& dump_providers,
213         const scoped_refptr<MemoryDumpSessionState>& session_state,
214         MemoryDumpCallback callback,
215         const scoped_refptr<SingleThreadTaskRunner>& dump_thread_task_runner);
216     ~ProcessMemoryDumpAsyncState();
217 
218     // Gets or creates the memory dump container for the given target process.
219     ProcessMemoryDump* GetOrCreateMemoryDumpContainerForProcess(ProcessId pid);
220 
221     // A map of ProcessId -> ProcessMemoryDump, one for each target process
222     // being dumped from the current process. Typically each process dumps only
223     // for itself, unless dump providers specify a different |target_process| in
224     // MemoryDumpProvider::Options.
225     std::map<ProcessId, scoped_ptr<ProcessMemoryDump>> process_dumps;
226 
227     // The arguments passed to the initial CreateProcessDump() request.
228     const MemoryDumpRequestArgs req_args;
229 
230     // An ordered sequence of dump providers that have to be invoked to complete
231     // the dump. This is a copy of |dump_providers_| at the beginning of a dump
232     // and becomes empty at the end, when all dump providers have been invoked.
233     std::vector<scoped_refptr<MemoryDumpProviderInfo>> pending_dump_providers;
234 
235     // The trace-global session state.
236     scoped_refptr<MemoryDumpSessionState> session_state;
237 
238     // Callback passed to the initial call to CreateProcessDump().
239     MemoryDumpCallback callback;
240 
241     // The thread on which FinalizeDumpAndAddToTrace() (and hence |callback|)
242     // should be invoked. This is the thread on which the initial
243     // CreateProcessDump() request was called.
244     const scoped_refptr<SingleThreadTaskRunner> callback_task_runner;
245 
246     // The thread on which unbound dump providers should be invoked.
247     // This is essentially |dump_thread_|.task_runner() but needs to be kept
248     // as a separate variable as it needs to be accessed by arbitrary dumpers'
249     // threads outside of the lock_ to avoid races when disabling tracing.
250     // It is immutable for all the duration of a tracing session.
251     const scoped_refptr<SingleThreadTaskRunner> dump_thread_task_runner;
252 
253    private:
254     DISALLOW_COPY_AND_ASSIGN(ProcessMemoryDumpAsyncState);
255   };
256 
257   static const int kMaxConsecutiveFailuresCount;
258   static const char* const kSystemAllocatorPoolName;
259 
260   MemoryDumpManager();
261   ~MemoryDumpManager() override;
262 
263   static void SetInstanceForTesting(MemoryDumpManager* instance);
264   static void FinalizeDumpAndAddToTrace(
265       scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state);
266 
267   // Internal, used only by MemoryDumpManagerDelegate.
268   // Creates a memory dump for the current process and appends it to the trace.
269   // |callback| will be invoked asynchronously upon completion on the same
270   // thread on which CreateProcessDump() was called.
271   void CreateProcessDump(const MemoryDumpRequestArgs& args,
272                          const MemoryDumpCallback& callback);
273 
274   // Continues the ProcessMemoryDump started by CreateProcessDump(), hopping
275   // across threads as needed as specified by MDPs in RegisterDumpProvider().
276   void ContinueAsyncProcessDump(
277       ProcessMemoryDumpAsyncState* owned_pmd_async_state);
278 
279   // Helper for the public UnregisterDumpProvider* functions.
280   void UnregisterDumpProviderInternal(MemoryDumpProvider* mdp,
281                                       bool take_mdp_ownership_and_delete_async);
282 
283   // An ordererd set of registered MemoryDumpProviderInfo(s), sorted by thread
284   // affinity (MDPs belonging to the same thread are adjacent).
285   MemoryDumpProviderInfo::OrderedSet dump_providers_;
286 
287   // Shared among all the PMDs to keep state scoped to the tracing session.
288   scoped_refptr<MemoryDumpSessionState> session_state_;
289 
290   MemoryDumpManagerDelegate* delegate_;  // Not owned.
291 
292   // When true, this instance is in charge of coordinating periodic dumps.
293   bool is_coordinator_;
294 
295   // Protects from concurrent accesses to the |dump_providers_*| and |delegate_|
296   // to guard against disabling logging while dumping on another thread.
297   Lock lock_;
298 
299   // Optimization to avoid attempting any memory dump (i.e. to not walk an empty
300   // dump_providers_enabled_ list) when tracing is not enabled.
301   subtle::AtomicWord memory_tracing_enabled_;
302 
303   // For time-triggered periodic dumps.
304   RepeatingTimer periodic_dump_timer_;
305 
306   // Thread used for MemoryDumpProviders which don't specify a thread affinity.
307   scoped_ptr<Thread> dump_thread_;
308 
309   // The unique id of the child process. This is created only for tracing and is
310   // expected to be valid only when tracing is enabled.
311   uint64_t tracing_process_id_;
312 
313   // When true, calling |RegisterMemoryDumpProvider| is a no-op.
314   bool dumper_registrations_ignored_for_testing_;
315 
316   // Whether new memory dump providers should be told to enable heap profiling.
317   bool heap_profiling_enabled_;
318 
319   DISALLOW_COPY_AND_ASSIGN(MemoryDumpManager);
320 };
321 
322 // The delegate is supposed to be long lived (read: a Singleton) and thread
323 // safe (i.e. should expect calls from any thread and handle thread hopping).
324 class BASE_EXPORT MemoryDumpManagerDelegate {
325  public:
326   virtual void RequestGlobalMemoryDump(const MemoryDumpRequestArgs& args,
327                                        const MemoryDumpCallback& callback) = 0;
328 
329   // Returns tracing process id of the current process. This is used by
330   // MemoryDumpManager::GetTracingProcessId.
331   virtual uint64_t GetTracingProcessId() const = 0;
332 
333  protected:
334   MemoryDumpManagerDelegate() {}
335   virtual ~MemoryDumpManagerDelegate() {}
336 
337   void CreateProcessDump(const MemoryDumpRequestArgs& args,
338                          const MemoryDumpCallback& callback) {
339     MemoryDumpManager::GetInstance()->CreateProcessDump(args, callback);
340   }
341 
342  private:
343   DISALLOW_COPY_AND_ASSIGN(MemoryDumpManagerDelegate);
344 };
345 
346 }  // namespace trace_event
347 }  // namespace base
348 
349 #endif  // BASE_TRACE_EVENT_MEMORY_DUMP_MANAGER_H_
350