Index: services/resource_coordinator/memory/coordinator/coordinator_impl.cc |
diff --git a/services/resource_coordinator/memory/coordinator/coordinator_impl.cc b/services/resource_coordinator/memory/coordinator/coordinator_impl.cc |
index d22c20b1b9eebe9ae40635664337b662bf795d79..923d6c1849b9229c96a563e48e258546a7f301c9 100644 |
--- a/services/resource_coordinator/memory/coordinator/coordinator_impl.cc |
+++ b/services/resource_coordinator/memory/coordinator/coordinator_impl.cc |
@@ -11,15 +11,13 @@ |
#include "base/location.h" |
#include "base/logging.h" |
#include "base/memory/ref_counted.h" |
-#include "base/single_thread_task_runner.h" |
-#include "base/threading/platform_thread.h" |
+#include "base/threading/thread_task_runner_handle.h" |
#include "base/trace_event/memory_dump_manager.h" |
#include "base/trace_event/memory_dump_request_args.h" |
#include "services/resource_coordinator/public/cpp/memory/process_local_dump_manager_impl.h" |
#include "services/resource_coordinator/public/interfaces/memory/constants.mojom.h" |
#include "services/resource_coordinator/public/interfaces/memory/memory_instrumentation.mojom.h" |
#include "services/service_manager/public/cpp/identity.h" |
-#include "services/service_manager/public/interfaces/service_manager.mojom.h" |
#if defined(OS_MACOSX) && !defined(OS_IOS) |
#include "base/mac/mac_util.h" |
@@ -29,6 +27,10 @@ namespace { |
memory_instrumentation::CoordinatorImpl* g_coordinator_impl; |
+// See design docs linked in the bugs for the rationale of the computation: |
+// - Linux/Android: https://crbug.com/707019 . |
+// - Mac OS: https://crbug.com/707021 . |
+// - Win: https://crbug.com/707022 . |
uint32_t CalculatePrivateFootprintKb( |
base::trace_event::MemoryDumpCallbackResult::OSMemDump& os_dump) { |
#if defined(OS_LINUX) || defined(OS_ANDROID) |
@@ -75,18 +77,20 @@ CoordinatorImpl::CoordinatorImpl(bool initialize_memory_dump_manager, |
base::trace_event::MemoryDumpManager::GetInstance()->set_tracing_process_id( |
mojom::kServiceTracingProcessId); |
} |
- process_map_.reset(new ProcessMap(connector)); |
+ process_map_ = base::MakeUnique<ProcessMap>(connector); |
+ DCHECK(!g_coordinator_impl); |
g_coordinator_impl = this; |
} |
-service_manager::Identity CoordinatorImpl::GetDispatchContext() const { |
- return bindings_.dispatch_context(); |
-} |
- |
CoordinatorImpl::~CoordinatorImpl() { |
g_coordinator_impl = nullptr; |
} |
+service_manager::Identity CoordinatorImpl::GetClientIdentityForCurrentRequest() |
+ const { |
+ return bindings_.dispatch_context(); |
+} |
+ |
void CoordinatorImpl::BindCoordinatorRequest( |
const service_manager::BindSourceInfo& source_info, |
mojom::CoordinatorRequest request) { |
@@ -94,13 +98,6 @@ void CoordinatorImpl::BindCoordinatorRequest( |
bindings_.AddBinding(this, std::move(request), source_info.identity); |
} |
-CoordinatorImpl::QueuedMemoryDumpRequest::QueuedMemoryDumpRequest( |
- const base::trace_event::MemoryDumpRequestArgs args, |
- const RequestGlobalMemoryDumpCallback callback) |
- : args(args), callback(callback) {} |
- |
-CoordinatorImpl::QueuedMemoryDumpRequest::~QueuedMemoryDumpRequest() {} |
- |
void CoordinatorImpl::RequestGlobalMemoryDump( |
const base::trace_event::MemoryDumpRequestArgs& args, |
const RequestGlobalMemoryDumpCallback& callback) { |
@@ -147,27 +144,27 @@ void CoordinatorImpl::RegisterProcessLocalDumpManager( |
base::Bind(&CoordinatorImpl::UnregisterProcessLocalDumpManager, |
base::Unretained(this), process_manager.get())); |
mojom::ProcessLocalDumpManager* key = process_manager.get(); |
- auto result = process_managers_.emplace( |
- key, std::make_pair(std::move(process_manager), GetDispatchContext())); |
- DCHECK(result.second); |
+ auto client_info = base::MakeUnique<ClientInfo>( |
+ GetClientIdentityForCurrentRequest(), std::move(process_manager)); |
+ auto iterator_and_inserted = clients_.emplace(key, std::move(client_info)); |
+ DCHECK(iterator_and_inserted.second); |
} |
void CoordinatorImpl::UnregisterProcessLocalDumpManager( |
mojom::ProcessLocalDumpManager* process_manager) { |
- size_t num_deleted = process_managers_.erase(process_manager); |
- DCHECK(num_deleted == 1); |
- |
// Check if we are waiting for an ack from this process-local manager. |
- if (pending_process_managers_.find(process_manager) != |
- pending_process_managers_.end()) { |
+ if (pending_clients_for_current_dump_.count(process_manager)) { |
DCHECK(!queued_memory_dump_requests_.empty()); |
OnProcessMemoryDumpResponse( |
process_manager, queued_memory_dump_requests_.front().args.dump_guid, |
false /* success */, nullptr /* process_memory_dump */); |
} |
+ size_t num_deleted = clients_.erase(process_manager); |
+ DCHECK(num_deleted == 1); |
} |
void CoordinatorImpl::PerformNextQueuedGlobalMemoryDump() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
DCHECK(!queued_memory_dump_requests_.empty()); |
const base::trace_event::MemoryDumpRequestArgs& args = |
queued_memory_dump_requests_.front().args; |
@@ -175,13 +172,14 @@ void CoordinatorImpl::PerformNextQueuedGlobalMemoryDump() { |
// No need to treat the service process different than other processes. The |
// service process will register itself as a ProcessLocalDumpManager and |
// will be treated like other process-local managers. |
- pending_process_managers_.clear(); |
+ pending_clients_for_current_dump_.clear(); |
failed_memory_dump_count_ = 0; |
- for (const auto& key_value : process_managers_) { |
- pending_process_managers_.insert(key_value.first); |
+ for (const auto& kv : clients_) { |
+ const mojom::ProcessLocalDumpManagerPtr& client = kv.second->client; |
+ pending_clients_for_current_dump_.insert(client.get()); |
auto callback = base::Bind(&CoordinatorImpl::OnProcessMemoryDumpResponse, |
- base::Unretained(this), key_value.first); |
- key_value.second.first->RequestProcessMemoryDump(args, callback); |
+ base::Unretained(this), client.get()); |
+ client->RequestProcessMemoryDump(args, callback); |
} |
// Run the callback in case there are no process-local managers. |
FinalizeGlobalMemoryDumpIfAllManagersReplied(); |
@@ -192,56 +190,61 @@ void CoordinatorImpl::OnProcessMemoryDumpResponse( |
uint64_t dump_guid, |
bool success, |
mojom::ProcessMemoryDumpPtr process_memory_dump) { |
- auto it = pending_process_managers_.find(process_manager); |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ auto it = pending_clients_for_current_dump_.find(process_manager); |
if (queued_memory_dump_requests_.empty() || |
queued_memory_dump_requests_.front().args.dump_guid != dump_guid || |
- it == pending_process_managers_.end()) { |
+ it == pending_clients_for_current_dump_.end()) { |
VLOG(1) << "Received unexpected memory dump response: " << dump_guid; |
return; |
} |
if (process_memory_dump) { |
base::ProcessId pid = base::kNullProcessId; |
- auto it = process_managers_.find(process_manager); |
- if (it != process_managers_.end()) { |
- pid = process_map_->GetProcessId(it->second.second); |
+ auto it = clients_.find(process_manager); |
+ if (it != clients_.end()) { |
+ pid = process_map_->GetProcessId(it->second->identity); |
} |
queued_memory_dump_requests_.front().process_memory_dumps.push_back( |
std::make_pair(pid, std::move(process_memory_dump))); |
} |
- pending_process_managers_.erase(it); |
+ pending_clients_for_current_dump_.erase(it); |
if (!success) { |
++failed_memory_dump_count_; |
VLOG(1) << base::trace_event::MemoryDumpManager::kLogPrefix |
- << " failed because of NACK from provider"; |
+ << " failed because of NACK from client"; |
} |
FinalizeGlobalMemoryDumpIfAllManagersReplied(); |
} |
void CoordinatorImpl::FinalizeGlobalMemoryDumpIfAllManagersReplied() { |
- if (pending_process_managers_.size() > 0) |
+ if (pending_clients_for_current_dump_.size() > 0) |
return; |
- if (queued_memory_dump_requests_.empty()) { |
- NOTREACHED(); |
- return; |
- } |
- |
+ DCHECK(!queued_memory_dump_requests_.empty()); |
+ QueuedMemoryDumpRequest& request = queued_memory_dump_requests_.front(); |
+ |
+ // Reconstruct a map of pid -> ProcessMemoryDump by reassembling the responses |
+ // received by the clients for this dump. In some cases the response coming |
+ // from one client can also provide the dump of OS counters for other |
+ // processes. A concrete case is Linux, where the browser process provides |
+ // details for the child processes to get around sandbox restrictions on |
+ // opening /proc pseudo files. |
std::map<base::ProcessId, mojom::ProcessMemoryDumpPtr> finalized_pmds; |
- for (auto& result : |
- queued_memory_dump_requests_.front().process_memory_dumps) { |
+ for (auto& result : request.process_memory_dumps) { |
mojom::ProcessMemoryDumpPtr& pmd = finalized_pmds[result.first]; |
if (!pmd) |
pmd = mojom::ProcessMemoryDump::New(); |
- pmd->chrome_dump = std::move(result.second->chrome_dump); |
+ pmd->chrome_dump = result.second->chrome_dump; |
// TODO(hjd): We should have a better way to tell if os_dump is filled. |
if (result.second->os_dump.resident_set_kb > 0) { |
- pmd->os_dump = std::move(result.second->os_dump); |
+ DCHECK_EQ(0u, pmd->os_dump.resident_set_kb); |
+ pmd->os_dump = result.second->os_dump; |
} |
for (auto& pair : result.second->extra_processes_dump) { |
@@ -249,7 +252,8 @@ void CoordinatorImpl::FinalizeGlobalMemoryDumpIfAllManagersReplied() { |
mojom::ProcessMemoryDumpPtr& pmd = finalized_pmds[pid]; |
if (!pmd) |
pmd = mojom::ProcessMemoryDump::New(); |
- pmd->os_dump = std::move(result.second->extra_processes_dump[pid]); |
+ DCHECK_EQ(0u, pmd->os_dump.resident_set_kb); |
+ pmd->os_dump = result.second->extra_processes_dump[pid]; |
} |
pmd->process_type = result.second->process_type; |
@@ -262,18 +266,16 @@ void CoordinatorImpl::FinalizeGlobalMemoryDumpIfAllManagersReplied() { |
// died. We should skip these. |
// TODO(hjd): We should have a better way to tell if a chrome_dump is |
// filled. |
- if (!pair.second->chrome_dump.malloc_total_kb) |
+ mojom::ProcessMemoryDumpPtr& pmd = pair.second; |
+ if (!pmd || !pmd->chrome_dump.malloc_total_kb) |
continue; |
- base::ProcessId pid = pair.first; |
- mojom::ProcessMemoryDumpPtr& pmd = finalized_pmds[pid]; |
pmd->private_footprint = CalculatePrivateFootprintKb(pmd->os_dump); |
global_dump->process_dumps.push_back(std::move(pmd)); |
} |
- const auto& callback = queued_memory_dump_requests_.front().callback; |
+ const auto& callback = request.callback; |
const bool global_success = failed_memory_dump_count_ == 0; |
- callback.Run(queued_memory_dump_requests_.front().args.dump_guid, |
- global_success, std::move(global_dump)); |
+ callback.Run(request.args.dump_guid, global_success, std::move(global_dump)); |
queued_memory_dump_requests_.pop_front(); |
// Schedule the next queued dump (if applicable). |
@@ -285,4 +287,17 @@ void CoordinatorImpl::FinalizeGlobalMemoryDumpIfAllManagersReplied() { |
} |
} |
+CoordinatorImpl::QueuedMemoryDumpRequest::QueuedMemoryDumpRequest( |
+ const base::trace_event::MemoryDumpRequestArgs& args, |
+ const RequestGlobalMemoryDumpCallback callback) |
+ : args(args), callback(callback) {} |
+ |
+CoordinatorImpl::QueuedMemoryDumpRequest::~QueuedMemoryDumpRequest() {} |
+ |
+CoordinatorImpl::ClientInfo::ClientInfo( |
+ const service_manager::Identity& identity, |
+ mojom::ProcessLocalDumpManagerPtr client) |
+ : identity(identity), client(std::move(client)) {} |
+CoordinatorImpl::ClientInfo::~ClientInfo() {} |
+ |
} // namespace memory_instrumentation |