| OLD | NEW |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "services/resource_coordinator/memory/coordinator/coordinator_impl.h" | 5 #include "services/resource_coordinator/memory/coordinator/coordinator_impl.h" |
| 6 | 6 |
| 7 #include <utility> |
| 8 |
| 7 #include "base/bind.h" | 9 #include "base/bind.h" |
| 8 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
| 9 #include "base/location.h" | 11 #include "base/location.h" |
| 10 #include "base/logging.h" | 12 #include "base/logging.h" |
| 11 #include "base/memory/ref_counted.h" | 13 #include "base/memory/ref_counted.h" |
| 12 #include "base/single_thread_task_runner.h" | 14 #include "base/single_thread_task_runner.h" |
| 13 #include "base/threading/platform_thread.h" | 15 #include "base/threading/platform_thread.h" |
| 14 #include "base/trace_event/memory_dump_manager.h" | 16 #include "base/trace_event/memory_dump_manager.h" |
| 15 #include "base/trace_event/memory_dump_request_args.h" | 17 #include "base/trace_event/memory_dump_request_args.h" |
| 16 #include "services/resource_coordinator/public/cpp/memory/process_local_dump_man
ager_impl.h" | 18 #include "services/resource_coordinator/public/cpp/memory/process_local_dump_man
ager_impl.h" |
| 17 #include "services/resource_coordinator/public/interfaces/memory/constants.mojom
.h" | 19 #include "services/resource_coordinator/public/interfaces/memory/constants.mojom
.h" |
| 18 #include "services/resource_coordinator/public/interfaces/memory/memory_instrume
ntation.mojom.h" | 20 #include "services/resource_coordinator/public/interfaces/memory/memory_instrume
ntation.mojom.h" |
| 21 #include "services/service_manager/public/cpp/identity.h" |
| 22 #include "services/service_manager/public/interfaces/service_manager.mojom.h" |
| 19 | 23 |
| 20 #if defined(OS_MACOSX) && !defined(OS_IOS) | 24 #if defined(OS_MACOSX) && !defined(OS_IOS) |
| 21 #include "base/mac/mac_util.h" | 25 #include "base/mac/mac_util.h" |
| 22 #endif | 26 #endif |
| 23 | 27 |
| 24 namespace { | 28 namespace { |
| 25 | 29 |
| 26 memory_instrumentation::CoordinatorImpl* g_coordinator_impl; | 30 memory_instrumentation::CoordinatorImpl* g_coordinator_impl; |
| 27 | 31 |
| 28 uint32_t CalculatePrivateFootprintKb( | 32 uint32_t CalculatePrivateFootprintKb( |
| (...skipping 22 matching lines...) Expand all Loading... |
| 51 | 55 |
| 52 } // namespace | 56 } // namespace |
| 53 | 57 |
| 54 namespace memory_instrumentation { | 58 namespace memory_instrumentation { |
| 55 | 59 |
| 56 // static | 60 // static |
| 57 CoordinatorImpl* CoordinatorImpl::GetInstance() { | 61 CoordinatorImpl* CoordinatorImpl::GetInstance() { |
| 58 return g_coordinator_impl; | 62 return g_coordinator_impl; |
| 59 } | 63 } |
| 60 | 64 |
| 61 CoordinatorImpl::CoordinatorImpl(bool initialize_memory_dump_manager) | 65 CoordinatorImpl::CoordinatorImpl(bool initialize_memory_dump_manager, |
| 66 service_manager::Connector* connector) |
| 62 : failed_memory_dump_count_(0), | 67 : failed_memory_dump_count_(0), |
| 63 initialize_memory_dump_manager_(initialize_memory_dump_manager) { | 68 initialize_memory_dump_manager_(initialize_memory_dump_manager) { |
| 64 if (initialize_memory_dump_manager) { | 69 if (initialize_memory_dump_manager) { |
| 65 // TODO(primiano): the current state where the coordinator also creates a | 70 // TODO(primiano): the current state where the coordinator also creates a |
| 66 // client (ProcessLocalDumpManagerImpl) is contra-intuitive. BrowserMainLoop | 71 // client (ProcessLocalDumpManagerImpl) is contra-intuitive. BrowserMainLoop |
| 67 // should be doing this. | 72 // should be doing this. |
| 68 ProcessLocalDumpManagerImpl::CreateInstance( | 73 ProcessLocalDumpManagerImpl::CreateInstance( |
| 69 ProcessLocalDumpManagerImpl::Config(this, mojom::ProcessType::BROWSER)); | 74 ProcessLocalDumpManagerImpl::Config(this, mojom::ProcessType::BROWSER)); |
| 70 base::trace_event::MemoryDumpManager::GetInstance()->set_tracing_process_id( | 75 base::trace_event::MemoryDumpManager::GetInstance()->set_tracing_process_id( |
| 71 mojom::kServiceTracingProcessId); | 76 mojom::kServiceTracingProcessId); |
| 72 } | 77 } |
| 78 process_map_.reset(new ProcessMap(connector)); |
| 73 g_coordinator_impl = this; | 79 g_coordinator_impl = this; |
| 74 } | 80 } |
| 75 | 81 |
| 82 service_manager::Identity CoordinatorImpl::GetDispatchContext() const { |
| 83 return bindings_.dispatch_context(); |
| 84 } |
| 85 |
| 76 CoordinatorImpl::~CoordinatorImpl() { | 86 CoordinatorImpl::~CoordinatorImpl() { |
| 77 g_coordinator_impl = nullptr; | 87 g_coordinator_impl = nullptr; |
| 78 } | 88 } |
| 79 | 89 |
| 80 void CoordinatorImpl::BindCoordinatorRequest( | 90 void CoordinatorImpl::BindCoordinatorRequest( |
| 81 const service_manager::BindSourceInfo& source_info, | 91 const service_manager::BindSourceInfo& source_info, |
| 82 mojom::CoordinatorRequest request) { | 92 mojom::CoordinatorRequest request) { |
| 83 DCHECK(thread_checker_.CalledOnValidThread()); | 93 DCHECK(thread_checker_.CalledOnValidThread()); |
| 84 bindings_.AddBinding(this, std::move(request)); | 94 bindings_.AddBinding(this, std::move(request), source_info.identity); |
| 85 } | 95 } |
| 86 | 96 |
| 87 CoordinatorImpl::QueuedMemoryDumpRequest::QueuedMemoryDumpRequest( | 97 CoordinatorImpl::QueuedMemoryDumpRequest::QueuedMemoryDumpRequest( |
| 88 const base::trace_event::MemoryDumpRequestArgs args, | 98 const base::trace_event::MemoryDumpRequestArgs args, |
| 89 const RequestGlobalMemoryDumpCallback callback) | 99 const RequestGlobalMemoryDumpCallback callback) |
| 90 : args(args), callback(callback) {} | 100 : args(args), callback(callback) {} |
| 91 | 101 |
| 92 CoordinatorImpl::QueuedMemoryDumpRequest::~QueuedMemoryDumpRequest() {} | 102 CoordinatorImpl::QueuedMemoryDumpRequest::~QueuedMemoryDumpRequest() {} |
| 93 | 103 |
| 94 void CoordinatorImpl::RequestGlobalMemoryDump( | 104 void CoordinatorImpl::RequestGlobalMemoryDump( |
| 95 const base::trace_event::MemoryDumpRequestArgs& args, | 105 const base::trace_event::MemoryDumpRequestArgs& args, |
| 96 const RequestGlobalMemoryDumpCallback& callback) { | 106 const RequestGlobalMemoryDumpCallback& callback) { |
| 97 DCHECK(thread_checker_.CalledOnValidThread()); | 107 DCHECK(thread_checker_.CalledOnValidThread()); |
| 98 bool another_dump_already_in_progress = !queued_memory_dump_requests_.empty(); | 108 bool another_dump_already_in_progress = !queued_memory_dump_requests_.empty(); |
| 99 | 109 |
| 100 // If this is a periodic or peak memory dump request and there already is | 110 // If this is a periodic or peak memory dump request and there already is |
| 101 // another request in the queue with the same level of detail, there's no | 111 // another request in the queue with the same level of detail, there's no |
| 102 // point in enqueuing this request. | 112 // point in enqueuing this request. |
| 103 if (another_dump_already_in_progress && | 113 if (another_dump_already_in_progress && |
| 104 args.dump_type != | 114 args.dump_type != |
| 105 base::trace_event::MemoryDumpType::EXPLICITLY_TRIGGERED) { | 115 base::trace_event::MemoryDumpType::EXPLICITLY_TRIGGERED && |
| 116 args.dump_type != base::trace_event::MemoryDumpType::SUMMARY_ONLY) { |
| 106 for (const auto& request : queued_memory_dump_requests_) { | 117 for (const auto& request : queued_memory_dump_requests_) { |
| 107 if (request.args.level_of_detail == args.level_of_detail) { | 118 if (request.args.level_of_detail == args.level_of_detail) { |
| 108 VLOG(1) << base::trace_event::MemoryDumpManager::kLogPrefix << " (" | 119 VLOG(1) << base::trace_event::MemoryDumpManager::kLogPrefix << " (" |
| 109 << base::trace_event::MemoryDumpTypeToString(args.dump_type) | 120 << base::trace_event::MemoryDumpTypeToString(args.dump_type) |
| 110 << ") skipped because another dump request with the same " | 121 << ") skipped because another dump request with the same " |
| 111 "level of detail (" | 122 "level of detail (" |
| 112 << base::trace_event::MemoryDumpLevelOfDetailToString( | 123 << base::trace_event::MemoryDumpLevelOfDetailToString( |
| 113 args.level_of_detail) | 124 args.level_of_detail) |
| 114 << ") is already in the queue"; | 125 << ") is already in the queue"; |
| 115 callback.Run(args.dump_guid, false /* success */, | 126 callback.Run(args.dump_guid, false /* success */, |
| (...skipping 12 matching lines...) Expand all Loading... |
| 128 | 139 |
| 129 PerformNextQueuedGlobalMemoryDump(); | 140 PerformNextQueuedGlobalMemoryDump(); |
| 130 } | 141 } |
| 131 | 142 |
| 132 void CoordinatorImpl::RegisterProcessLocalDumpManager( | 143 void CoordinatorImpl::RegisterProcessLocalDumpManager( |
| 133 mojom::ProcessLocalDumpManagerPtr process_manager) { | 144 mojom::ProcessLocalDumpManagerPtr process_manager) { |
| 134 DCHECK(thread_checker_.CalledOnValidThread()); | 145 DCHECK(thread_checker_.CalledOnValidThread()); |
| 135 process_manager.set_connection_error_handler( | 146 process_manager.set_connection_error_handler( |
| 136 base::Bind(&CoordinatorImpl::UnregisterProcessLocalDumpManager, | 147 base::Bind(&CoordinatorImpl::UnregisterProcessLocalDumpManager, |
| 137 base::Unretained(this), process_manager.get())); | 148 base::Unretained(this), process_manager.get())); |
| 138 auto result = process_managers_.insert( | 149 mojom::ProcessLocalDumpManager* key = process_manager.get(); |
| 139 std::make_pair<mojom::ProcessLocalDumpManager*, | 150 auto result = process_managers_.emplace( |
| 140 mojom::ProcessLocalDumpManagerPtr>( | 151 key, std::make_pair(std::move(process_manager), GetDispatchContext())); |
| 141 process_manager.get(), std::move(process_manager))); | |
| 142 DCHECK(result.second); | 152 DCHECK(result.second); |
| 143 } | 153 } |
| 144 | 154 |
| 145 void CoordinatorImpl::UnregisterProcessLocalDumpManager( | 155 void CoordinatorImpl::UnregisterProcessLocalDumpManager( |
| 146 mojom::ProcessLocalDumpManager* process_manager) { | 156 mojom::ProcessLocalDumpManager* process_manager) { |
| 147 size_t num_deleted = process_managers_.erase(process_manager); | 157 size_t num_deleted = process_managers_.erase(process_manager); |
| 148 DCHECK(num_deleted == 1); | 158 DCHECK(num_deleted == 1); |
| 149 | 159 |
| 150 // Check if we are waiting for an ack from this process-local manager. | 160 // Check if we are waiting for an ack from this process-local manager. |
| 151 if (pending_process_managers_.find(process_manager) != | 161 if (pending_process_managers_.find(process_manager) != |
| 152 pending_process_managers_.end()) { | 162 pending_process_managers_.end()) { |
| 153 DCHECK(!queued_memory_dump_requests_.empty()); | 163 DCHECK(!queued_memory_dump_requests_.empty()); |
| 154 OnProcessMemoryDumpResponse( | 164 OnProcessMemoryDumpResponse( |
| 155 process_manager, queued_memory_dump_requests_.front().args.dump_guid, | 165 process_manager, queued_memory_dump_requests_.front().args.dump_guid, |
| 156 false /* success */, nullptr /* process_memory_dump */); | 166 false /* success */, nullptr /* process_memory_dump */); |
| 157 } | 167 } |
| 158 } | 168 } |
| 159 | 169 |
| 160 void CoordinatorImpl::PerformNextQueuedGlobalMemoryDump() { | 170 void CoordinatorImpl::PerformNextQueuedGlobalMemoryDump() { |
| 161 DCHECK(!queued_memory_dump_requests_.empty()); | 171 DCHECK(!queued_memory_dump_requests_.empty()); |
| 162 const base::trace_event::MemoryDumpRequestArgs& args = | 172 const base::trace_event::MemoryDumpRequestArgs& args = |
| 163 queued_memory_dump_requests_.front().args; | 173 queued_memory_dump_requests_.front().args; |
| 164 | 174 |
| 165 // No need to treat the service process different than other processes. The | 175 // No need to treat the service process different than other processes. The |
| 166 // service process will register itself as a ProcessLocalDumpManager and will | 176 // service process will register itself as a ProcessLocalDumpManager and |
| 167 // be treated like other process-local managers. | 177 // will be treated like other process-local managers. |
| 168 pending_process_managers_.clear(); | 178 pending_process_managers_.clear(); |
| 169 failed_memory_dump_count_ = 0; | 179 failed_memory_dump_count_ = 0; |
| 170 for (const auto& key_value : process_managers_) { | 180 for (const auto& key_value : process_managers_) { |
| 171 pending_process_managers_.insert(key_value.first); | 181 pending_process_managers_.insert(key_value.first); |
| 172 auto callback = base::Bind(&CoordinatorImpl::OnProcessMemoryDumpResponse, | 182 auto callback = base::Bind(&CoordinatorImpl::OnProcessMemoryDumpResponse, |
| 173 base::Unretained(this), key_value.first); | 183 base::Unretained(this), key_value.first); |
| 174 key_value.second->RequestProcessMemoryDump(args, callback); | 184 key_value.second.first->RequestProcessMemoryDump(args, callback); |
| 175 } | 185 } |
| 176 // Run the callback in case there are no process-local managers. | 186 // Run the callback in case there are no process-local managers. |
| 177 FinalizeGlobalMemoryDumpIfAllManagersReplied(); | 187 FinalizeGlobalMemoryDumpIfAllManagersReplied(); |
| 178 } | 188 } |
| 179 | 189 |
| 180 void CoordinatorImpl::OnProcessMemoryDumpResponse( | 190 void CoordinatorImpl::OnProcessMemoryDumpResponse( |
| 181 mojom::ProcessLocalDumpManager* process_manager, | 191 mojom::ProcessLocalDumpManager* process_manager, |
| 182 uint64_t dump_guid, | 192 uint64_t dump_guid, |
| 183 bool success, | 193 bool success, |
| 184 mojom::ProcessMemoryDumpPtr process_memory_dump) { | 194 mojom::ProcessMemoryDumpPtr process_memory_dump) { |
| 185 auto it = pending_process_managers_.find(process_manager); | 195 auto it = pending_process_managers_.find(process_manager); |
| 186 | 196 |
| 187 if (queued_memory_dump_requests_.empty() || | 197 if (queued_memory_dump_requests_.empty() || |
| 188 queued_memory_dump_requests_.front().args.dump_guid != dump_guid || | 198 queued_memory_dump_requests_.front().args.dump_guid != dump_guid || |
| 189 it == pending_process_managers_.end()) { | 199 it == pending_process_managers_.end()) { |
| 190 VLOG(1) << "Received unexpected memory dump response: " << dump_guid; | 200 VLOG(1) << "Received unexpected memory dump response: " << dump_guid; |
| 191 return; | 201 return; |
| 192 } | 202 } |
| 193 if (process_memory_dump) { | 203 if (process_memory_dump) { |
| 204 base::ProcessId pid = base::kNullProcessId; |
| 205 auto it = process_managers_.find(process_manager); |
| 206 if (it != process_managers_.end()) { |
| 207 pid = process_map_->GetProcessId(it->second.second); |
| 208 } |
| 209 |
| 194 queued_memory_dump_requests_.front().process_memory_dumps.push_back( | 210 queued_memory_dump_requests_.front().process_memory_dumps.push_back( |
| 195 std::move(process_memory_dump)); | 211 std::make_pair(pid, std::move(process_memory_dump))); |
| 196 } | 212 } |
| 197 | 213 |
| 198 pending_process_managers_.erase(it); | 214 pending_process_managers_.erase(it); |
| 199 | 215 |
| 200 if (!success) { | 216 if (!success) { |
| 201 ++failed_memory_dump_count_; | 217 ++failed_memory_dump_count_; |
| 202 VLOG(1) << base::trace_event::MemoryDumpManager::kLogPrefix | 218 VLOG(1) << base::trace_event::MemoryDumpManager::kLogPrefix |
| 203 << " failed because of NACK from provider"; | 219 << " failed because of NACK from provider"; |
| 204 } | 220 } |
| 205 | 221 |
| 206 FinalizeGlobalMemoryDumpIfAllManagersReplied(); | 222 FinalizeGlobalMemoryDumpIfAllManagersReplied(); |
| 207 } | 223 } |
| 208 | 224 |
| 209 void CoordinatorImpl::FinalizeGlobalMemoryDumpIfAllManagersReplied() { | 225 void CoordinatorImpl::FinalizeGlobalMemoryDumpIfAllManagersReplied() { |
| 210 if (pending_process_managers_.size() > 0) | 226 if (pending_process_managers_.size() > 0) |
| 211 return; | 227 return; |
| 212 | 228 |
| 213 if (queued_memory_dump_requests_.empty()) { | 229 if (queued_memory_dump_requests_.empty()) { |
| 214 NOTREACHED(); | 230 NOTREACHED(); |
| 215 return; | 231 return; |
| 216 } | 232 } |
| 217 | 233 |
| 218 std::map<base::ProcessId, mojom::ProcessMemoryDumpPtr> finalized_pmds; | 234 std::map<base::ProcessId, mojom::ProcessMemoryDumpPtr> finalized_pmds; |
| 219 for (auto& result : | 235 for (auto& result : |
| 220 queued_memory_dump_requests_.front().process_memory_dumps) { | 236 queued_memory_dump_requests_.front().process_memory_dumps) { |
| 221 // TODO(fmeawad): Write into correct map entry instead of always | 237 mojom::ProcessMemoryDumpPtr& pmd = finalized_pmds[result.first]; |
| 222 // to pid = 0. | |
| 223 mojom::ProcessMemoryDumpPtr& pmd = finalized_pmds[0]; | |
| 224 if (!pmd) | 238 if (!pmd) |
| 225 pmd = mojom::ProcessMemoryDump::New(); | 239 pmd = mojom::ProcessMemoryDump::New(); |
| 226 pmd->chrome_dump = std::move(result->chrome_dump); | 240 pmd->chrome_dump = std::move(result.second->chrome_dump); |
| 227 | 241 |
| 228 // TODO(hjd): We should have a better way to tell if os_dump is filled. | 242 // TODO(hjd): We should have a better way to tell if os_dump is filled. |
| 229 if (result->os_dump.resident_set_kb > 0) { | 243 if (result.second->os_dump.resident_set_kb > 0) { |
| 230 pmd->os_dump = std::move(result->os_dump); | 244 pmd->os_dump = std::move(result.second->os_dump); |
| 231 } | 245 } |
| 232 | 246 |
| 233 for (auto& pair : result->extra_processes_dump) { | 247 for (auto& pair : result.second->extra_processes_dump) { |
| 234 base::ProcessId pid = pair.first; | 248 base::ProcessId pid = pair.first; |
| 235 mojom::ProcessMemoryDumpPtr& pmd = finalized_pmds[pid]; | 249 mojom::ProcessMemoryDumpPtr& pmd = finalized_pmds[pid]; |
| 236 if (!pmd) | 250 if (!pmd) |
| 237 pmd = mojom::ProcessMemoryDump::New(); | 251 pmd = mojom::ProcessMemoryDump::New(); |
| 238 pmd->os_dump = std::move(result->extra_processes_dump[pid]); | 252 pmd->os_dump = std::move(result.second->extra_processes_dump[pid]); |
| 239 } | 253 } |
| 254 |
| 255 pmd->process_type = result.second->process_type; |
| 240 } | 256 } |
| 241 | 257 |
| 242 mojom::GlobalMemoryDumpPtr global_dump(mojom::GlobalMemoryDump::New()); | 258 mojom::GlobalMemoryDumpPtr global_dump(mojom::GlobalMemoryDump::New()); |
| 243 for (auto& pair : finalized_pmds) { | 259 for (auto& pair : finalized_pmds) { |
| 244 // It's possible that the renderer has died but we still have an os_dump, | 260 // It's possible that the renderer has died but we still have an os_dump, |
| 245 // because those were comptued from the browser proces before the renderer | 261 // because those were computed from the browser proces before the renderer |
| 246 // died. We should skip these. | 262 // died. We should skip these. |
| 247 // TODO(hjd): We should have a better way to tell if a chrome_dump is | 263 // TODO(hjd): We should have a better way to tell if a chrome_dump is |
| 248 // filled. | 264 // filled. |
| 249 if (!pair.second->chrome_dump.malloc_total_kb) | 265 if (!pair.second->chrome_dump.malloc_total_kb) |
| 250 continue; | 266 continue; |
| 251 base::ProcessId pid = pair.first; | 267 base::ProcessId pid = pair.first; |
| 252 mojom::ProcessMemoryDumpPtr pmd = std::move(finalized_pmds[pid]); | 268 mojom::ProcessMemoryDumpPtr& pmd = finalized_pmds[pid]; |
| 253 pmd->private_footprint = CalculatePrivateFootprintKb(pmd->os_dump); | 269 pmd->private_footprint = CalculatePrivateFootprintKb(pmd->os_dump); |
| 254 global_dump->process_dumps.push_back(std::move(pmd)); | 270 global_dump->process_dumps.push_back(std::move(pmd)); |
| 255 } | 271 } |
| 256 | 272 |
| 257 const auto& callback = queued_memory_dump_requests_.front().callback; | 273 const auto& callback = queued_memory_dump_requests_.front().callback; |
| 258 const bool global_success = failed_memory_dump_count_ == 0; | 274 const bool global_success = failed_memory_dump_count_ == 0; |
| 259 callback.Run(queued_memory_dump_requests_.front().args.dump_guid, | 275 callback.Run(queued_memory_dump_requests_.front().args.dump_guid, |
| 260 global_success, std::move(global_dump)); | 276 global_success, std::move(global_dump)); |
| 261 queued_memory_dump_requests_.pop_front(); | 277 queued_memory_dump_requests_.pop_front(); |
| 262 | 278 |
| 263 // Schedule the next queued dump (if applicable). | 279 // Schedule the next queued dump (if applicable). |
| 264 if (!queued_memory_dump_requests_.empty()) { | 280 if (!queued_memory_dump_requests_.empty()) { |
| 265 base::ThreadTaskRunnerHandle::Get()->PostTask( | 281 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 266 FROM_HERE, | 282 FROM_HERE, |
| 267 base::Bind(&CoordinatorImpl::PerformNextQueuedGlobalMemoryDump, | 283 base::Bind(&CoordinatorImpl::PerformNextQueuedGlobalMemoryDump, |
| 268 base::Unretained(this))); | 284 base::Unretained(this))); |
| 269 } | 285 } |
| 270 } | 286 } |
| 271 | 287 |
| 272 } // namespace memory_instrumentation | 288 } // namespace memory_instrumentation |
| OLD | NEW |