| Index: content/browser/tracing/tracing_controller_impl.cc
|
| diff --git a/content/browser/tracing/tracing_controller_impl.cc b/content/browser/tracing/tracing_controller_impl.cc
|
| index 54d1455aa3868711a0ca12e734f51cc992496b17..5fc480346a29332414bbd150039dfcabea0385ee 100644
|
| --- a/content/browser/tracing/tracing_controller_impl.cc
|
| +++ b/content/browser/tracing/tracing_controller_impl.cc
|
| @@ -193,8 +193,13 @@
|
| pending_trace_log_status_ack_count_(0),
|
| maximum_trace_buffer_usage_(0),
|
| approximate_event_count_(0),
|
| + pending_memory_dump_ack_count_(0),
|
| + failed_memory_dump_count_(0),
|
| pending_clock_sync_ack_count_(0),
|
| is_tracing_(false) {
|
| + base::trace_event::MemoryDumpManager::GetInstance()->Initialize(
|
| + this /* delegate */, true /* is_coordinator */);
|
| +
|
| // Deliberately leaked, like this class.
|
| base::FileTracing::SetProvider(new FileTracingProviderImpl);
|
| }
|
| @@ -531,6 +536,20 @@
|
| base::trace_event::TraceLogStatus()));
|
| }
|
| }
|
| + if (pending_memory_dump_ack_count_ > 0) {
|
| + DCHECK(!queued_memory_dump_requests_.empty());
|
| + TraceMessageFilterSet::const_iterator it =
|
| + pending_memory_dump_filters_.find(trace_message_filter);
|
| + if (it != pending_memory_dump_filters_.end()) {
|
| + BrowserThread::PostTask(
|
| + BrowserThread::UI, FROM_HERE,
|
| + base::Bind(&TracingControllerImpl::OnProcessMemoryDumpResponse,
|
| + base::Unretained(this),
|
| + base::RetainedRef(trace_message_filter),
|
| + queued_memory_dump_requests_.front().args.dump_guid,
|
| + false /* success */));
|
| + }
|
| + }
|
| trace_message_filters_.erase(trace_message_filter);
|
| }
|
|
|
| @@ -877,6 +896,87 @@
|
| sink->AddMetadata(std::move(filtered_metadata));
|
| }
|
|
|
| +void TracingControllerImpl::RequestGlobalMemoryDump(
|
| + const base::trace_event::MemoryDumpRequestArgs& args,
|
| + const base::trace_event::MemoryDumpCallback& callback) {
|
| + if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
|
| + BrowserThread::PostTask(
|
| + BrowserThread::UI, FROM_HERE,
|
| + base::Bind(&TracingControllerImpl::RequestGlobalMemoryDump,
|
| + base::Unretained(this), args, callback));
|
| + return;
|
| + }
|
| +
|
| + bool another_dump_already_in_progress = !queued_memory_dump_requests_.empty();
|
| +
|
| + // If this is a periodic memory dump request and there already is another
|
| + // request in the queue with the same level of detail, there's no point in
|
| + // enqueuing this request.
|
| + if (another_dump_already_in_progress &&
|
| + args.dump_type == base::trace_event::MemoryDumpType::PERIODIC_INTERVAL) {
|
| + for (const auto& request : queued_memory_dump_requests_) {
|
| + if (request.args.level_of_detail == args.level_of_detail) {
|
| + VLOG(1) << base::trace_event::MemoryDumpManager::kLogPrefix << " ("
|
| + << base::trace_event::MemoryDumpTypeToString(args.dump_type)
|
| + << ") skipped because another dump request with the same "
|
| + "level of detail ("
|
| + << base::trace_event::MemoryDumpLevelOfDetailToString(
|
| + args.level_of_detail)
|
| + << ") is already in the queue";
|
| + if (!callback.is_null())
|
| + callback.Run(args.dump_guid, false /* success */);
|
| + return;
|
| + }
|
| + }
|
| + }
|
| +
|
| + queued_memory_dump_requests_.emplace_back(args, callback);
|
| +
|
| + // If another dump is already in progress, this dump will automatically be
|
| + // scheduled when the other dump finishes.
|
| + if (another_dump_already_in_progress)
|
| + return;
|
| +
|
| + PerformNextQueuedGlobalMemoryDump();
|
| +}
|
| +
|
| +void TracingControllerImpl::PerformNextQueuedGlobalMemoryDump() {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| + DCHECK(!queued_memory_dump_requests_.empty());
|
| + const base::trace_event::MemoryDumpRequestArgs& args =
|
| + queued_memory_dump_requests_.front().args;
|
| +
|
| + // Count myself (local trace) in pending_memory_dump_ack_count_, acked by
|
| + // OnBrowserProcessMemoryDumpDone().
|
| + pending_memory_dump_ack_count_ = trace_message_filters_.size() + 1;
|
| + pending_memory_dump_filters_.clear();
|
| + failed_memory_dump_count_ = 0;
|
| +
|
| + MemoryDumpManagerDelegate::CreateProcessDump(
|
| + args, base::Bind(&TracingControllerImpl::OnBrowserProcessMemoryDumpDone,
|
| + base::Unretained(this)));
|
| +
|
| + // If there are no child processes we are just done.
|
| + if (pending_memory_dump_ack_count_ == 1)
|
| + return;
|
| +
|
| + pending_memory_dump_filters_ = trace_message_filters_;
|
| +
|
| + for (const scoped_refptr<TraceMessageFilter>& tmf : trace_message_filters_)
|
| + tmf->SendProcessMemoryDumpRequest(args);
|
| +}
|
| +
|
| +TracingControllerImpl::QueuedMemoryDumpRequest::QueuedMemoryDumpRequest(
|
| + const base::trace_event::MemoryDumpRequestArgs& args,
|
| + const base::trace_event::MemoryDumpCallback& callback)
|
| + : args(args), callback(callback) {}
|
| +
|
| +TracingControllerImpl::QueuedMemoryDumpRequest::~QueuedMemoryDumpRequest() {}
|
| +
|
| +uint64_t TracingControllerImpl::GetTracingProcessId() const {
|
| + return ChildProcessHost::kBrowserTracingProcessId;
|
| +}
|
| +
|
| void TracingControllerImpl::AddTraceMessageFilterObserver(
|
| TraceMessageFilterObserver* observer) {
|
| DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| @@ -895,4 +995,76 @@
|
| observer->OnTraceMessageFilterRemoved(filter.get());
|
| }
|
|
|
| +void TracingControllerImpl::OnProcessMemoryDumpResponse(
|
| + TraceMessageFilter* trace_message_filter,
|
| + uint64_t dump_guid,
|
| + bool success) {
|
| + if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
|
| + BrowserThread::PostTask(
|
| + BrowserThread::UI, FROM_HERE,
|
| + base::Bind(&TracingControllerImpl::OnProcessMemoryDumpResponse,
|
| + base::Unretained(this),
|
| + base::RetainedRef(trace_message_filter), dump_guid,
|
| + success));
|
| + return;
|
| + }
|
| +
|
| + TraceMessageFilterSet::iterator it =
|
| + pending_memory_dump_filters_.find(trace_message_filter);
|
| +
|
| + DCHECK(!queued_memory_dump_requests_.empty());
|
| + if (queued_memory_dump_requests_.front().args.dump_guid != dump_guid ||
|
| + it == pending_memory_dump_filters_.end()) {
|
| + DLOG(WARNING) << "Received unexpected memory dump response: " << dump_guid;
|
| + return;
|
| + }
|
| +
|
| + DCHECK_GT(pending_memory_dump_ack_count_, 0);
|
| + --pending_memory_dump_ack_count_;
|
| + pending_memory_dump_filters_.erase(it);
|
| + if (!success) {
|
| + ++failed_memory_dump_count_;
|
| + VLOG(1) << base::trace_event::MemoryDumpManager::kLogPrefix
|
| + << " failed because of NACK from child "
|
| + << trace_message_filter->peer_pid();
|
| + }
|
| + FinalizeGlobalMemoryDumpIfAllProcessesReplied();
|
| +}
|
| +
|
| +void TracingControllerImpl::OnBrowserProcessMemoryDumpDone(uint64_t dump_guid,
|
| + bool success) {
|
| + DCHECK_GT(pending_memory_dump_ack_count_, 0);
|
| + --pending_memory_dump_ack_count_;
|
| + if (!success) {
|
| + ++failed_memory_dump_count_;
|
| + VLOG(1) << base::trace_event::MemoryDumpManager::kLogPrefix
|
| + << " aborted on the current process";
|
| + }
|
| + FinalizeGlobalMemoryDumpIfAllProcessesReplied();
|
| +}
|
| +
|
| +void TracingControllerImpl::FinalizeGlobalMemoryDumpIfAllProcessesReplied() {
|
| + if (pending_memory_dump_ack_count_ > 0)
|
| + return;
|
| +
|
| + DCHECK(!queued_memory_dump_requests_.empty());
|
| + {
|
| + const auto& callback = queued_memory_dump_requests_.front().callback;
|
| + if (!callback.is_null()) {
|
| + const bool global_success = failed_memory_dump_count_ == 0;
|
| + callback.Run(queued_memory_dump_requests_.front().args.dump_guid,
|
| + global_success);
|
| + }
|
| + }
|
| + queued_memory_dump_requests_.pop_front();
|
| +
|
| + // Schedule the next queued dump (if applicable).
|
| + if (!queued_memory_dump_requests_.empty()) {
|
| + BrowserThread::PostTask(
|
| + BrowserThread::UI, FROM_HERE,
|
| + base::Bind(&TracingControllerImpl::PerformNextQueuedGlobalMemoryDump,
|
| + base::Unretained(this)));
|
| + }
|
| +}
|
| +
|
| } // namespace content
|
|
|