| Index: base/trace_event/memory_dump_manager.cc
|
| diff --git a/base/trace_event/memory_dump_manager.cc b/base/trace_event/memory_dump_manager.cc
|
| index b14d265f19ebbdc7945c141474957bece0aad403..a2628d9ed655f4a12ab81ceb7a0e491c3661c6ac 100644
|
| --- a/base/trace_event/memory_dump_manager.cc
|
| +++ b/base/trace_event/memory_dump_manager.cc
|
| @@ -16,6 +16,7 @@
|
| #include "base/memory/ptr_util.h"
|
| #include "base/threading/thread.h"
|
| #include "base/threading/thread_task_runner_handle.h"
|
| +#include "base/timer/timer.h"
|
| #include "base/trace_event/heap_profiler.h"
|
| #include "base/trace_event/heap_profiler_allocation_context_tracker.h"
|
| #include "base/trace_event/heap_profiler_stack_frame_deduplicator.h"
|
| @@ -46,26 +47,16 @@ const char* kTraceEventArgNames[] = {"dumps"};
|
| const unsigned char kTraceEventArgTypes[] = {TRACE_VALUE_TYPE_CONVERTABLE};
|
|
|
| StaticAtomicSequenceNumber g_next_guid;
|
| -uint32_t g_periodic_dumps_count = 0;
|
| -uint32_t g_heavy_dumps_rate = 0;
|
| MemoryDumpManager* g_instance_for_testing = nullptr;
|
|
|
| -void RequestPeriodicGlobalDump() {
|
| - MemoryDumpLevelOfDetail level_of_detail;
|
| - if (g_heavy_dumps_rate == 0) {
|
| - level_of_detail = MemoryDumpLevelOfDetail::LIGHT;
|
| - } else {
|
| - level_of_detail = g_periodic_dumps_count == 0
|
| - ? MemoryDumpLevelOfDetail::DETAILED
|
| - : MemoryDumpLevelOfDetail::LIGHT;
|
| -
|
| - if (++g_periodic_dumps_count == g_heavy_dumps_rate)
|
| - g_periodic_dumps_count = 0;
|
| - }
|
| -
|
| - MemoryDumpManager::GetInstance()->RequestGlobalDump(
|
| - MemoryDumpType::PERIODIC_INTERVAL, level_of_detail);
|
| -}
|
| +// The names of dump providers whitelisted for background tracing. Dump
|
| +// providers can be added here only if the background mode dump has very
|
| +// less performance and memory overhead.
|
| +const char* const kDumpProviderWhitelist[] = {
|
| + // TODO(ssid): Fill this list with dump provider names which support
|
| + // background mode, crbug.com/613198.
|
| + nullptr, // End of list marker.
|
| +};
|
|
|
| // Callback wrapper to hook upon the completion of RequestGlobalDump() and
|
| // inject trace markers.
|
| @@ -109,6 +100,16 @@ struct SessionStateConvertableProxy : public ConvertableToTraceFormat {
|
| GetterFunctPtr const getter_function;
|
| };
|
|
|
| +// Checks if the name is in the given |list|. Last element of the list should be
|
| +// an empty string.
|
| +bool IsNameInList(const char* name, const char* const* list) {
|
| + for (size_t i = 0; list[i] != nullptr; ++i) {
|
| + if (strcmp(name, list[i]) == 0)
|
| + return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| } // namespace
|
|
|
| // static
|
| @@ -149,6 +150,7 @@ MemoryDumpManager::MemoryDumpManager()
|
| : delegate_(nullptr),
|
| is_coordinator_(false),
|
| memory_tracing_enabled_(0),
|
| + dump_provider_whitelist_(kDumpProviderWhitelist),
|
| tracing_process_id_(kInvalidTracingProcessId),
|
| dumper_registrations_ignored_for_testing_(false),
|
| heap_profiling_enabled_(false) {
|
| @@ -272,8 +274,11 @@ void MemoryDumpManager::RegisterDumpProviderInternal(
|
| if (dumper_registrations_ignored_for_testing_)
|
| return;
|
|
|
| + bool whitelisted_for_background_mode =
|
| + IsNameInList(name, dump_provider_whitelist_);
|
| scoped_refptr<MemoryDumpProviderInfo> mdpinfo =
|
| - new MemoryDumpProviderInfo(mdp, name, std::move(task_runner), options);
|
| + new MemoryDumpProviderInfo(mdp, name, std::move(task_runner), options,
|
| + whitelisted_for_background_mode);
|
|
|
| {
|
| AutoLock lock(lock_);
|
| @@ -449,6 +454,15 @@ void MemoryDumpManager::SetupNextMemoryDump(
|
| MemoryDumpProviderInfo* mdpinfo =
|
| pmd_async_state->pending_dump_providers.back().get();
|
|
|
| + // If we are in background tracing, we should invoke only the whitelisted
|
| + // providers. Ignore other providers and continue.
|
| + if (pmd_async_state->req_args.level_of_detail ==
|
| + MemoryDumpLevelOfDetail::BACKGROUND &&
|
| + !mdpinfo->whitelisted_for_background_mode) {
|
| + pmd_async_state->pending_dump_providers.pop_back();
|
| + return SetupNextMemoryDump(std::move(pmd_async_state));
|
| + }
|
| +
|
| // If the dump provider did not specify a task runner affinity, dump on
|
| // |dump_thread_| which is already checked above for presence.
|
| SequencedTaskRunner* task_runner = mdpinfo->task_runner.get();
|
| @@ -632,78 +646,57 @@ void MemoryDumpManager::OnTraceLogEnabled() {
|
| return;
|
| }
|
|
|
| - AutoLock lock(lock_);
|
| -
|
| - DCHECK(delegate_); // At this point we must have a delegate.
|
| - session_state_ = new MemoryDumpSessionState;
|
| -
|
| + const TraceConfig trace_config =
|
| + TraceLog::GetInstance()->GetCurrentTraceConfig();
|
| + scoped_refptr<MemoryDumpSessionState> session_state =
|
| + new MemoryDumpSessionState;
|
| + session_state->SetMemoryDumpConfig(trace_config.memory_dump_config());
|
| if (heap_profiling_enabled_) {
|
| // If heap profiling is enabled, the stack frame deduplicator and type name
|
| // deduplicator will be in use. Add a metadata events to write the frames
|
| // and type IDs.
|
| - session_state_->SetStackFrameDeduplicator(
|
| + session_state->SetStackFrameDeduplicator(
|
| WrapUnique(new StackFrameDeduplicator));
|
|
|
| - session_state_->SetTypeNameDeduplicator(
|
| + session_state->SetTypeNameDeduplicator(
|
| WrapUnique(new TypeNameDeduplicator));
|
|
|
| TRACE_EVENT_API_ADD_METADATA_EVENT(
|
| TraceLog::GetCategoryGroupEnabled("__metadata"), "stackFrames",
|
| "stackFrames",
|
| - WrapUnique(
|
| - new SessionStateConvertableProxy<StackFrameDeduplicator>(
|
| - session_state_,
|
| - &MemoryDumpSessionState::stack_frame_deduplicator)));
|
| + WrapUnique(new SessionStateConvertableProxy<StackFrameDeduplicator>(
|
| + session_state, &MemoryDumpSessionState::stack_frame_deduplicator)));
|
|
|
| TRACE_EVENT_API_ADD_METADATA_EVENT(
|
| TraceLog::GetCategoryGroupEnabled("__metadata"), "typeNames",
|
| "typeNames",
|
| WrapUnique(new SessionStateConvertableProxy<TypeNameDeduplicator>(
|
| - session_state_, &MemoryDumpSessionState::type_name_deduplicator)));
|
| + session_state, &MemoryDumpSessionState::type_name_deduplicator)));
|
| }
|
|
|
| - DCHECK(!dump_thread_);
|
| - dump_thread_ = std::move(dump_thread);
|
| - subtle::NoBarrier_Store(&memory_tracing_enabled_, 1);
|
| + {
|
| + AutoLock lock(lock_);
|
|
|
| - // TODO(primiano): This is a temporary hack to disable periodic memory dumps
|
| - // when running memory benchmarks until telemetry uses TraceConfig to
|
| - // enable/disable periodic dumps. See crbug.com/529184 .
|
| - if (!is_coordinator_ ||
|
| - CommandLine::ForCurrentProcess()->HasSwitch(
|
| - "enable-memory-benchmarking")) {
|
| - return;
|
| - }
|
| + DCHECK(delegate_); // At this point we must have a delegate.
|
| + session_state_ = session_state;
|
|
|
| - // Enable periodic dumps. At the moment the periodic support is limited to at
|
| - // most one low-detail periodic dump and at most one high-detail periodic
|
| - // dump. If both are specified the high-detail period must be an integer
|
| - // multiple of the low-level one.
|
| - g_periodic_dumps_count = 0;
|
| - const TraceConfig trace_config =
|
| - TraceLog::GetInstance()->GetCurrentTraceConfig();
|
| - session_state_->SetMemoryDumpConfig(trace_config.memory_dump_config());
|
| - const std::vector<TraceConfig::MemoryDumpConfig::Trigger>& triggers_list =
|
| - trace_config.memory_dump_config().triggers;
|
| - if (triggers_list.empty())
|
| - return;
|
| + DCHECK(!dump_thread_);
|
| + dump_thread_ = std::move(dump_thread);
|
|
|
| - uint32_t min_timer_period_ms = std::numeric_limits<uint32_t>::max();
|
| - uint32_t heavy_dump_period_ms = 0;
|
| - DCHECK_LE(triggers_list.size(), 2u);
|
| - for (const TraceConfig::MemoryDumpConfig::Trigger& config : triggers_list) {
|
| - DCHECK(config.periodic_interval_ms);
|
| - if (config.level_of_detail == MemoryDumpLevelOfDetail::DETAILED)
|
| - heavy_dump_period_ms = config.periodic_interval_ms;
|
| - min_timer_period_ms =
|
| - std::min(min_timer_period_ms, config.periodic_interval_ms);
|
| + subtle::NoBarrier_Store(&memory_tracing_enabled_, 1);
|
| +
|
| + // TODO(primiano): This is a temporary hack to disable periodic memory dumps
|
| + // when running memory benchmarks until telemetry uses TraceConfig to
|
| + // enable/disable periodic dumps. See crbug.com/529184 .
|
| + if (!is_coordinator_ ||
|
| + CommandLine::ForCurrentProcess()->HasSwitch(
|
| + "enable-memory-benchmarking")) {
|
| + return;
|
| + }
|
| }
|
| - DCHECK_EQ(0u, heavy_dump_period_ms % min_timer_period_ms);
|
| - g_heavy_dumps_rate = heavy_dump_period_ms / min_timer_period_ms;
|
|
|
| - periodic_dump_timer_.Start(FROM_HERE,
|
| - TimeDelta::FromMilliseconds(min_timer_period_ms),
|
| - base::Bind(&RequestPeriodicGlobalDump));
|
| + // Enable periodic dumps if necessary.
|
| + periodic_dump_timer_.Start(trace_config.memory_dump_config().triggers);
|
| }
|
|
|
| void MemoryDumpManager::OnTraceLogDisabled() {
|
| @@ -733,13 +726,15 @@ MemoryDumpManager::MemoryDumpProviderInfo::MemoryDumpProviderInfo(
|
| MemoryDumpProvider* dump_provider,
|
| const char* name,
|
| scoped_refptr<SequencedTaskRunner> task_runner,
|
| - const MemoryDumpProvider::Options& options)
|
| + const MemoryDumpProvider::Options& options,
|
| + bool whitelisted_for_background_mode)
|
| : dump_provider(dump_provider),
|
| name(name),
|
| task_runner(std::move(task_runner)),
|
| options(options),
|
| consecutive_failures(0),
|
| - disabled(false) {}
|
| + disabled(false),
|
| + whitelisted_for_background_mode(whitelisted_for_background_mode) {}
|
|
|
| MemoryDumpManager::MemoryDumpProviderInfo::~MemoryDumpProviderInfo() {}
|
|
|
| @@ -785,5 +780,69 @@ ProcessMemoryDump* MemoryDumpManager::ProcessMemoryDumpAsyncState::
|
| return iter->second.get();
|
| }
|
|
|
| +MemoryDumpManager::PeriodicGlobalDumpTimer::PeriodicGlobalDumpTimer() {}
|
| +
|
| +MemoryDumpManager::PeriodicGlobalDumpTimer::~PeriodicGlobalDumpTimer() {
|
| + Stop();
|
| +}
|
| +
|
| +void MemoryDumpManager::PeriodicGlobalDumpTimer::Start(
|
| + const std::vector<TraceConfig::MemoryDumpConfig::Trigger>& triggers_list) {
|
| + if (triggers_list.empty())
|
| + return;
|
| +
|
| + // At the moment the periodic support is limited to at most one periodic
|
| + // trigger per dump mode. All intervals should be an integer multiple of the
|
| + // smallest interval specified.
|
| + periodic_dumps_count_ = 0;
|
| + uint32_t min_timer_period_ms = std::numeric_limits<uint32_t>::max();
|
| + uint32_t light_dump_period_ms = 0;
|
| + uint32_t heavy_dump_period_ms = 0;
|
| + DCHECK_LE(triggers_list.size(), 3u);
|
| + for (const TraceConfig::MemoryDumpConfig::Trigger& config : triggers_list) {
|
| + DCHECK_NE(0u, config.periodic_interval_ms);
|
| + if (config.level_of_detail == MemoryDumpLevelOfDetail::LIGHT) {
|
| + DCHECK_EQ(0u, light_dump_period_ms);
|
| + light_dump_period_ms = config.periodic_interval_ms;
|
| + } else if (config.level_of_detail == MemoryDumpLevelOfDetail::DETAILED) {
|
| + DCHECK_EQ(0u, heavy_dump_period_ms);
|
| + heavy_dump_period_ms = config.periodic_interval_ms;
|
| + }
|
| + min_timer_period_ms =
|
| + std::min(min_timer_period_ms, config.periodic_interval_ms);
|
| + }
|
| +
|
| + DCHECK_EQ(0u, light_dump_period_ms % min_timer_period_ms);
|
| + light_dump_rate_ = light_dump_period_ms / min_timer_period_ms;
|
| + DCHECK_EQ(0u, heavy_dump_period_ms % min_timer_period_ms);
|
| + heavy_dump_rate_ = heavy_dump_period_ms / min_timer_period_ms;
|
| +
|
| + timer_.Start(FROM_HERE, TimeDelta::FromMilliseconds(min_timer_period_ms),
|
| + base::Bind(&PeriodicGlobalDumpTimer::RequestPeriodicGlobalDump,
|
| + base::Unretained(this)));
|
| +}
|
| +
|
| +void MemoryDumpManager::PeriodicGlobalDumpTimer::Stop() {
|
| + if (IsRunning()) {
|
| + timer_.Stop();
|
| + }
|
| +}
|
| +
|
| +bool MemoryDumpManager::PeriodicGlobalDumpTimer::IsRunning() {
|
| + return timer_.IsRunning();
|
| +}
|
| +
|
| +void MemoryDumpManager::PeriodicGlobalDumpTimer::RequestPeriodicGlobalDump() {
|
| + MemoryDumpLevelOfDetail level_of_detail = MemoryDumpLevelOfDetail::BACKGROUND;
|
| + if (light_dump_rate_ > 0 && periodic_dumps_count_ % light_dump_rate_ == 0)
|
| + level_of_detail = MemoryDumpLevelOfDetail::LIGHT;
|
| + if (heavy_dump_rate_ > 0 && periodic_dumps_count_ % heavy_dump_rate_ == 0)
|
| + level_of_detail = MemoryDumpLevelOfDetail::DETAILED;
|
| + ++periodic_dumps_count_;
|
| +
|
| + MemoryDumpManager::GetInstance()->RequestGlobalDump(
|
| + MemoryDumpType::PERIODIC_INTERVAL, level_of_detail);
|
| +}
|
| +
|
| } // namespace trace_event
|
| } // namespace base
|
|
|