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 |