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 <unordered_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/trace_event/memory_allocator_dump.h"
     22 #include "base/trace_event/memory_dump_provider_info.h"
     23 #include "base/trace_event/memory_dump_request_args.h"
     24 #include "base/trace_event/process_memory_dump.h"
     25 #include "base/trace_event/trace_event.h"
     26 
     27 // Forward declare |MemoryDumpManagerDelegateImplTest| so that we can make it a
     28 // friend of |MemoryDumpManager| and give it access to |SetInstanceForTesting|.
     29 namespace memory_instrumentation {
     30 
     31 class MemoryDumpManagerDelegateImplTest;
     32 
     33 }  // namespace memory_instrumentation
     34 
     35 namespace base {
     36 
     37 class SingleThreadTaskRunner;
     38 class Thread;
     39 
     40 namespace trace_event {
     41 
     42 class MemoryDumpManagerDelegate;
     43 class MemoryDumpProvider;
     44 class MemoryDumpSessionState;
     45 class MemoryDumpScheduler;
     46 
     47 // This is the interface exposed to the rest of the codebase to deal with
     48 // memory tracing. The main entry point for clients is represented by
     49 // RequestDumpPoint(). The extension by Un(RegisterDumpProvider).
     50 class BASE_EXPORT MemoryDumpManager : public TraceLog::EnabledStateObserver {
     51  public:
     52   static const char* const kTraceCategory;
     53   static const char* const kLogPrefix;
     54 
     55   // This value is returned as the tracing id of the child processes by
     56   // GetTracingProcessId() when tracing is not enabled.
     57   static const uint64_t kInvalidTracingProcessId;
     58 
     59   static MemoryDumpManager* GetInstance();
     60 
     61   // Invoked once per process to listen to trace begin / end events.
     62   // Initialization can happen after (Un)RegisterMemoryDumpProvider() calls
     63   // and the MemoryDumpManager guarantees to support this.
     64   // On the other side, the MemoryDumpManager will not be fully operational
     65   // (i.e. will NACK any RequestGlobalMemoryDump()) until initialized.
     66   // Arguments:
     67   //  delegate: inversion-of-control interface for embedder-specific behaviors
     68   //      (multiprocess handshaking). See the lifetime and thread-safety
     69   //      requirements in the |MemoryDumpManagerDelegate| docstring.
     70   void Initialize(std::unique_ptr<MemoryDumpManagerDelegate> delegate);
     71 
     72   // (Un)Registers a MemoryDumpProvider instance.
     73   // Args:
     74   //  - mdp: the MemoryDumpProvider instance to be registered. MemoryDumpManager
     75   //      does NOT take memory ownership of |mdp|, which is expected to either
     76   //      be a singleton or unregister itself.
     77   //  - name: a friendly name (duplicates allowed). Used for debugging and
     78   //      run-time profiling of memory-infra internals. Must be a long-lived
     79   //      C string.
     80   //  - task_runner: either a SingleThreadTaskRunner or SequencedTaskRunner. All
     81   //      the calls to |mdp| will be run on the given |task_runner|. If passed
     82   //      null |mdp| should be able to handle calls on arbitrary threads.
     83   //  - options: extra optional arguments. See memory_dump_provider.h.
     84   void RegisterDumpProvider(MemoryDumpProvider* mdp,
     85                             const char* name,
     86                             scoped_refptr<SingleThreadTaskRunner> task_runner);
     87   void RegisterDumpProvider(MemoryDumpProvider* mdp,
     88                             const char* name,
     89                             scoped_refptr<SingleThreadTaskRunner> task_runner,
     90                             MemoryDumpProvider::Options options);
     91   void RegisterDumpProviderWithSequencedTaskRunner(
     92       MemoryDumpProvider* mdp,
     93       const char* name,
     94       scoped_refptr<SequencedTaskRunner> task_runner,
     95       MemoryDumpProvider::Options options);
     96   void UnregisterDumpProvider(MemoryDumpProvider* mdp);
     97 
     98   // Unregisters an unbound dump provider and takes care about its deletion
     99   // asynchronously. Can be used only for for dump providers with no
    100   // task-runner affinity.
    101   // This method takes ownership of the dump provider and guarantees that:
    102   //  - The |mdp| will be deleted at some point in the near future.
    103   //  - Its deletion will not happen concurrently with the OnMemoryDump() call.
    104   // Note that OnMemoryDump() and PollFastMemoryTotal() calls can still happen
    105   // after this method returns.
    106   void UnregisterAndDeleteDumpProviderSoon(
    107       std::unique_ptr<MemoryDumpProvider> mdp);
    108 
    109   // Requests a memory dump. The dump might happen or not depending on the
    110   // filters and categories specified when enabling tracing.
    111   // The optional |callback| is executed asynchronously, on an arbitrary thread,
    112   // to notify about the completion of the global dump (i.e. after all the
    113   // processes have dumped) and its success (true iff all the dumps were
    114   // successful).
    115   void RequestGlobalDump(MemoryDumpType dump_type,
    116                          MemoryDumpLevelOfDetail level_of_detail,
    117                          const MemoryDumpCallback& callback);
    118 
    119   // Same as above (still asynchronous), but without callback.
    120   void RequestGlobalDump(MemoryDumpType dump_type,
    121                          MemoryDumpLevelOfDetail level_of_detail);
    122 
    123   // TraceLog::EnabledStateObserver implementation.
    124   void OnTraceLogEnabled() override;
    125   void OnTraceLogDisabled() override;
    126 
    127   // Enable heap profiling if kEnableHeapProfiling is specified.
    128   void EnableHeapProfilingIfNeeded();
    129 
    130   // Returns true if the dump mode is allowed for current tracing session.
    131   bool IsDumpModeAllowed(MemoryDumpLevelOfDetail dump_mode);
    132 
    133   // Lets tests see if a dump provider is registered.
    134   bool IsDumpProviderRegisteredForTesting(MemoryDumpProvider*);
    135 
    136   // Returns the MemoryDumpSessionState object, which is shared by all the
    137   // ProcessMemoryDump and MemoryAllocatorDump instances through all the tracing
    138   // session lifetime.
    139   const scoped_refptr<MemoryDumpSessionState>& session_state_for_testing()
    140       const {
    141     return session_state_;
    142   }
    143 
    144   // Returns a unique id for identifying the processes. The id can be
    145   // retrieved by child processes only when tracing is enabled. This is
    146   // intended to express cross-process sharing of memory dumps on the
    147   // child-process side, without having to know its own child process id.
    148   uint64_t GetTracingProcessId() const { return tracing_process_id_; }
    149   void set_tracing_process_id(uint64_t tracing_process_id) {
    150     tracing_process_id_ = tracing_process_id;
    151   }
    152 
    153   // Returns the name for a the allocated_objects dump. Use this to declare
    154   // suballocator dumps from other dump providers.
    155   // It will return nullptr if there is no dump provider for the system
    156   // allocator registered (which is currently the case for Mac OS).
    157   const char* system_allocator_pool_name() const {
    158     return kSystemAllocatorPoolName;
    159   };
    160 
    161   // When set to true, calling |RegisterMemoryDumpProvider| is a no-op.
    162   void set_dumper_registrations_ignored_for_testing(bool ignored) {
    163     dumper_registrations_ignored_for_testing_ = ignored;
    164   }
    165 
    166  private:
    167   friend std::default_delete<MemoryDumpManager>;  // For the testing instance.
    168   friend struct DefaultSingletonTraits<MemoryDumpManager>;
    169   friend class MemoryDumpManagerDelegate;
    170   friend class MemoryDumpManagerTest;
    171   friend class MemoryDumpScheduler;
    172   friend class memory_instrumentation::MemoryDumpManagerDelegateImplTest;
    173 
    174   // Holds the state of a process memory dump that needs to be carried over
    175   // across task runners in order to fulfil an asynchronous CreateProcessDump()
    176   // request. At any time exactly one task runner owns a
    177   // ProcessMemoryDumpAsyncState.
    178   struct ProcessMemoryDumpAsyncState {
    179     ProcessMemoryDumpAsyncState(
    180         MemoryDumpRequestArgs req_args,
    181         const MemoryDumpProviderInfo::OrderedSet& dump_providers,
    182         scoped_refptr<MemoryDumpSessionState> session_state,
    183         MemoryDumpCallback callback,
    184         scoped_refptr<SingleThreadTaskRunner> dump_thread_task_runner);
    185     ~ProcessMemoryDumpAsyncState();
    186 
    187     // Gets or creates the memory dump container for the given target process.
    188     ProcessMemoryDump* GetOrCreateMemoryDumpContainerForProcess(
    189         ProcessId pid,
    190         const MemoryDumpArgs& dump_args);
    191 
    192     // A map of ProcessId -> ProcessMemoryDump, one for each target process
    193     // being dumped from the current process. Typically each process dumps only
    194     // for itself, unless dump providers specify a different |target_process| in
    195     // MemoryDumpProvider::Options.
    196     std::map<ProcessId, std::unique_ptr<ProcessMemoryDump>> process_dumps;
    197 
    198     // The arguments passed to the initial CreateProcessDump() request.
    199     const MemoryDumpRequestArgs req_args;
    200 
    201     // An ordered sequence of dump providers that have to be invoked to complete
    202     // the dump. This is a copy of |dump_providers_| at the beginning of a dump
    203     // and becomes empty at the end, when all dump providers have been invoked.
    204     std::vector<scoped_refptr<MemoryDumpProviderInfo>> pending_dump_providers;
    205 
    206     // The trace-global session state.
    207     scoped_refptr<MemoryDumpSessionState> session_state;
    208 
    209     // Callback passed to the initial call to CreateProcessDump().
    210     MemoryDumpCallback callback;
    211 
    212     // The |success| field that will be passed as argument to the |callback|.
    213     bool dump_successful;
    214 
    215     // The thread on which FinalizeDumpAndAddToTrace() (and hence |callback|)
    216     // should be invoked. This is the thread on which the initial
    217     // CreateProcessDump() request was called.
    218     const scoped_refptr<SingleThreadTaskRunner> callback_task_runner;
    219 
    220     // The thread on which unbound dump providers should be invoked.
    221     // This is essentially |dump_thread_|.task_runner() but needs to be kept
    222     // as a separate variable as it needs to be accessed by arbitrary dumpers'
    223     // threads outside of the lock_ to avoid races when disabling tracing.
    224     // It is immutable for all the duration of a tracing session.
    225     const scoped_refptr<SingleThreadTaskRunner> dump_thread_task_runner;
    226 
    227    private:
    228     DISALLOW_COPY_AND_ASSIGN(ProcessMemoryDumpAsyncState);
    229   };
    230 
    231   static const int kMaxConsecutiveFailuresCount;
    232   static const char* const kSystemAllocatorPoolName;
    233 
    234   MemoryDumpManager();
    235   ~MemoryDumpManager() override;
    236 
    237   static void SetInstanceForTesting(MemoryDumpManager* instance);
    238   static uint32_t GetDumpsSumKb(const std::string&, const ProcessMemoryDump*);
    239   static void FinalizeDumpAndAddToTrace(
    240       std::unique_ptr<ProcessMemoryDumpAsyncState> pmd_async_state);
    241 
    242   // Internal, used only by MemoryDumpManagerDelegate.
    243   // Creates a memory dump for the current process and appends it to the trace.
    244   // |callback| will be invoked asynchronously upon completion on the same
    245   // thread on which CreateProcessDump() was called.
    246   void CreateProcessDump(const MemoryDumpRequestArgs& args,
    247                          const MemoryDumpCallback& callback);
    248 
    249   // Calls InvokeOnMemoryDump() for the next MDP on the task runner specified by
    250   // the MDP while registration. On failure to do so, skips and continues to
    251   // next MDP.
    252   void SetupNextMemoryDump(
    253       std::unique_ptr<ProcessMemoryDumpAsyncState> pmd_async_state);
    254 
    255   // Invokes OnMemoryDump() of the next MDP and calls SetupNextMemoryDump() at
    256   // the end to continue the ProcessMemoryDump. Should be called on the MDP task
    257   // runner.
    258   void InvokeOnMemoryDump(ProcessMemoryDumpAsyncState* owned_pmd_async_state);
    259 
    260   // Records a quick total memory usage in |memory_total|. This is used to track
    261   // and detect peaks in the memory usage of the process without having to
    262   // record all data from dump providers. This value is approximate to trade-off
    263   // speed, and not consistent with the rest of the memory-infra metrics. Must
    264   // be called on the dump thread.
    265   // Returns true if |memory_total| was updated by polling at least 1 MDP.
    266   bool PollFastMemoryTotal(uint64_t* memory_total);
    267 
    268   // Helper for RegierDumpProvider* functions.
    269   void RegisterDumpProviderInternal(
    270       MemoryDumpProvider* mdp,
    271       const char* name,
    272       scoped_refptr<SequencedTaskRunner> task_runner,
    273       const MemoryDumpProvider::Options& options);
    274 
    275   // Helper for the public UnregisterDumpProvider* functions.
    276   void UnregisterDumpProviderInternal(MemoryDumpProvider* mdp,
    277                                       bool take_mdp_ownership_and_delete_async);
    278 
    279   // Adds / removes provider that supports polling to
    280   // |dump_providers_for_polling_|.
    281   void RegisterPollingMDPOnDumpThread(
    282       scoped_refptr<MemoryDumpProviderInfo> mdpinfo);
    283   void UnregisterPollingMDPOnDumpThread(
    284       scoped_refptr<MemoryDumpProviderInfo> mdpinfo);
    285 
    286   // An ordererd set of registered MemoryDumpProviderInfo(s), sorted by task
    287   // runner affinity (MDPs belonging to the same task runners are adjacent).
    288   MemoryDumpProviderInfo::OrderedSet dump_providers_;
    289 
    290   // A copy of mdpinfo list that support polling. It must be accessed only on
    291   // the dump thread if dump thread exists.
    292   MemoryDumpProviderInfo::OrderedSet dump_providers_for_polling_;
    293 
    294   // Shared among all the PMDs to keep state scoped to the tracing session.
    295   scoped_refptr<MemoryDumpSessionState> session_state_;
    296 
    297   // The list of names of dump providers that are blacklisted from strict thread
    298   // affinity check on unregistration.
    299   std::unordered_set<StringPiece, StringPieceHash>
    300       strict_thread_check_blacklist_;
    301 
    302   std::unique_ptr<MemoryDumpManagerDelegate> delegate_;
    303 
    304   // Protects from concurrent accesses to the |dump_providers_*| and |delegate_|
    305   // to guard against disabling logging while dumping on another thread.
    306   Lock lock_;
    307 
    308   // Optimization to avoid attempting any memory dump (i.e. to not walk an empty
    309   // dump_providers_enabled_ list) when tracing is not enabled.
    310   subtle::AtomicWord memory_tracing_enabled_;
    311 
    312   // Thread used for MemoryDumpProviders which don't specify a task runner
    313   // affinity.
    314   std::unique_ptr<Thread> dump_thread_;
    315 
    316   // The unique id of the child process. This is created only for tracing and is
    317   // expected to be valid only when tracing is enabled.
    318   uint64_t tracing_process_id_;
    319 
    320   // When true, calling |RegisterMemoryDumpProvider| is a no-op.
    321   bool dumper_registrations_ignored_for_testing_;
    322 
    323   // Whether new memory dump providers should be told to enable heap profiling.
    324   bool heap_profiling_enabled_;
    325 
    326   DISALLOW_COPY_AND_ASSIGN(MemoryDumpManager);
    327 };
    328 
    329 // The delegate is supposed to be long lived (read: a Singleton) and thread
    330 // safe (i.e. should expect calls from any thread and handle thread hopping).
    331 class BASE_EXPORT MemoryDumpManagerDelegate {
    332  public:
    333   MemoryDumpManagerDelegate() {}
    334   virtual ~MemoryDumpManagerDelegate() {}
    335 
    336   virtual void RequestGlobalMemoryDump(const MemoryDumpRequestArgs& args,
    337                                        const MemoryDumpCallback& callback) = 0;
    338 
    339   virtual bool IsCoordinator() const = 0;
    340 
    341  protected:
    342   void CreateProcessDump(const MemoryDumpRequestArgs& args,
    343                          const MemoryDumpCallback& callback) {
    344     MemoryDumpManager::GetInstance()->CreateProcessDump(args, callback);
    345   }
    346 
    347  private:
    348   DISALLOW_COPY_AND_ASSIGN(MemoryDumpManagerDelegate);
    349 };
    350 
    351 }  // namespace trace_event
    352 }  // namespace base
    353 
    354 #endif  // BASE_TRACE_EVENT_MEMORY_DUMP_MANAGER_H_
    355