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 |