Chromium Code Reviews| 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..26d8bc3e9c9f77325887c97b71fed33157989e41 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,14 @@ 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[] = { |
| + "WhitelistedTestDumpProvider", // For testing. |
|
Primiano Tucci (use gerrit)
2016/05/26 17:20:53
I think a better approach is to:
- Make this an em
ssid
2016/05/26 22:12:54
Yeah the problem was that i cannot get the array s
|
| +}; |
| // Callback wrapper to hook upon the completion of RequestGlobalDump() and |
| // inject trace markers. |
| @@ -109,8 +98,90 @@ struct SessionStateConvertableProxy : public ConvertableToTraceFormat { |
| GetterFunctPtr const getter_function; |
| }; |
| +// Checks if the dump provider is in the whitelist. |
| +bool IsDumpProviderInWhitelist(const char* name) { |
| + for (size_t i = 0; i < arraysize(kDumpProviderWhitelist); ++i) { |
| + if (strcmp(name, kDumpProviderWhitelist[i]) == 0) |
| + return true; |
| + } |
| + return false; |
| +} |
| + |
| } // namespace |
| +// Sets up periodic memory dump timers to start global dump requests based on |
| +// the dump triggers from trace config. |
| +class MemoryDumpManager::PeriodicGlobalDumpInvokeHelper { |
|
Primiano Tucci (use gerrit)
2016/05/26 17:20:53
nit: I think this should go after the constants be
ssid
2016/05/26 22:12:54
Added to the last.
|
| + public: |
| + PeriodicGlobalDumpInvokeHelper( |
| + const std::vector<TraceConfig::MemoryDumpConfig::Trigger>& triggers_list); |
| + ~PeriodicGlobalDumpInvokeHelper(); |
| + |
| + // Periodically called by the timer. |
| + void RequestPeriodicGlobalDump(); |
| + |
| + private: |
| + RepeatingTimer periodic_dump_timer_; |
| + uint32_t periodic_dumps_count_; |
| + uint32_t light_dump_rate_; |
| + uint32_t heavy_dump_rate_; |
| +}; |
| + |
| +MemoryDumpManager::PeriodicGlobalDumpInvokeHelper:: |
| + PeriodicGlobalDumpInvokeHelper( |
|
Primiano Tucci (use gerrit)
2016/05/26 17:20:53
In general the constructor should not do actions,
ssid
2016/05/26 22:12:54
Makes sense.
|
| + const std::vector<TraceConfig::MemoryDumpConfig::Trigger>& |
| + triggers_list) |
| + : 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(triggers_list.size()); |
| + DCHECK_LE(triggers_list.size(), 3u); |
| + for (const TraceConfig::MemoryDumpConfig::Trigger& config : triggers_list) { |
| + 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); |
| + } |
| + |
| + // Do not start timer if period is 0 for any trigger. |
| + if (!min_timer_period_ms) |
|
Primiano Tucci (use gerrit)
2016/05/26 17:20:53
Hmm this is a bit contra-intuitive. THis means tha
ssid
2016/05/26 22:12:54
Yeah, I was thinking it is useful to specify mode
|
| + return; |
| + |
| + 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_rate_ % min_timer_period_ms); |
| + heavy_dump_rate_ = heavy_dump_period_ms / min_timer_period_ms; |
| + |
| + periodic_dump_timer_.Start( |
| + FROM_HERE, TimeDelta::FromMilliseconds(min_timer_period_ms), |
| + base::Bind(&PeriodicGlobalDumpInvokeHelper::RequestPeriodicGlobalDump, |
| + base::Unretained(this))); |
| +} |
| + |
| +MemoryDumpManager::PeriodicGlobalDumpInvokeHelper:: |
| + ~PeriodicGlobalDumpInvokeHelper() { |
| + periodic_dump_timer_.Stop(); |
| +} |
| + |
| +void MemoryDumpManager::PeriodicGlobalDumpInvokeHelper:: |
| + 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); |
| +} |
| + |
| // static |
| const char* const MemoryDumpManager::kTraceCategory = |
| TRACE_DISABLED_BY_DEFAULT("memory-infra"); |
| @@ -449,6 +520,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->disabled_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 +712,64 @@ void MemoryDumpManager::OnTraceLogEnabled() { |
| return; |
| } |
| - AutoLock lock(lock_); |
|
ssid
2016/05/23 18:17:03
This unnecessarily locks the whole function. I can
Primiano Tucci (use gerrit)
2016/05/26 17:20:53
Where is the call to RequestGlobalDump? In the tim
ssid
2016/05/26 22:12:54
We currently do the first dump after 250ms of star
|
| - |
| - 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; |
| 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))); |
| } |
| + session_state->SetMemoryDumpConfig(trace_config.memory_dump_config()); |
|
Primiano Tucci (use gerrit)
2016/05/26 17:20:53
nit: seems a bit more logical to have this after s
ssid
2016/05/26 22:12:54
Done.
|
| - 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; |
| + |
| + DCHECK(!dump_thread_); |
| + dump_thread_ = std::move(dump_thread); |
| + |
| + 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; |
| + } |
| } |
| // 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()); |
|
ssid
2016/05/23 18:17:03
I think this needs to be set before the check for
|
| + // most one periodic trigger per dump mode. All intervals should be an integer |
| + // multiple of the smallest interval specified. |
| const std::vector<TraceConfig::MemoryDumpConfig::Trigger>& triggers_list = |
| trace_config.memory_dump_config().triggers; |
| - if (triggers_list.empty()) |
| - return; |
| - |
| - 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); |
| + if (!triggers_list.empty()) { |
|
Primiano Tucci (use gerrit)
2016/05/26 17:20:53
maybe just always pass the triggers and to this ch
ssid
2016/05/26 22:12:54
Done.
|
| + periodic_dump_helper_.reset( |
| + new PeriodicGlobalDumpInvokeHelper(triggers_list)); |
| } |
| - 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)); |
| } |
| void MemoryDumpManager::OnTraceLogDisabled() { |
| @@ -720,7 +786,7 @@ void MemoryDumpManager::OnTraceLogDisabled() { |
| // Thread stops are blocking and must be performed outside of the |lock_| |
| // or will deadlock (e.g., if SetupNextMemoryDump() tries to acquire it). |
| - periodic_dump_timer_.Stop(); |
| + periodic_dump_helper_.reset(); |
| if (dump_thread) |
| dump_thread->Stop(); |
| } |
| @@ -739,7 +805,8 @@ MemoryDumpManager::MemoryDumpProviderInfo::MemoryDumpProviderInfo( |
| task_runner(std::move(task_runner)), |
| options(options), |
| consecutive_failures(0), |
| - disabled(false) {} |
| + disabled(false), |
| + disabled_for_background_mode(!IsDumpProviderInWhitelist(name)) {} |
| MemoryDumpManager::MemoryDumpProviderInfo::~MemoryDumpProviderInfo() {} |