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
26namespace base {
27
28class SingleThreadTaskRunner;
29class Thread;
30
31namespace trace_event {
32
33class MemoryDumpManagerDelegate;
34class MemoryDumpProvider;
35class 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).
40class 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.
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).
140  const char* system_allocator_pool_name() const {
141    return kSystemAllocatorPoolName;
142  };
143
144  // When set to true, calling |RegisterMemoryDumpProvider| is a no-op.
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).
385class 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