summaryrefslogtreecommitdiffstats
path: root/base/trace_event/memory_dump_manager.h
blob: e918a773a6d371aae386133b06ed8eb3e0d596c7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef BASE_TRACE_EVENT_MEMORY_DUMP_MANAGER_H_
#define BASE_TRACE_EVENT_MEMORY_DUMP_MANAGER_H_

#include <set>

#include "base/atomicops.h"
#include "base/containers/hash_tables.h"
#include "base/memory/ref_counted.h"
#include "base/memory/singleton.h"
#include "base/synchronization/lock.h"
#include "base/timer/timer.h"
#include "base/trace_event/memory_dump_request_args.h"
#include "base/trace_event/process_memory_dump.h"
#include "base/trace_event/trace_event.h"

namespace base {

class SingleThreadTaskRunner;

namespace trace_event {

class MemoryDumpManagerDelegate;
class MemoryDumpProvider;
class MemoryDumpSessionState;

// This is the interface exposed to the rest of the codebase to deal with
// memory tracing. The main entry point for clients is represented by
// RequestDumpPoint(). The extension by Un(RegisterDumpProvider).
class BASE_EXPORT MemoryDumpManager : public TraceLog::EnabledStateObserver {
 public:
  static const char* const kTraceCategoryForTesting;

  // This value is returned as the tracing id of the child processes by
  // GetTracingProcessId() when tracing is not enabled.
  static const uint64 kInvalidTracingProcessId;

  static MemoryDumpManager* GetInstance();

  // Invoked once per process to register the TraceLog observer.
  void Initialize();

  // See the lifetime and thread-safety requirements on the delegate below in
  // the |MemoryDumpManagerDelegate| docstring.
  void SetDelegate(MemoryDumpManagerDelegate* delegate);

  // MemoryDumpManager does NOT take memory ownership of |mdp|, which is
  // expected to either be a singleton or unregister itself.
  // If the optional |task_runner| argument is non-null, all the calls to the
  // |mdp| will be issues on the given thread. Otherwise, the |mdp| should be
  // able to handle calls on arbitrary threads.
  void RegisterDumpProvider(
      MemoryDumpProvider* mdp,
      const scoped_refptr<SingleThreadTaskRunner>& task_runner);
  void RegisterDumpProvider(MemoryDumpProvider* mdp);
  void UnregisterDumpProvider(MemoryDumpProvider* mdp);

  // Requests a memory dump. The dump might happen or not depending on the
  // filters and categories specified when enabling tracing.
  // The optional |callback| is executed asynchronously, on an arbitrary thread,
  // to notify about the completion of the global dump (i.e. after all the
  // processes have dumped) and its success (true iff all the dumps were
  // successful).
  void RequestGlobalDump(MemoryDumpType dump_type,
                         const MemoryDumpCallback& callback);

  // Same as above (still asynchronous), but without callback.
  void RequestGlobalDump(MemoryDumpType dump_type);

  // TraceLog::EnabledStateObserver implementation.
  void OnTraceLogEnabled() override;
  void OnTraceLogDisabled() override;

  // Returns the MemoryDumpSessionState object, which is shared by all the
  // ProcessMemoryDump and MemoryAllocatorDump instances through all the tracing
  // session lifetime.
  const scoped_refptr<MemoryDumpSessionState>& session_state() const {
    return session_state_;
  }

  // Returns a unique id for identifying the processes. The id can be
  // retrieved by child processes only when tracing is enabled. This is
  // intended to express cross-process sharing of memory dumps on the
  // child-process side, without having to know its own child process id.
  uint64 GetTracingProcessId() const;

  // Returns the name for a the allocated_objects dump. Use this to declare
  // suballocator dumps from other dump providers.
  // It should not return nullptr after the manager has been initialized.
  const char* system_allocator_pool_name() const {
    return system_allocator_pool_name_;
  };

 private:
  friend struct DefaultDeleter<MemoryDumpManager>;  // For the testing instance.
  friend struct DefaultSingletonTraits<MemoryDumpManager>;
  friend class MemoryDumpManagerDelegate;
  friend class MemoryDumpManagerTest;
  FRIEND_TEST_ALL_PREFIXES(MemoryDumpManagerTest, DisableFailingDumpers);

  // Descriptor struct used to hold information about registered MDPs. It is
  // deliberately copyable, in order to allow it to be used as std::set value.
  struct MemoryDumpProviderInfo {
    MemoryDumpProviderInfo(
        MemoryDumpProvider* dump_provider,
        const scoped_refptr<SingleThreadTaskRunner>& task_runner);
    ~MemoryDumpProviderInfo();

    // Define a total order based on the thread (i.e. |task_runner|) affinity,
    // so that all MDP belonging to the same thread are adjacent in the set.
    bool operator<(const MemoryDumpProviderInfo& other) const;

    MemoryDumpProvider* const dump_provider;
    scoped_refptr<SingleThreadTaskRunner> task_runner;  // Optional.

    // For fail-safe logic (auto-disable failing MDPs). These fields are mutable
    // as can be safely changed without impacting the order within the set.
    mutable int consecutive_failures;
    mutable bool disabled;
  };

  using MemoryDumpProviderInfoSet = std::set<MemoryDumpProviderInfo>;

