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