| // 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 <map> |
| #include <memory> |
| #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; |
| class Thread; |
| |
| 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 kTraceCategory; |
| |
| // This value is returned as the tracing id of the child processes by |
| // GetTracingProcessId() when tracing is not enabled. |
| static const uint64_t kInvalidTracingProcessId; |
| |
| static MemoryDumpManager* GetInstance(); |
| |
| // Invoked once per process to listen to trace begin / end events. |
| // Initialization can happen after (Un)RegisterMemoryDumpProvider() calls |
| // and the MemoryDumpManager guarantees to support this. |
| // On the other side, the MemoryDumpManager will not be fully operational |
| // (i.e. will NACK any RequestGlobalMemoryDump()) until initialized. |
| // Arguments: |
| // is_coordinator: if true this MemoryDumpManager instance will act as a |
| // coordinator and schedule periodic dumps (if enabled via TraceConfig); |
| // false when the MemoryDumpManager is initialized in a slave process. |
| // delegate: inversion-of-control interface for embedder-specific behaviors |
| // (multiprocess handshaking). See the lifetime and thread-safety |
| // requirements in the |MemoryDumpManagerDelegate| docstring. |
| void Initialize(MemoryDumpManagerDelegate* delegate, bool is_coordinator); |
| |
| // (Un)Registers a MemoryDumpProvider instance. |
| // Args: |
| // - mdp: the MemoryDumpProvider instance to be registered. MemoryDumpManager |
| // does NOT take memory ownership of |mdp|, which is expected to either |
| // be a singleton or unregister itself. |
| // - name: a friendly name (duplicates allowed). Used for debugging and |
| // run-time profiling of memory-infra internals. Must be a long-lived |
| // C string. |
| // - task_runner: if non-null, all the calls to |mdp| will be |
| // issued on the given thread. Otherwise, |mdp| should be able to |
| // handle calls on arbitrary threads. |
| // - options: extra optional arguments. See memory_dump_provider.h. |
| void RegisterDumpProvider( |
| MemoryDumpProvider* mdp, |
| const char* name, |
| const scoped_refptr<SingleThreadTaskRunner>& task_runner); |
| void RegisterDumpProvider( |
| MemoryDumpProvider* mdp, |
| const char* name, |
| const scoped_refptr<SingleThreadTaskRunner>& task_runner, |
| const MemoryDumpProvider::Options& options); |
| 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, |
| MemoryDumpLevelOfDetail level_of_detail, |
| const MemoryDumpCallback& callback); |
| |
| // Same as above (still asynchronous), but without callback. |
| void RequestGlobalDump(MemoryDumpType dump_type, |
| MemoryDumpLevelOfDetail level_of_detail); |
| |
| // 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_t GetTracingProcessId() const; |
| |
| // Returns the name for a the allocated_objects dump. Use this to declare |
| // suballocator dumps from other dump providers. |
| // It will return nullptr if there is no dump provider for the system |
| // allocator registered (which is currently the case for Mac OS). |
| const char* system_allocator_pool_name() const { |
| return kSystemAllocatorPoolName; |
| }; |
| |
| // When set to true, calling |RegisterMemoryDumpProvider| is a no-op. |
| void set_dumper_registrations_ignored_for_testing(bool ignored) { |
| dumper_registrations_ignored_for_testing_ = ignored; |
| } |
| |
| private: |
| friend std::default_delete<MemoryDumpManager>; // For the testing instance. |
| friend struct DefaultSingletonTraits<MemoryDumpManager>; |
| friend class MemoryDumpManagerDelegate; |
| friend class MemoryDumpManagerTest; |
| |
| // 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 char* name, |
| const scoped_refptr<SingleThreadTaskRunner>& task_runner, |
| const MemoryDumpProvider::Options& options); |
| ~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; |
| const char* const name; |
| |
| // The task_runner affinity. Can be nullptr, in which case the dump provider |
| // will be invoked on |dump_thread_|. |
| scoped_refptr<SingleThreadTaskRunner> task_runner; |
| |
| // The |options| arg passed to RegisterDumpProvider(). |
| const MemoryDumpProvider::Options options; |
| |
| // 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; |
| |
| // When a dump provider unregisters, it is flagged as |unregistered| and it |
| // is removed only upon the next memory dump. This is to avoid altering the |
| // |dump_providers_| collection while a dump is in progress. |
| mutable bool unregistered; |
| }; |
| |
| 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, |
| const scoped_refptr<SingleThreadTaskRunner>& dump_thread_task_runner); |
| ~ProcessMemoryDumpAsyncState(); |
| |
| // Gets or creates the memory dump container for the given target process. |
| ProcessMemoryDump* GetOrCreateMemoryDumpContainerForProcess(ProcessId pid); |
| |
| // A map of ProcessId -> ProcessMemoryDump, one for each target process |
| // being dumped from the current process. Typically each process dumps only |
| // for itself, unless dump providers specify a different |target_process| in |
| // MemoryDumpProvider::Options. |
| std::map<ProcessId, scoped_ptr<ProcessMemoryDump>> process_dumps; |
| |
| // 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; |
| |
| // The trace-global session state. |
| scoped_refptr<MemoryDumpSessionState> session_state; |
| |
| // 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> callback_task_runner; |
| |
| // The thread on which unbound dump providers should be invoked. |
| // This is essentially |dump_thread_|.task_runner() but needs to be kept |
| // as a separate variable as it needs to be accessed by arbitrary dumpers' |
| // threads outside of the lock_ to avoid races when disabling tracing. |
| // It is immutable for all the duration of a tracing session. |
| const scoped_refptr<SingleThreadTaskRunner> dump_thread_task_runner; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(ProcessMemoryDumpAsyncState); |
| }; |
| |
| static const int kMaxConsecutiveFailuresCount; |
| static const char* const kSystemAllocatorPoolName; |
| |
| 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_t 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_; |
| |
| // Shared among all the PMDs to keep state scoped to the tracing session. |
| scoped_refptr<MemoryDumpSessionState> session_state_; |
| |
| MemoryDumpManagerDelegate* delegate_; // Not owned. |
| |
| // When true, this instance is in charge of coordinating periodic dumps. |
| bool is_coordinator_; |
| |
| // 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 periodic_dump_timer_; |
| |
| // Thread used for MemoryDumpProviders which don't specify a thread affinity. |
| scoped_ptr<Thread> dump_thread_; |
| |
| // 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_t tracing_process_id_; |
| |
| // When true, calling |RegisterMemoryDumpProvider| is a no-op. |
| bool dumper_registrations_ignored_for_testing_; |
| |
| // Whether new memory dump providers should be told to enable heap profiling. |
| bool heap_profiling_enabled_; |
| |
| 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; |
| |
| // Returns tracing process id of the current process. This is used by |
| // MemoryDumpManager::GetTracingProcessId. |
| virtual uint64_t 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_ |