  // Holds the state of a process memory dump that needs to be carried over
  // across threads in order to fulfil an asynchronous CreateProcessDump()
  // request. At any time exactly one thread owns a ProcessMemoryDumpAsyncState.
  struct ProcessMemoryDumpAsyncState {
    ProcessMemoryDumpAsyncState(
        MemoryDumpRequestArgs req_args,
        MemoryDumpProviderInfoSet::iterator next_dump_provider,
        const scoped_refptr<MemoryDumpSessionState>& session_state,
        MemoryDumpCallback callback);
    ~ProcessMemoryDumpAsyncState();

    // The ProcessMemoryDump container, where each dump provider will dump its
    // own MemoryAllocatorDump(s) upon the OnMemoryDump() call.
    ProcessMemoryDump process_memory_dump;

    // The arguments passed to the initial CreateProcessDump() request.
    const MemoryDumpRequestArgs req_args;

    // The |dump_providers_| iterator to the next dump provider that should be
    // invoked (or dump_providers_.end() if at the end of the sequence).
    MemoryDumpProviderInfoSet::iterator next_dump_provider;

    // Callback passed to the initial call to CreateProcessDump().
    MemoryDumpCallback callback;

    // The thread on which FinalizeDumpAndAddToTrace() (and hence |callback|)
    // should be invoked. This is the thread on which the initial
    // CreateProcessDump() request was called.
    const scoped_refptr<SingleThreadTaskRunner> task_runner;

   private:
    DISALLOW_COPY_AND_ASSIGN(ProcessMemoryDumpAsyncState);
  };

  static const int kMaxConsecutiveFailuresCount;

  MemoryDumpManager();
  ~MemoryDumpManager() override;

  static void SetInstanceForTesting(MemoryDumpManager* instance);
  static void FinalizeDumpAndAddToTrace(
      scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state);
  static void AbortDumpLocked(MemoryDumpCallback callback,
                              scoped_refptr<SingleThreadTaskRunner> task_runner,
                              uint64 dump_guid);

  // Internal, used only by MemoryDumpManagerDelegate.
  // Creates a memory dump for the current process and appends it to the trace.
  // |callback| will be invoked asynchronously upon completion on the same
  // thread on which CreateProcessDump() was called.
  void CreateProcessDump(const MemoryDumpRequestArgs& args,
                         const MemoryDumpCallback& callback);

  // Continues the ProcessMemoryDump started by CreateProcessDump(), hopping
  // across threads as needed as specified by MDPs in RegisterDumpProvider().
  void ContinueAsyncProcessDump(
      scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state);

  // An ordererd set of registered MemoryDumpProviderInfo(s), sorted by thread
  // affinity (MDPs belonging to the same thread are adjacent).
  MemoryDumpProviderInfoSet dump_providers_;

  // Flag used to signal that some provider was removed from |dump_providers_|
  // and therefore the current memory dump (if any) should be aborted.
  bool did_unregister_dump_provider_;

  // Shared among all the PMDs to keep state scoped to the tracing session.
  scoped_refptr<MemoryDumpSessionState> session_state_;

  MemoryDumpManagerDelegate* delegate_;  // Not owned.

  // Protects from concurrent accesses to the |dump_providers_*| and |delegate_|
  // to guard against disabling logging while dumping on another thread.
  Lock lock_;

  // Optimization to avoid attempting any memory dump (i.e. to not walk an empty
  // dump_providers_enabled_ list) when tracing is not enabled.
  subtle::AtomicWord memory_tracing_enabled_;

  // For time-triggered periodic dumps.
  RepeatingTimer<MemoryDumpManager> periodic_dump_timer_;

  // The unique id of the child process. This is created only for tracing and is
  // expected to be valid only when tracing is enabled.
  uint64 tracing_process_id_;

  // Name of the allocated_objects dump.
  const char* system_allocator_pool_name_;

  // Skips the auto-registration of the core dumpers during Initialize().
  bool skip_core_dumpers_auto_registration_for_testing_;

  DISALLOW_COPY_AND_ASSIGN(MemoryDumpManager);
};

// The delegate is supposed to be long lived (read: a Singleton) and thread
// safe (i.e. should expect calls from any thread and handle thread hopping).
class BASE_EXPORT MemoryDumpManagerDelegate {
 public:
  virtual void RequestGlobalMemoryDump(const MemoryDumpRequestArgs& args,
                                       const MemoryDumpCallback& callback) = 0;

  // Determines whether the MemoryDumpManager instance should be the master
  // (the ones which initiates and coordinates the multiprocess dumps) or not.
  virtual bool IsCoordinatorProcess() const = 0;

  // Returns tracing process id of the current process. This is used by
  // MemoryDumpManager::GetTracingProcessId.
  virtual uint64 GetTracingProcessId() const = 0;

 protected:
  MemoryDumpManagerDelegate() {}
  virtual ~MemoryDumpManagerDelegate() {}

  void CreateProcessDump(const MemoryDumpRequestArgs& args,
                         const MemoryDumpCallback& callback) {
    MemoryDumpManager::GetInstance()->CreateProcessDump(args, callback);
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(MemoryDumpManagerDelegate);
};

}  // namespace trace_event
}  // namespace base

#endif  // BASE_TRACE_EVENT_MEMORY_DUMP_MANAGER_H_