Home | History | Annotate | Download | only in trace_event
      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.
    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).
    131   const char* system_allocator_pool_name() const {
    132     return kSystemAllocatorPoolName;
    133   };
    134 
    135   // When set to true, calling |RegisterMemoryDumpProvider| is a no-op.
    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