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