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 <unordered_set>
13 #include <vector>
14 
15 #include "base/atomicops.h"
16 #include "base/macros.h"
17 #include "base/memory/ref_counted.h"
18 #include "base/memory/singleton.h"
19 #include "base/synchronization/lock.h"
20 #include "base/trace_event/memory_allocator_dump.h"
21 #include "base/trace_event/memory_dump_provider_info.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 SequencedTaskRunner;
29 class SingleThreadTaskRunner;
30 class Thread;
31 
32 namespace trace_event {
33 
34 class MemoryDumpProvider;
35 
36 // This is the interface exposed to the rest of the codebase to deal with
37 // memory tracing. The main entry point for clients is represented by
38 // RequestDumpPoint(). The extension by Un(RegisterDumpProvider).
39 class BASE_EXPORT MemoryDumpManager {
40  public:
41   using RequestGlobalDumpFunction =
42       RepeatingCallback<void(MemoryDumpType, MemoryDumpLevelOfDetail)>;
43 
44   static constexpr const char* const kTraceCategory =
45       TRACE_DISABLED_BY_DEFAULT("memory-infra");
46 
47   // This value is returned as the tracing id of the child processes by
48   // GetTracingProcessId() when tracing is not enabled.
49   static const uint64_t kInvalidTracingProcessId;
50 
51   static MemoryDumpManager* GetInstance();
52   static std::unique_ptr<MemoryDumpManager> CreateInstanceForTesting();
53 
54   // Invoked once per process to listen to trace begin / end events.
55   // Initialization can happen after (Un)RegisterMemoryDumpProvider() calls
56   // and the MemoryDumpManager guarantees to support this.
57   // On the other side, the MemoryDumpManager will not be fully operational
58   // (any CreateProcessDump() will return a failure) until initialized.
59   // Arguments:
60   //  is_coordinator: True when current process coordinates the periodic dump
61   //      triggering.
62   //  request_dump_function: Function to invoke a global dump. Global dump
63   //      involves embedder-specific behaviors like multiprocess handshaking.
64   //      TODO(primiano): this is only required to trigger global dumps from
65   //      the scheduler. Should be removed once they are both moved out of base.
66   void Initialize(RequestGlobalDumpFunction request_dump_function,
67                   bool is_coordinator);
68 
69   // (Un)Registers a MemoryDumpProvider instance.
70   // Args:
71   //  - mdp: the MemoryDumpProvider instance to be registered. MemoryDumpManager
72   //      does NOT take memory ownership of |mdp|, which is expected to either
73   //      be a singleton or unregister itself.
74   //  - name: a friendly name (duplicates allowed). Used for debugging and
75   //      run-time profiling of memory-infra internals. Must be a long-lived
76   //      C string.
77   //  - task_runner: either a SingleThreadTaskRunner or SequencedTaskRunner. All
78   //      the calls to |mdp| will be run on the given |task_runner|. If passed
79   //      null |mdp| should be able to handle calls on arbitrary threads.
80   //  - options: extra optional arguments. See memory_dump_provider.h.
81   void RegisterDumpProvider(MemoryDumpProvider* mdp,
82                             const char* name,
83                             scoped_refptr<SingleThreadTaskRunner> task_runner);
84   void RegisterDumpProvider(MemoryDumpProvider* mdp,
85                             const char* name,
86                             scoped_refptr<SingleThreadTaskRunner> task_runner,
87                             MemoryDumpProvider::Options options);
88   void RegisterDumpProviderWithSequencedTaskRunner(
89       MemoryDumpProvider* mdp,
90       const char* name,
91       scoped_refptr<SequencedTaskRunner> task_runner,
92       MemoryDumpProvider::Options options);
93   void UnregisterDumpProvider(MemoryDumpProvider* mdp);
94 
95   // Unregisters an unbound dump provider and takes care about its deletion
96   // asynchronously. Can be used only for for dump providers with no
97   // task-runner affinity.
98   // This method takes ownership of the dump provider and guarantees that:
99   //  - The |mdp| will be deleted at some point in the near future.
100   //  - Its deletion will not happen concurrently with the OnMemoryDump() call.
101   // Note that OnMemoryDump() calls can still happen after this method returns.
102   void UnregisterAndDeleteDumpProviderSoon(
103       std::unique_ptr<MemoryDumpProvider> mdp);
104 
105   // Prepare MemoryDumpManager for CreateProcessDump() calls for tracing-related
106   // modes (i.e. |level_of_detail| != SUMMARY_ONLY).
107   // Also initializes the scheduler with the given config.
108   void SetupForTracing(const TraceConfig::MemoryDumpConfig&);
109 
110   // Tear-down tracing related state.
111   // Non-tracing modes (e.g. SUMMARY_ONLY) will continue to work.
112   void TeardownForTracing();
113 
114   // Creates a memory dump for the current process and appends it to the trace.
115   // |callback| will be invoked asynchronously upon completion on the same
116   // thread on which CreateProcessDump() was called. This method should only be
117   // used by the memory-infra service while creating a global memory dump.
118   void CreateProcessDump(const MemoryDumpRequestArgs& args,
119                          ProcessMemoryDumpCallback callback);
120 
121   // Lets tests see if a dump provider is registered.
122   bool IsDumpProviderRegisteredForTesting(MemoryDumpProvider*);
123 
124   // Returns a unique id for identifying the processes. The id can be
125   // retrieved by child processes only when tracing is enabled. This is
126   // intended to express cross-process sharing of memory dumps on the
127   // child-process side, without having to know its own child process id.
GetTracingProcessId()128   uint64_t GetTracingProcessId() const { return tracing_process_id_; }
set_tracing_process_id(uint64_t tracing_process_id)129   void set_tracing_process_id(uint64_t tracing_process_id) {
130     tracing_process_id_ = tracing_process_id;
131   }
132 
133   // Returns the name for a the allocated_objects dump. Use this to declare
134   // suballocator dumps from other dump providers.
135   // It will return nullptr if there is no dump provider for the system
136   // allocator registered (which is currently the case for Mac OS).
system_allocator_pool_name()137   const char* system_allocator_pool_name() const {
138     return kSystemAllocatorPoolName;
139   }
140 
141   // When set to true, calling |RegisterMemoryDumpProvider| is a no-op.
set_dumper_registrations_ignored_for_testing(bool ignored)142   void set_dumper_registrations_ignored_for_testing(bool ignored) {
143     dumper_registrations_ignored_for_testing_ = ignored;
144   }
145 
146   scoped_refptr<SequencedTaskRunner> GetDumpThreadTaskRunner();
147 
148  private:
149   friend std::default_delete<MemoryDumpManager>;  // For the testing instance.
150   friend struct DefaultSingletonTraits<MemoryDumpManager>;
151   friend class MemoryDumpManagerTest;
152   FRIEND_TEST_ALL_PREFIXES(MemoryDumpManagerTest,
153                            NoStackOverflowWithTooManyMDPs);
154 
155   // Holds the state of a process memory dump that needs to be carried over
156   // across task runners in order to fulfill an asynchronous CreateProcessDump()
157   // request. At any time exactly one task runner owns a
158   // ProcessMemoryDumpAsyncState.
159   struct ProcessMemoryDumpAsyncState {
160     ProcessMemoryDumpAsyncState(
161         MemoryDumpRequestArgs req_args,
162         const MemoryDumpProviderInfo::OrderedSet& dump_providers,
163         ProcessMemoryDumpCallback callback,
164         scoped_refptr<SequencedTaskRunner> dump_thread_task_runner);
165     ~ProcessMemoryDumpAsyncState();
166 
167     // A ProcessMemoryDump to collect data from MemoryDumpProviders.
168     std::unique_ptr<ProcessMemoryDump> process_memory_dump;
169 
170     // The arguments passed to the initial CreateProcessDump() request.
171     const MemoryDumpRequestArgs req_args;
172 
173     // An ordered sequence of dump providers that have to be invoked to complete
174     // the dump. This is a copy of |dump_providers_| at the beginning of a dump
175     // and becomes empty at the end, when all dump providers have been invoked.
176     std::vector<scoped_refptr<MemoryDumpProviderInfo>> pending_dump_providers;
177 
178     // Callback passed to the initial call to CreateProcessDump().
179     ProcessMemoryDumpCallback callback;
180 
181     // The thread on which FinishAsyncProcessDump() (and hence |callback|)
182     // should be invoked. This is the thread on which the initial
183     // CreateProcessDump() request was called.
184     const scoped_refptr<SingleThreadTaskRunner> callback_task_runner;
185 
186     // The thread on which unbound dump providers should be invoked.
187     // This is essentially |dump_thread_|.task_runner() but needs to be kept
188     // as a separate variable as it needs to be accessed by arbitrary dumpers'
189     // threads outside of the lock_ to avoid races when disabling tracing.
190     // It is immutable for all the duration of a tracing session.
191     const scoped_refptr<SequencedTaskRunner> dump_thread_task_runner;
192 
193    private:
194     DISALLOW_COPY_AND_ASSIGN(ProcessMemoryDumpAsyncState);
195   };
196 
197   static const int kMaxConsecutiveFailuresCount;
198   static const char* const kSystemAllocatorPoolName;
199 
200   MemoryDumpManager();
201   virtual ~MemoryDumpManager();
202 
203   static void SetInstanceForTesting(MemoryDumpManager* instance);
204 
205   // Lazily initializes dump_thread_ and returns its TaskRunner.
206   scoped_refptr<base::SequencedTaskRunner> GetOrCreateBgTaskRunnerLocked();
207 
208   // Calls InvokeOnMemoryDump() for the each MDP that belongs to the current
209   // task runner and switches to the task runner of the next MDP. Handles
210   // failures in MDP and thread hops, and always calls FinishAsyncProcessDump()
211   // at the end.
212   void ContinueAsyncProcessDump(
213       ProcessMemoryDumpAsyncState* owned_pmd_async_state);
214 
215   // Invokes OnMemoryDump() of the given MDP. Should be called on the MDP task
216   // runner.
217   void InvokeOnMemoryDump(MemoryDumpProviderInfo* mdpinfo,
218                           ProcessMemoryDump* pmd);
219 
220   void FinishAsyncProcessDump(
221       std::unique_ptr<ProcessMemoryDumpAsyncState> pmd_async_state);
222 
223   // Helper for RegierDumpProvider* functions.
224   void RegisterDumpProviderInternal(
225       MemoryDumpProvider* mdp,
226       const char* name,
227       scoped_refptr<SequencedTaskRunner> task_runner,
228       const MemoryDumpProvider::Options& options);
229 
230   // Helper for the public UnregisterDumpProvider* functions.
231   void UnregisterDumpProviderInternal(MemoryDumpProvider* mdp,
232                                       bool take_mdp_ownership_and_delete_async);
233 
234   bool can_request_global_dumps() const {
235     return !request_dump_function_.is_null();
236   }
237 
238   // An ordered set of registered MemoryDumpProviderInfo(s), sorted by task
239   // runner affinity (MDPs belonging to the same task runners are adjacent).
240   MemoryDumpProviderInfo::OrderedSet dump_providers_;
241 
242   // Function provided by the embedder to handle global dump requests.
243   RequestGlobalDumpFunction request_dump_function_;
244 
245   // True when current process coordinates the periodic dump triggering.
246   bool is_coordinator_;
247 
248   // Protects from concurrent accesses to the local state, eg: to guard against
249   // disabling logging while dumping on another thread.
250   Lock lock_;
251 
252   // Thread used for MemoryDumpProviders which don't specify a task runner
253   // affinity.
254   std::unique_ptr<Thread> dump_thread_;
255 
256   // The unique id of the child process. This is created only for tracing and is
257   // expected to be valid only when tracing is enabled.
258   uint64_t tracing_process_id_;
259 
260   // When true, calling |RegisterMemoryDumpProvider| is a no-op.
261   bool dumper_registrations_ignored_for_testing_;
262 
263   DISALLOW_COPY_AND_ASSIGN(MemoryDumpManager);
264 };
265 
266 }  // namespace trace_event
267 }  // namespace base
268 
269 #endif  // BASE_TRACE_EVENT_MEMORY_DUMP_MANAGER_H_
270