Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(834)

Unified Diff: base/trace_event/memory_dump_manager.cc

Issue 1540283003: Revert of [tracing] Simplify logic of MemoryDumpManager (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « base/trace_event/memory_dump_manager.h ('k') | base/trace_event/memory_dump_manager_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 f5c3c4feb4b91c8e6835a154239cc55979e476ef..cbce21021c08a599fa6f6d23db007de8d8bad7b4 100644
--- a/base/trace_event/memory_dump_manager.cc
+++ b/base/trace_event/memory_dump_manager.cc
@@ -193,16 +193,17 @@
if (dumper_registrations_ignored_for_testing_)
return;
- scoped_refptr<MemoryDumpProviderInfo> mdpinfo =
- new MemoryDumpProviderInfo(mdp, name, task_runner, options);
-
- {
- AutoLock lock(lock_);
- bool already_registered = !dump_providers_.insert(mdpinfo).second;
- // This actually happen in some tests which don't have a clean tear-down
- // path for RenderThreadImpl::Init().
- if (already_registered)
- return;
+ MemoryDumpProviderInfo mdp_info(mdp, name, task_runner, options);
+ AutoLock lock(lock_);
+ auto iter_new = dump_providers_.insert(mdp_info);
+
+ // If there was a previous entry, replace it with the new one. This is to deal
+ // with the case where a dump provider unregisters itself and then re-
+ // registers before a memory dump happens, so its entry was still in the
+ // collection but flagged |unregistered|.
+ if (!iter_new.second) {
+ dump_providers_.erase(iter_new.first);
+ dump_providers_.insert(mdp_info);
}
if (heap_profiling_enabled_)
@@ -221,7 +222,7 @@
auto mdp_iter = dump_providers_.begin();
for (; mdp_iter != dump_providers_.end(); ++mdp_iter) {
- if ((*mdp_iter)->dump_provider == mdp)
+ if (mdp_iter->dump_provider == mdp)
break;
}
@@ -235,18 +236,12 @@
// Otherwise, it is not possible to guarantee that its unregistration is
// race-free. If you hit this DCHECK, your MDP has a bug.
DCHECK(!subtle::NoBarrier_Load(&memory_tracing_enabled_) ||
- ((*mdp_iter)->task_runner &&
- (*mdp_iter)->task_runner->BelongsToCurrentThread()))
- << "MemoryDumpProvider \"" << (*mdp_iter)->name << "\" attempted to "
+ (mdp_iter->task_runner &&
+ mdp_iter->task_runner->BelongsToCurrentThread()))
+ << "MemoryDumpProvider \"" << mdp_iter->name << "\" attempted to "
<< "unregister itself in a racy way. Please file a crbug.";
- // The MDPInfo instance can still be referenced by the
- // |ProcessMemoryDumpAsyncState.pending_dump_providers|. For this reason
- // the MDPInfo is flagged as disabled. It will cause ContinueAsyncProcessDump
- // to just skip it, without actually invoking the |mdp|, which might be
- // destroyed by the caller soon after this method returns.
- (*mdp_iter)->disabled = true;
- dump_providers_.erase(mdp_iter);
+ mdp_iter->unregistered = true;
}
void MemoryDumpManager::RequestGlobalDump(
@@ -301,9 +296,9 @@
scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state;
{
AutoLock lock(lock_);
- pmd_async_state.reset(
- new ProcessMemoryDumpAsyncState(args, dump_providers_, session_state_,
- callback, dump_thread_->task_runner()));
+ pmd_async_state.reset(new ProcessMemoryDumpAsyncState(
+ args, dump_providers_.begin(), session_state_, callback,
+ dump_thread_->task_runner()));
}
TRACE_EVENT_WITH_FLOW0(kTraceCategory, "MemoryDumpManager::CreateProcessDump",
@@ -313,7 +308,7 @@
// Start the thread hop. |dump_providers_| are kept sorted by thread, so
// ContinueAsyncProcessDump will hop at most once per thread (w.r.t. thread
// affinity specified by the MemoryDumpProvider(s) in RegisterDumpProvider()).
- ContinueAsyncProcessDump(pmd_async_state.release());
+ ContinueAsyncProcessDump(std::move(pmd_async_state));
}
// At most one ContinueAsyncProcessDump() can be active at any time for a given
@@ -323,103 +318,128 @@
// means of subsequent PostTask(s).
//
// 1) Prologue:
-// - If this was the last hop, create a trace event, add it to the trace
-// and finalize (invoke callback).
+// - Check if the dump provider is disabled, if so skip the dump.
// - Check if we are on the right thread. If not hop and continue there.
-// - Check if the dump provider is disabled, if so skip the dump.
// 2) Invoke the dump provider's OnMemoryDump() (unless skipped).
// 3) Epilogue:
-// - Unregister the dump provider if it failed too many times consecutively.
-// - Pop() the MDP from the |pending_dump_providers| list, eventually
-// destroying the MDPInfo if that was unregistered in the meantime.
+// - Unregister the dump provider if it failed too many times consecutively.
+// - Advance the |next_dump_provider| iterator to the next dump provider.
+// - If this was the last hop, create a trace event, add it to the trace
+// and finalize (invoke callback).
+
void MemoryDumpManager::ContinueAsyncProcessDump(
- ProcessMemoryDumpAsyncState* owned_pmd_async_state) {
+ scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state) {
// Initalizes the ThreadLocalEventBuffer to guarantee that the TRACE_EVENTs
// in the PostTask below don't end up registering their own dump providers
// (for discounting trace memory overhead) while holding the |lock_|.
TraceLog::GetInstance()->InitializeThreadLocalEventBufferIfSupported();
- // In theory |owned_pmd_async_state| should be a scoped_ptr. The only reason
- // why it isn't is because of the corner case logic of |did_post_task| below,
- // which needs to take back the ownership of the |pmd_async_state| when a
- // thread goes away and consequently the PostTask() fails.
- // Unfortunately, PostTask() destroys the scoped_ptr arguments upon failure
- // to prevent accidental leaks. Using a scoped_ptr would prevent us to to
- // skip the hop and move on. Hence the manual naked -> scoped ptr juggling.
- auto pmd_async_state = make_scoped_ptr(owned_pmd_async_state);
- owned_pmd_async_state = nullptr;
-
- if (pmd_async_state->pending_dump_providers.empty())
- return FinalizeDumpAndAddToTrace(std::move(pmd_async_state));
-
- // Read MemoryDumpProviderInfo thread safety considerations in
- // memory_dump_manager.h when accessing |mdpinfo| fields.
- MemoryDumpProviderInfo* mdpinfo =
- pmd_async_state->pending_dump_providers.back().get();
-
- // If the dump provider did not specify a thread affinity, dump on
- // |dump_thread_|. Note that |dump_thread_| might have been Stop()-ed at this
- // point (if tracing was disabled in the meanwhile). In such case the
- // PostTask() below will fail, but |task_runner| should always be non-null.
- SingleThreadTaskRunner* task_runner = mdpinfo->task_runner.get();
- if (!task_runner)
- task_runner = pmd_async_state->dump_thread_task_runner.get();
-
- if (!task_runner->BelongsToCurrentThread()) {
- // It's time to hop onto another thread.
- const bool did_post_task = task_runner->PostTask(
- FROM_HERE, Bind(&MemoryDumpManager::ContinueAsyncProcessDump,
- Unretained(this), Unretained(pmd_async_state.get())));
- if (did_post_task) {
- // Ownership is tranferred to the next ContinueAsyncProcessDump().
- ignore_result(pmd_async_state.release());
- return;
+ const uint64_t dump_guid = pmd_async_state->req_args.dump_guid;
+ const char* dump_provider_name = nullptr;
+
+ // Pid of the target process being dumped. Often kNullProcessId (= current
+ // process), non-zero when the coordinator process creates dumps on behalf
+ // of child processes (see crbug.com/461788).
+ ProcessId pid;
+
+ // DO NOT put any LOG() statement in the locked sections, as in some contexts
+ // (GPU process) LOG() ends up performing PostTask/IPCs.
+ MemoryDumpProvider* mdp;
+ bool skip_dump = false;
+ {
+ AutoLock lock(lock_);
+
+ auto mdp_info = pmd_async_state->next_dump_provider;
+ mdp = mdp_info->dump_provider;
+ dump_provider_name = mdp_info->name;
+ pid = mdp_info->options.target_pid;
+
+ // If the dump provider did not specify a thread affinity, dump on
+ // |dump_thread_|.
+ SingleThreadTaskRunner* task_runner = mdp_info->task_runner.get();
+ if (!task_runner)
+ task_runner = pmd_async_state->dump_thread_task_runner.get();
+
+ // |dump_thread_| might have been Stop()-ed at this point (if tracing was
+ // disabled in the meanwhile). In such case the PostTask() below will fail.
+ // |task_runner|, however, should always be non-null.
+ DCHECK(task_runner);
+
+ if (mdp_info->disabled || mdp_info->unregistered) {
+ skip_dump = true;
+ } else if (!task_runner->BelongsToCurrentThread()) {
+ // It's time to hop onto another thread.
+
+ // Copy the callback + arguments just for the unlikley case in which
+ // PostTask fails. In such case the Bind helper will destroy the
+ // pmd_async_state and we must keep a copy of the fields to notify the
+ // abort.
+ MemoryDumpCallback callback = pmd_async_state->callback;
+ scoped_refptr<SingleThreadTaskRunner> callback_task_runner =
+ pmd_async_state->callback_task_runner;
+
+ const bool did_post_task = task_runner->PostTask(
+ FROM_HERE, Bind(&MemoryDumpManager::ContinueAsyncProcessDump,
+ Unretained(this), Passed(&pmd_async_state)));
+ if (did_post_task)
+ return;
+
+ // The thread is gone. At this point the best thing we can do is to
+ // disable the dump provider and abort this dump.
+ mdp_info->disabled = true;
+ return AbortDumpLocked(callback, callback_task_runner, dump_guid);
}
- // The thread is gone. Skip the dump provider and keep going.
- mdpinfo->disabled = true;
- }
-
- // At this point wither we are on the right thread (|mdpinfo.task_runner|)
- // to access mdp fields, or the right thread is gone (and |disabled| == true).
-
- if (!mdpinfo->disabled) {
- // Invoke the dump provider.
+ } // AutoLock(lock_)
+
+ // Invoke the dump provider without holding the |lock_|.
+ bool finalize = false;
+ bool dump_successful = false;
+
+ if (!skip_dump) {
TRACE_EVENT_WITH_FLOW1(kTraceCategory,
"MemoryDumpManager::ContinueAsyncProcessDump",
- TRACE_ID_MANGLE(pmd_async_state->req_args.dump_guid),
+ TRACE_ID_MANGLE(dump_guid),
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
- "dump_provider.name", mdpinfo->name);
-
- // Pid of the target process being dumped. Often kNullProcessId (= current
- // process), non-zero when the coordinator process creates dumps on behalf
- // of child processes (see crbug.com/461788).
- ProcessId target_pid = mdpinfo->options.target_pid;
- ProcessMemoryDump* pmd =
- pmd_async_state->GetOrCreateMemoryDumpContainerForProcess(target_pid);
+ "dump_provider.name", dump_provider_name);
MemoryDumpArgs args = {pmd_async_state->req_args.level_of_detail};
- bool dump_successful = mdpinfo->dump_provider->OnMemoryDump(args, pmd);
-
+ ProcessMemoryDump* process_memory_dump =
+ pmd_async_state->GetOrCreateMemoryDumpContainerForProcess(pid);
+ dump_successful = mdp->OnMemoryDump(args, process_memory_dump);
+ }
+
+ {
+ AutoLock lock(lock_);
+ auto mdp_info = pmd_async_state->next_dump_provider;
if (dump_successful) {
- mdpinfo->consecutive_failures = 0;
- } else {
- ++mdpinfo->consecutive_failures;
- if (mdpinfo->consecutive_failures >= kMaxConsecutiveFailuresCount) {
- mdpinfo->disabled = true;
- LOG(ERROR) << "MemoryDumpProvider \"" << mdpinfo->name << "\" failed, "
- << "possibly due to sandboxing (crbug.com/461788)."
- << "Disabling dumper for current process. Try --no-sandbox.";
+ mdp_info->consecutive_failures = 0;
+ } else if (!skip_dump) {
+ ++mdp_info->consecutive_failures;
+ if (mdp_info->consecutive_failures >= kMaxConsecutiveFailuresCount) {
+ mdp_info->disabled = true;
}
}
- } // if (!mdpinfo->disabled)
-
- pmd_async_state->pending_dump_providers.pop_back();
- ContinueAsyncProcessDump(pmd_async_state.release());
+ ++pmd_async_state->next_dump_provider;
+ finalize = pmd_async_state->next_dump_provider == dump_providers_.end();
+
+ if (mdp_info->unregistered)
+ dump_providers_.erase(mdp_info);
+ }
+
+ if (!skip_dump && !dump_successful) {
+ LOG(ERROR) << "MemoryDumpProvider \"" << dump_provider_name << "\" failed, "
+ << "possibly due to sandboxing (crbug.com/461788)."
+ << "Disabling dumper for current process. Try --no-sandbox.";
+ }
+
+ if (finalize)
+ return FinalizeDumpAndAddToTrace(std::move(pmd_async_state));
+
+ ContinueAsyncProcessDump(std::move(pmd_async_state));
}
// static
void MemoryDumpManager::FinalizeDumpAndAddToTrace(
scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state) {
- DCHECK(pmd_async_state->pending_dump_providers.empty());
const uint64_t dump_guid = pmd_async_state->req_args.dump_guid;
if (!pmd_async_state->callback_task_runner->BelongsToCurrentThread()) {
scoped_refptr<SingleThreadTaskRunner> callback_task_runner =
@@ -461,6 +481,20 @@
TRACE_EVENT_NESTABLE_ASYNC_END0(kTraceCategory, "ProcessMemoryDump",
TRACE_ID_MANGLE(dump_guid));
+}
+
+// static
+void MemoryDumpManager::AbortDumpLocked(
+ MemoryDumpCallback callback,
+ scoped_refptr<SingleThreadTaskRunner> task_runner,
+ uint64_t dump_guid) {
+ if (callback.is_null())
+ return; // There is nothing to NACK.
+
+ // Post the callback even if we are already on the right thread to avoid
+ // invoking the callback while holding the lock_.
+ task_runner->PostTask(FROM_HERE,
+ Bind(callback, dump_guid, false /* success */));
}
void MemoryDumpManager::OnTraceLogEnabled() {
@@ -507,6 +541,11 @@
session_state_ = new MemoryDumpSessionState(stack_frame_deduplicator,
type_name_deduplicator);
+ for (auto it = dump_providers_.begin(); it != dump_providers_.end(); ++it) {
+ it->disabled = false;
+ it->consecutive_failures = 0;
+ }
+
subtle::NoBarrier_Store(&memory_tracing_enabled_, 1);
// TODO(primiano): This is a temporary hack to disable periodic memory dumps
@@ -578,36 +617,31 @@
task_runner(task_runner),
options(options),
consecutive_failures(0),
- disabled(false) {}
+ disabled(false),
+ unregistered(false) {}
MemoryDumpManager::MemoryDumpProviderInfo::~MemoryDumpProviderInfo() {}
-bool MemoryDumpManager::MemoryDumpProviderInfo::Comparator::operator()(
- const scoped_refptr<MemoryDumpManager::MemoryDumpProviderInfo>& a,
- const scoped_refptr<MemoryDumpManager::MemoryDumpProviderInfo>& b) const {
- if (!a || !b)
- return a.get() < b.get();
+bool MemoryDumpManager::MemoryDumpProviderInfo::operator<(
+ const MemoryDumpProviderInfo& other) const {
+ if (task_runner == other.task_runner)
+ return dump_provider < other.dump_provider;
// Ensure that unbound providers (task_runner == nullptr) always run last.
- // Rationale: some unbound dump providers are known to be slow, keep them last
- // to avoid skewing timings of the other dump providers.
- return std::tie(a->task_runner, a->dump_provider) >
- std::tie(b->task_runner, b->dump_provider);
+ return !(task_runner < other.task_runner);
}
MemoryDumpManager::ProcessMemoryDumpAsyncState::ProcessMemoryDumpAsyncState(
MemoryDumpRequestArgs req_args,
- const MemoryDumpProviderInfo::OrderedSet& dump_providers,
+ MemoryDumpProviderInfoSet::iterator next_dump_provider,
const scoped_refptr<MemoryDumpSessionState>& session_state,
MemoryDumpCallback callback,
const scoped_refptr<SingleThreadTaskRunner>& dump_thread_task_runner)
: req_args(req_args),
+ next_dump_provider(next_dump_provider),
session_state(session_state),
callback(callback),
callback_task_runner(MessageLoop::current()->task_runner()),
- dump_thread_task_runner(dump_thread_task_runner) {
- pending_dump_providers.reserve(dump_providers.size());
- pending_dump_providers.assign(dump_providers.rbegin(), dump_providers.rend());
-}
+ dump_thread_task_runner(dump_thread_task_runner) {}
MemoryDumpManager::ProcessMemoryDumpAsyncState::~ProcessMemoryDumpAsyncState() {
}
« no previous file with comments | « base/trace_event/memory_dump_manager.h ('k') | base/trace_event/memory_dump_manager_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698